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

Commit

Permalink
Merge pull request #190 from FormidableLabs/feature/victory-brush
Browse files Browse the repository at this point in the history
Feature/victory brush
  • Loading branch information
boygirl authored Jan 30, 2017
2 parents 53667d3 + fa3255b commit 5ef16eb
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 26 deletions.
44 changes: 29 additions & 15 deletions src/victory-container/victory-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@ export default class VictoryContainer extends React.Component {
title: PropTypes.string,
desc: PropTypes.string,
portalComponent: PropTypes.element,
responsive: PropTypes.bool
responsive: PropTypes.bool,
standalone: PropTypes.bool
}

static defaultProps = {
title: "Victory Chart",
desc: "",
portalComponent: <Portal/>,
responsive: true
responsive: true,
standalone: true
}

static contextTypes = {
Expand All @@ -47,7 +49,6 @@ export default class VictoryContainer extends React.Component {

componentWillMount() {
this.savePortalRef = (portal) => this.portalRef = portal;
this.saveSvgRef = (svg) => this.svgRef = svg;
this.portalUpdate = (key, el) => this.portalRef.portalUpdate(key, el);
this.portalRegister = () => this.portalRef.portalRegister();
this.portalDeregister = (key) => this.portalRef.portalDeregister(key);
Expand Down Expand Up @@ -78,27 +79,40 @@ export default class VictoryContainer extends React.Component {
return this.timer;
}

// overridden in custom containers
getChildren(props) {
return props.children;
}

// Overridden in victory-core-native
renderContainer(props, svgProps, style) {
const { title, desc, children, portalComponent, className } = props;
return (
<svg {...svgProps} style={style} className={className}>
<title id="title">{title}</title>
<desc id="desc">{desc}</desc>
{children}
{React.cloneElement(portalComponent, {ref: this.savePortalRef})}
</svg>
);
const { title, desc, portalComponent, className, standalone } = props;
return standalone ?
(
<svg {...svgProps} style={style} className={className}>
<title id="title">{title}</title>
<desc id="desc">{desc}</desc>
{this.getChildren(props)}
{React.cloneElement(portalComponent, {ref: this.savePortalRef})}
</svg>
) :
(
<g {...svgProps} style={style} className={className}>
<title id="title">{title}</title>
<desc id="desc">{desc}</desc>
{this.getChildren(props)}
{React.cloneElement(portalComponent, {ref: this.savePortalRef})}
</g>
);
}

render() {
const { width, height, responsive, events } = this.props;
const { width, height, responsive, events, standalone } = this.props;
const style = responsive ? this.props.style : omit(this.props.style, ["height", "width"]);
const svgProps = assign(
{
"aria-labelledby": "title desc", role: "img", width, height,
viewBox: responsive ? `0 0 ${width} ${height}` : undefined,
ref: this.saveSvgRef
viewBox: responsive && standalone ? `0 0 ${width} ${height}` : undefined
},
events
);
Expand Down
27 changes: 26 additions & 1 deletion src/victory-shared-events/victory-shared-events.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { assign, isFunction, partialRight, defaults } from "lodash";
import React, { PropTypes } from "react";
import { PropTypes as CustomPropTypes, Events } from "../victory-util/index";
import { PropTypes as CustomPropTypes, Events, Timer } from "../victory-util/index";

export default class VictorySharedEvents extends React.Component {
static displayName = "VictorySharedEvents";
Expand Down Expand Up @@ -40,11 +40,36 @@ export default class VictorySharedEvents extends React.Component {
groupComponent: <g/>
};

static contextTypes = {
getTimer: React.PropTypes.func
};

static childContextTypes = {
getTimer: React.PropTypes.func
};

constructor() {
super();
this.state = this.state || {};
this.getScopedEvents = Events.getScopedEvents.bind(this);
this.getEventState = Events.getEventState.bind(this);
this.getTimer = this.getTimer.bind(this);
}

getChildContext() {
return {
getTimer: this.getTimer
};
}

getTimer() {
if (this.context.getTimer) {
return this.context.getTimer();
}
if (!this.timer) {
this.timer = new Timer();
}
return this.timer;
}

componentWillMount() {
Expand Down
20 changes: 15 additions & 5 deletions src/victory-util/add-events.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defaults, assign, isFunction, partialRight } from "lodash";
import { defaults, assign, isFunction, partialRight, pick } from "lodash";
import Events from "./events";

export default (WrappedComponent) => {
Expand All @@ -15,7 +15,7 @@ export default (WrappedComponent) => {
this.setupEvents(this.props);
}

componentWillReceiveProps(newProps) {
componentWillUpdate(newProps) {
if (isFunction(super.componentWillReceiveProps)) {
super.componentWillReceiveProps();
}
Expand All @@ -26,15 +26,25 @@ export default (WrappedComponent) => {
const { sharedEvents } = props;
const components = WrappedComponent.expectedComponents;
this.componentEvents = Events.getComponentEvents(props, components);
this.baseProps = isFunction(WrappedComponent.getBaseProps) ?
WrappedComponent.getBaseProps(props) : {};
this.dataKeys = Object.keys(this.baseProps).filter((key) => key !== "parent");
this.getSharedEventState = sharedEvents && isFunction(sharedEvents.getEventState) ?
sharedEvents.getEventState : () => undefined;
this.baseProps = this.getBaseProps(props);
this.dataKeys = Object.keys(this.baseProps).filter((key) => key !== "parent");
this.hasEvents = props.events || props.sharedEvents || this.componentEvents;
this.events = this.getAllEvents(props);
}

getBaseProps(props) {
const sharedParentState = this.getSharedEventState("parent", "parent");
const parentState = this.getEventState("parent", "parent");
const baseParentProps = defaults({}, parentState, sharedParentState);
const parentPropsList = baseParentProps.parentControlledProps;
const parentProps = parentPropsList ? pick(baseParentProps, parentPropsList) : {};
const modifiedProps = defaults({}, parentProps, props);
return isFunction(WrappedComponent.getBaseProps) ?
WrappedComponent.getBaseProps(modifiedProps) : {};
}

getAllEvents(props) {
if (Array.isArray(this.componentEvents)) {
return Array.isArray(props.events) ?
Expand Down
14 changes: 12 additions & 2 deletions src/victory-util/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,22 @@ export default {
parseEvent(eventReturn, eventKey);
};

const compileCallbacks = (eventReturn) => {
const getCallback = (obj) => isFunction(obj.callback) && obj.callback;
const callbacks = Array.isArray(eventReturn) ?
eventReturn.map((evtObj) => getCallback(evtObj)) : [getCallback(eventReturn)];
const callbackArray = callbacks.filter((callback) => callback !== false);
return callbackArray.length ?
() => callbackArray.forEach((callback) => callback()) : undefined;
};

// A function that calls a particular event handler, parses its return
// into a state mutation, and calls setState
const onEvent = (evt, childProps, eventKey, eventName) => {
const eventReturn = events[eventName](evt, childProps, eventKey);
const eventReturn = events[eventName](evt, childProps, eventKey, this);
if (eventReturn) {
this.setState(parseEventReturn(eventReturn, eventKey));
const callbacks = compileCallbacks(eventReturn);
this.setState(parseEventReturn(eventReturn, eventKey), callbacks);
}
};

Expand Down
23 changes: 20 additions & 3 deletions src/victory-util/selection.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,30 @@ export default {
}
},

getTransformationMatrix(svg) {
return svg.getScreenCTM().inverse();
},

getSVGEventCoordinates(evt) {
const svg = this.getParentSVG(evt.target);
const matrix = svg.getScreenCTM().inverse();
const matrix = this.getTransformationMatrix(svg);
return {
x: this.transformTarget(evt.clientX, matrix, "x"),
y: this.transformTarget(evt.clientY, matrix, "y")
};
},

transformTarget(target, matrix, dimension) {
const {a, d, e, f} = matrix;
return dimension === "y" ?
d * target + f : a * target + e;
},

getDomainCoordinates(scale, domain) {
domain = domain || { x: scale.x.domain(), y: scale.y.domain()};
return {
x: a * evt.clientX + e,
y: d * evt.clientY + f
x: [scale.x(domain.x[0]), scale.x(domain.x[1])],
y: [scale.y(domain.y[0]), scale.y(domain.y[1])]
};
},

Expand Down

0 comments on commit 5ef16eb

Please sign in to comment.