Skip to content

Commit

Permalink
Merge pull request #131 from conglei/conglei_add_brush_reset
Browse files Browse the repository at this point in the history
[UI]added reset support and click support for Brush
  • Loading branch information
williaster committed Sep 10, 2018
2 parents 1747f85 + 4fcf9ee commit 2620c9a
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 34 deletions.
12 changes: 12 additions & 0 deletions packages/demo/examples/01-xy-chart/BrushableLineChart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class BrushableLineChart extends React.PureComponent {
disableDraggingSelection: false,
};
this.handleBrushChange = this.handleBrushChange.bind(this);
this.handleClearBrush = this.handleClearBrush.bind(this);
this.Brush = React.createRef();
}

handleBrushChange(domain) {
Expand Down Expand Up @@ -64,13 +66,22 @@ class BrushableLineChart extends React.PureComponent {
}));
}

handleClearBrush() {
this.Brush.current.reset();
}

renderControls() {
const { disableDraggingSelection, resizeTriggerAreas } = this.state;
const resizeTriggerAreaset = new Set(resizeTriggerAreas);

return (
<div className="brush-demo--form">
<h4>Brush Props</h4>
<div>
<button type="button" onClick={this.handleClearBrush}>
Clear Brush
</button>
</div>
<div>
Disable Dragging the Selection
<label>
Expand Down Expand Up @@ -409,6 +420,7 @@ class BrushableLineChart extends React.PureComponent {
fill: 'url(#brush_pattern)',
stroke: allColors.blue[5],
}}
ref={this.Brush}
/>
</XYChart>

Expand Down
67 changes: 59 additions & 8 deletions packages/demo/examples/01-xy-chart/HorizontalBarChart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
import React from 'react';
import { timeParse, timeFormat } from 'd3-time-format';

import { CrossHair, XAxis, YAxis, BarSeries, PatternCircles } from '@data-ui/xy-chart';
import { CrossHair, XAxis, YAxis, BarSeries, PatternCircles, Brush } from '@data-ui/xy-chart';

import colors, { allColors } from '@data-ui/theme/lib/color';
import { allColors } from '@data-ui/theme/lib/color';
import ResponsiveXYChart from './ResponsiveXYChart';

import { timeSeriesData } from './data';
Expand All @@ -17,19 +17,49 @@ export const dateFormatter = date => formatYear(parseDate(date));
const categoryHorizontalData = timeSeriesData.map((d, i) => ({
x: d.y,
y: i + 1,
selected: false,
}));

const categoryData = timeSeriesData.map((d, i) => ({
x: i + 1,
y: d.y,
selected: false,
}));

class HorizontalBarChartExample extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
direction: 'horizontal',
data: categoryHorizontalData,
};
this.Brush = React.createRef();
this.handleBrushChange = this.handleBrushChange.bind(this);
}

handleBrushChange(domain) {
let valueSet = new Set();
const { direction } = this.state;
const horizontal = direction === 'horizontal';
if (domain) {
const values = horizontal ? domain.yValues : domain.xValues;
valueSet = new Set(values);
}
let data;
if (horizontal) {
data = categoryHorizontalData.map(bar => ({
...bar,
selected: valueSet.has(bar.y),
}));
} else {
data = categoryData.map(bar => ({
...bar,
selected: valueSet.has(bar.x),
}));
}
this.setState(() => ({
data,
}));
}

