Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(legend/series): add hover interaction on legend items #31

Merged
merged 21 commits into from
Feb 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
455a033
feat(legend/series): add hover interaction on legend items
emmacunningham Feb 4, 2019
a063717
feat(legend/series): set highlighted legend item to null on mouseout
emmacunningham Feb 4, 2019
94d6508
feat(legend/series): compare highlightedLegendItemIndex with null
emmacunningham Feb 4, 2019
3db7f00
feat(legend/series): add legend hover interaction to line series
emmacunningham Feb 4, 2019
ae5dcaf
feat(legend/series): add legend hover interaction to area chart
emmacunningham Feb 4, 2019
d6d88a9
refactor(geometry): allow all geometries to have specId & seriesKey
emmacunningham Feb 6, 2019
c062b2e
refactor(geometries): share common styles with different geometries
emmacunningham Feb 7, 2019
409097e
refactor(geometry): add GEOMETRY_STYLES constant
emmacunningham Feb 7, 2019
65b59f8
docs(legend): add interaction stories for each chart type
emmacunningham Feb 8, 2019
eec61b3
refactor(legend): move getter to store
emmacunningham Feb 8, 2019
98d5cec
refactor: move shared geometry style to theme
emmacunningham Feb 8, 2019
7d12db7
refactor(legend): use observable for legend item state
emmacunningham Feb 8, 2019
61a2443
refactor: use for loop for series key array comparison
emmacunningham Feb 8, 2019
77e101f
refactor(geometry): move bar hover opacity logic to shared logic
emmacunningham Feb 8, 2019
4e4dafd
refactor: use computed for current highlighted legend item
emmacunningham Feb 8, 2019
26ff575
feat(legend): add mouse over/out listeners from store
emmacunningham Feb 8, 2019
407fc94
refactor: pass only the necessary values to legend mouseover listener
emmacunningham Feb 9, 2019
669da2a
feat(legend): add hover style for legend title
emmacunningham Feb 13, 2019
3fe141a
fix(legend): use mouseenter/leave for consistent event firing
emmacunningham Feb 13, 2019
9f467cb
feat(legend): add hover style to entire legend item
emmacunningham Feb 13, 2019
166841c
feat(legend): remove tooltip in favor of title for item
emmacunningham Feb 13, 2019
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
9 changes: 7 additions & 2 deletions src/components/_legend.scss
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ $euiChartLegendMaxHeight: $euiSize * 4 + $euiSize;
top: 0;
bottom: 0;
left: 0;
width: $euiChartLegendMaxWidth;
width: $euiChartLegendMaxWidth;
order: 1;
.euiChartLegend__listItem {
min-width: 100%;
Expand All @@ -58,7 +58,7 @@ $euiChartLegendMaxHeight: $euiSize * 4 + $euiSize;
top: 0;
bottom: 0;
right: 0;
width: $euiChartLegendMaxWidth;
width: $euiChartLegendMaxWidth;
.euiChartLegend__listItem {
min-width: 100%;
}
Expand Down Expand Up @@ -93,4 +93,9 @@ $euiChartLegendMaxHeight: $euiSize * 4 + $euiSize;
.euiChartLegendListItem__title {
width: $euiChartLegendMaxWidth - 4 * $euiSize;
max-width: $euiChartLegendMaxWidth - 4 * $euiSize;
}
.euiChartLegendList__item {
&:hover {
text-decoration: underline;
}
}
30 changes: 21 additions & 9 deletions src/components/legend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
EuiFlexItem,
EuiIcon,
EuiText,
EuiToolTip,
} from '@elastic/eui';
import classNames from 'classnames';
import { inject, observer } from 'mobx-react';
Expand Down Expand Up @@ -86,8 +85,15 @@ class LegendComponent extends React.Component<ReactiveChartProps> {
responsive={false}
>
{legendItems.map((item, index) => {
const legendItemProps = {
key: index,
className: 'euiChartLegendList__item',
onMouseEnter: this.onLegendItemMouseover(index),
onMouseLeave: this.onLegendItemMouseout,
};

return (
<EuiFlexItem key={index} className="euiChartLegendList__item">
<EuiFlexItem {...legendItemProps}>
<LegendElement color={item.color} label={item.label} />
</EuiFlexItem>
);
Expand All @@ -97,6 +103,14 @@ class LegendComponent extends React.Component<ReactiveChartProps> {
</div>
);
}

private onLegendItemMouseover = (legendItemIndex: number) => () => {
this.props.chartStore!.onLegendItemOver(legendItemIndex);
}

private onLegendItemMouseout = () => {
this.props.chartStore!.onLegendItemOut();
}
}
function LegendElement({ color, label }: Partial<LegendItem>) {
return (
Expand All @@ -105,13 +119,11 @@ function LegendElement({ color, label }: Partial<LegendItem>) {
<EuiIcon type="dot" color={color} />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiToolTip position="right" content={<EuiText size="xs">{label}</EuiText>}>
<EuiFlexItem grow={true} className="euiChartLegendListItem__title">
<EuiText size="xs" className="eui-textTruncate">
{label}
</EuiText>
</EuiFlexItem>
</EuiToolTip>
<EuiFlexItem grow={true} className="euiChartLegendListItem__title" title={label}>
<EuiText size="xs" className="eui-textTruncate">
{label}
</EuiText>
</EuiFlexItem>
</EuiFlexItem>
</EuiFlexGroup>
);
Expand Down
22 changes: 15 additions & 7 deletions src/components/react_canvas/area_geometries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { IAction } from 'mobx';
import React from 'react';
import { Circle, Group, Path } from 'react-konva';
import { animated, Spring } from 'react-spring/konva';
import { AreaGeometry, GeometryValue, PointGeometry } from '../../lib/series/rendering';
import { LegendItem } from '../../lib/series/legend';
import { AreaGeometry, GeometryValue, getGeometryStyle, PointGeometry } from '../../lib/series/rendering';
import { AreaSeriesStyle } from '../../lib/themes/theme';
import { ElementClickListener, TooltipData } from '../../state/chart_state';

Expand All @@ -15,14 +16,15 @@ interface AreaGeometriesDataProps {
onElementClick?: ElementClickListener;
onElementOver: ((tooltip: TooltipData) => void) & IAction;
onElementOut: (() => void) & IAction;
highlightedLegendItem: LegendItem | null;
}
interface AreaGeometriesDataState {
overPoint?: PointGeometry;
}
export class AreaGeometries extends React.PureComponent<
AreaGeometriesDataProps,
AreaGeometriesDataState
> {
> {
static defaultProps: Partial<AreaGeometriesDataProps> = {
animated: false,
num: 1,
Expand Down Expand Up @@ -131,10 +133,14 @@ export class AreaGeometries extends React.PureComponent<
);
});
}

private renderAreaGeoms = (): JSX.Element[] => {
const { areas } = this.props;
return areas.map((glyph, i) => {
const { area, color, transform } = glyph;
const { area, color, transform, geometryId } = glyph;

const geometryStyle = getGeometryStyle(geometryId, this.props.highlightedLegendItem);

if (this.props.animated) {
return (
<Group key={`area-group-${i}`} x={transform.x}>
Expand All @@ -145,8 +151,9 @@ export class AreaGeometries extends React.PureComponent<
data={props.area}
fill={color}
listening={false}
// areaCap="round"
// areaJoin="round"
{...geometryStyle}
// areaCap="round"
// areaJoin="round"
/>
)}
</Spring>
Expand All @@ -159,8 +166,9 @@ export class AreaGeometries extends React.PureComponent<
data={area}
fill={color}
listening={false}
// areaCap="round"
// areaJoin="round"
{...geometryStyle}
// areaCap="round"
// areaJoin="round"
/>
);
}
Expand Down
26 changes: 18 additions & 8 deletions src/components/react_canvas/bar_geometries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { IAction } from 'mobx';
import React from 'react';
import { Group, Rect } from 'react-konva';
import { animated, Spring } from 'react-spring/konva';
import { BarGeometry, GeometryValue } from '../../lib/series/rendering';
import { LegendItem } from '../../lib/series/legend';
import { BarGeometry, GeometryValue, getGeometryStyle } from '../../lib/series/rendering';
import { ElementClickListener, TooltipData } from '../../state/chart_state';

interface BarGeometriesDataProps {
Expand All @@ -12,14 +13,15 @@ interface BarGeometriesDataProps {
onElementClick?: ElementClickListener;
onElementOver: ((tooltip: TooltipData) => void) & IAction;
onElementOut: (() => void) & IAction;
highlightedLegendItem: LegendItem | null;
}
interface BarGeometriesDataState {
overBar?: BarGeometry;
}
export class BarGeometries extends React.PureComponent<
BarGeometriesDataProps,
BarGeometriesDataState
> {
> {
static defaultProps: Partial<BarGeometriesDataProps> = {
animated: false,
};
Expand Down Expand Up @@ -70,14 +72,22 @@ export class BarGeometries extends React.PureComponent<
});
onElementOut();
}

private renderBarGeoms = (bars: BarGeometry[]): JSX.Element[] => {
const { overBar } = this.state;
return bars.map((bar, i) => {
const { x, y, width, height, color, value } = bar;
let opacity = 1;
if (overBar && overBar !== bar) {
opacity = 0.6;
}

// Properties to determine if we need to highlight individual bars depending on hover state
const hasGeometryHover = overBar != null;
const hasHighlight = overBar === bar;
const individualHighlight = {
hasGeometryHover,
hasHighlight,
};

const geometryStyle = getGeometryStyle(bar.geometryId, this.props.highlightedLegendItem, individualHighlight);

if (this.props.animated) {
return (
<Group key={i}>
Expand All @@ -91,11 +101,11 @@ export class BarGeometries extends React.PureComponent<
height={props.height}
fill={color}
strokeWidth={0}
opacity={opacity}
perfectDrawEnabled={true}
onMouseOver={this.onOverBar(bar)}
onMouseLeave={this.onOutBar}
onClick={this.onElementClick(value)}
{...geometryStyle}
markov00 marked this conversation as resolved.
Show resolved Hide resolved
/>
)}
</Spring>
Expand All @@ -111,11 +121,11 @@ export class BarGeometries extends React.PureComponent<
height={height}
fill={color}
strokeWidth={0}
opacity={opacity}
perfectDrawEnabled={false}
onMouseOver={this.onOverBar(bar)}
onMouseLeave={this.onOutBar}
onClick={this.onElementClick(bar.value)}
{...geometryStyle}
markov00 marked this conversation as resolved.
Show resolved Hide resolved
/>
);
}
Expand Down
14 changes: 11 additions & 3 deletions src/components/react_canvas/line_geometries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { IAction } from 'mobx';
import React from 'react';
import { Circle, Group, Path } from 'react-konva';
import { animated, Spring } from 'react-spring/konva';
import { GeometryValue, LineGeometry, PointGeometry } from '../../lib/series/rendering';
import { LegendItem } from '../../lib/series/legend';
import { GeometryValue, getGeometryStyle, LineGeometry, PointGeometry } from '../../lib/series/rendering';
import { LineSeriesStyle } from '../../lib/themes/theme';
import { ElementClickListener, TooltipData } from '../../state/chart_state';

Expand All @@ -14,14 +15,15 @@ interface LineGeometriesDataProps {
onElementClick?: ElementClickListener;
onElementOver: ((tooltip: TooltipData) => void) & IAction;
onElementOut: (() => void) & IAction;
highlightedLegendItem: LegendItem | null;
}
interface LineGeometriesDataState {
overPoint?: PointGeometry;
}
export class LineGeometries extends React.PureComponent<
LineGeometriesDataProps,
LineGeometriesDataState
> {
> {
static defaultProps: Partial<LineGeometriesDataProps> = {
animated: false,
};
Expand Down Expand Up @@ -129,10 +131,14 @@ export class LineGeometries extends React.PureComponent<
);
});
}

private renderLineGeoms = (): JSX.Element[] => {
const { style, lines } = this.props;
return lines.map((glyph, i) => {
const { line, color, transform } = glyph;
const { line, color, transform, geometryId } = glyph;

const geometryStyle = getGeometryStyle(geometryId, this.props.highlightedLegendItem);

if (this.props.animated) {
return (
<Group key={i} x={transform.x}>
Expand All @@ -146,6 +152,7 @@ export class LineGeometries extends React.PureComponent<
listening={false}
lineCap="round"
lineJoin="round"
{...geometryStyle}
/>
)}
</Spring>
Expand All @@ -161,6 +168,7 @@ export class LineGeometries extends React.PureComponent<
listening={false}
lineCap="round"
lineJoin="round"
{...geometryStyle}
/>
);
}
Expand Down
15 changes: 15 additions & 0 deletions src/components/react_canvas/reactive_chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,16 @@ class Chart extends React.Component<ReactiveChartProps, ReactiveChartState> {
if (!geometries) {
return;
}
const highlightedLegendItem = this.getHighlightedLegendItem();

return (
<BarGeometries
animated={canDataBeAnimated}
bars={geometries.bars}
onElementOver={onOverElement}
onElementOut={onOutElement}
onElementClick={onElementClickListener}
highlightedLegendItem={highlightedLegendItem}
/>
);
}
Expand All @@ -93,6 +96,9 @@ class Chart extends React.Component<ReactiveChartProps, ReactiveChartState> {
if (!geometries) {
return;
}

const highlightedLegendItem = this.getHighlightedLegendItem();

return (
<LineGeometries
animated={canDataBeAnimated}
Expand All @@ -101,6 +107,7 @@ class Chart extends React.Component<ReactiveChartProps, ReactiveChartState> {
onElementOver={onOverElement}
onElementOut={onOutElement}
onElementClick={onElementClickListener}
highlightedLegendItem={highlightedLegendItem}
/>
);
}
Expand All @@ -116,6 +123,9 @@ class Chart extends React.Component<ReactiveChartProps, ReactiveChartState> {
if (!geometries) {
return;
}

const highlightedLegendItem = this.getHighlightedLegendItem();

return (
<AreaGeometries
animated={canDataBeAnimated}
Expand All @@ -124,6 +134,7 @@ class Chart extends React.Component<ReactiveChartProps, ReactiveChartState> {
onElementOver={onOverElement}
onElementOut={onOutElement}
onElementClick={onElementClickListener}
highlightedLegendItem={highlightedLegendItem}
/>
);
}
Expand Down Expand Up @@ -353,6 +364,10 @@ class Chart extends React.Component<ReactiveChartProps, ReactiveChartState> {
/>
);
}

private getHighlightedLegendItem = () => {
return this.props.chartStore!.highlightedLegendItem.get();
}
markov00 marked this conversation as resolved.
Show resolved Hide resolved
}

export const ReactiveChart = inject('chartStore')(observer(Chart));
Loading