renderControls() {
Expand All @@ -42,7 +72,13 @@ class HorizontalBarChartExample extends React.PureComponent {
<input
type="radio"
value="horizontal"
onChange={e => this.setState({ direction: e.target.value })}
onChange={e => {
this.Brush.current.reset();
this.setState({
direction: e.target.value,
data: [...categoryHorizontalData],
});
}}
checked={this.state.direction === 'horizontal'}
/>{' '}
horizonal
Expand All @@ -51,7 +87,13 @@ class HorizontalBarChartExample extends React.PureComponent {
<input
type="radio"
value="vertical"
onChange={e => this.setState({ direction: e.target.value })}
onChange={e => {
this.Brush.current.reset();
this.setState({
direction: e.target.value,
data: [...categoryData],
});
}}
checked={this.state.direction !== 'horizontal'}
/>{' '}
vertical
Expand All @@ -62,7 +104,7 @@ class HorizontalBarChartExample extends React.PureComponent {
}

render() {
const { direction } = this.state;
const { direction, data } = this.state;
const categoryScale = { type: 'band', paddingInner: 0.4 };
const valueScale = { type: 'linear' };
const horizontal = direction === 'horizontal';
Expand All @@ -86,14 +128,18 @@ class HorizontalBarChartExample extends React.PureComponent {
strokeWidth={0}
/>
<BarSeries
fill={allColors.blue[horizontal ? 8 : 2]}
fill={bar => {
const color = bar.selected ? allColors.red : allColors.blue;

return color[horizontal ? 8 : 2];
}}
horizontal={horizontal}
data={horizontal ? categoryHorizontalData : categoryData}
data={data}
/>
<BarSeries
fill="url(#horizontal_bar_circles)"
horizontal={horizontal}
data={horizontal ? categoryHorizontalData : categoryData}
data={data}
stroke={allColors.blue[8]}
strokeWidth={1.5}
/>
Expand All @@ -109,6 +155,11 @@ class HorizontalBarChartExample extends React.PureComponent {
/>
<YAxis numTicks={5} orientation="left" />
<XAxis numTicks={5} />
<Brush
brushDirection={horizontal ? 'vertical' : 'horizontal'}
ref={this.Brush}
onChange={this.handleBrushChange}
/>
</ResponsiveXYChart>

<style type="text/css">
Expand Down
3 changes: 2 additions & 1 deletion packages/demo/examples/01-xy-chart/LineSeriesExample.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Button } from '@data-ui/forms';
import { LegendOrdinal } from '@vx/legend';
import { scaleOrdinal } from '@vx/scale';

import { CrossHair, LineSeries, WithTooltip, XAxis, YAxis } from '@data-ui/xy-chart';
import { CrossHair, LineSeries, WithTooltip, XAxis, YAxis, Brush } from '@data-ui/xy-chart';

import ResponsiveXYChart, { formatYear } from './ResponsiveXYChart';
import { timeSeriesData } from './data';
Expand Down Expand Up @@ -316,6 +316,7 @@ class LineSeriesExample extends React.PureComponent {
showCircle={useVoronoiTrigger || !this.state.programmaticTrigger}
showMultipleCircles={!useVoronoiTrigger && showMultipleCircles}
/>
<Brush disableDraggingSelection />
</ResponsiveXYChart>
)}
</WithTooltip>
Expand Down
59 changes: 47 additions & 12 deletions packages/xy-chart/src/selection/Brush.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { color } from '@data-ui/theme';

import BaseBrush from '../utils/brush/Brush';
import { generalStyleShape, marginShape } from '../utils/propShapes';
import { scaleInvert, getDomainFromExtent } from '../utils/chartUtils';

const SAFE_PIXEL = 2;

Expand All @@ -18,6 +19,7 @@ export const propTypes = {
onBrushEnd: PropTypes.func,
onMouseMove: PropTypes.func,
onMouseLeave: PropTypes.func,
onClick: PropTypes.func,
margin: marginShape,
brushDirection: PropTypes.oneOf(['vertical', 'horizontal', 'both']),
resizeTriggerAreas: PropTypes.arrayOf(
Expand All @@ -37,6 +39,16 @@ export const propTypes = {
xAxisOrientation: PropTypes.oneOf(['top', 'bottom']),
disableDraggingSelection: PropTypes.bool,
handleSize: PropTypes.number,
enabledRegion: PropTypes.shape({
start: PropTypes.shape({
x: PropTypes.oneOf([PropTypes.number, PropTypes.string]),
y: PropTypes.oneOf([PropTypes.number, PropTypes.string]),
}),
end: PropTypes.shape({
x: PropTypes.oneOf([PropTypes.number, PropTypes.string]),
y: PropTypes.oneOf([PropTypes.number, PropTypes.string]),
}),
}),
};

const defaultProps = {
Expand Down Expand Up @@ -69,21 +81,30 @@ const defaultProps = {
disableDraggingSelection: false,
onMouseMove: null,
onMouseLeave: null,
onClick: null,
enabledRegion: null,
};

class Brush extends React.Component {
constructor(props) {
super(props);

this.BaseBrush = null;
this.handleChange = this.handleChange.bind(this);
this.handleBrushStart = this.handleBrushStart.bind(this);
this.handleBrushEnd = this.handleBrushEnd.bind(this);
this.reset = this.reset.bind(this);
}

reset() {
this.BaseBrush.reset();
}

handleChange(brush) {
const { onChange } = this.props;
if (!onChange) return;
const { x0 } = brush.extent;
if (x0 < 0) {
if (x0 < 0 || typeof x0 === 'undefined') {
onChange(null);

return;
Expand All @@ -95,24 +116,32 @@ class Brush extends React.Component {
convertRangeToDomain(brush) {
const { xScale, yScale } = this.props;
const { x0, x1, y0, y1 } = brush.extent;
const invertedX0 = xScale.invert(x0 + (x0 < x1 ? -SAFE_PIXEL : SAFE_PIXEL));
const invertedX1 = xScale.invert(x1 + (x1 < x0 ? -SAFE_PIXEL : SAFE_PIXEL));
const invertedY0 = yScale.invert(y0 + (y0 < y1 ? -SAFE_PIXEL : SAFE_PIXEL));
const invertedY1 = yScale.invert(y1 + (y1 < y0 ? -SAFE_PIXEL : SAFE_PIXEL));

const xDomain = getDomainFromExtent(xScale, x0, x1, SAFE_PIXEL);
const yDomain = getDomainFromExtent(yScale, y0, y1, SAFE_PIXEL);

const domain = {
x0: Math.min(invertedX0, invertedX1),
x1: Math.max(invertedX0, invertedX1),
y0: Math.min(invertedY0, invertedY1),
y1: Math.max(invertedY0, invertedY1),
x0: xDomain.start,
x1: xDomain.end,
xValues: xDomain.values,
y0: yDomain.start,
y1: yDomain.end,
yValues: yDomain.values,
};

return domain;
}

handleBrushStart() {
const { onBrushStart } = this.props;
handleBrushStart(point) {
const { x, y } = point;
const { onBrushStart, xScale, yScale } = this.props;
const invertedX = scaleInvert(xScale, x);
const invertedY = scaleInvert(yScale, y);
if (onBrushStart) {
onBrushStart();
onBrushStart({
x: xScale.invert ? invertedX : xScale.domain()[invertedX],
y: yScale.invert ? invertedY : yScale.domain()[invertedY],
});
}
}

Expand Down Expand Up @@ -145,7 +174,9 @@ class Brush extends React.Component {
disableDraggingSelection,
onMouseLeave,
onMouseMove,
onClick,
handleSize,
enabledRegion,
} = this.props;
if (!xScale || !yScale) return null;

Expand Down Expand Up @@ -198,6 +229,10 @@ class Brush extends React.Component {
disableDraggingSelection={disableDraggingSelection}
onMouseLeave={onMouseLeave}
onMouseMove={onMouseMove}
onClick={onClick}
ref={el => {
this.BaseBrush = el;
}}
/>
);
}
Expand Down
Loading

0 comments on commit 2620c9a

Please sign in to comment.