Skip to content
This repository has been archived by the owner on Dec 10, 2021. It is now read-only.

Commit

Permalink
feat: add tooltip and layout components for charts (#13)
Browse files Browse the repository at this point in the history
* feat: add components for charts

* refactor: remove jsx

* refactor: address comments
  • Loading branch information
kristw committed Mar 13, 2019
1 parent 4f02035 commit 27227eb
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 90 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import { isDefined } from '@superset-ui/core';

function checkNumber(input: any): input is number {
return isDefined(input) && typeof input === 'number';
}

type Props = {
contentWidth?: number;
contentHeight?: number;
height: number;
renderContent: ({ height, width }: { height: number; width: number }) => React.ReactElement;
width: number;
};

export default class ChartFrame extends React.PureComponent<Props, {}> {
static defaultProps = {
renderContent() {},
};

render() {
const { contentWidth, contentHeight, width, height, renderContent } = this.props;

const overflowX = checkNumber(contentWidth) && contentWidth > width;
const overflowY = checkNumber(contentHeight) && contentHeight > height;

if (overflowX || overflowY) {
return (
<div
style={{
height,
overflowX: overflowX ? 'auto' : 'hidden',
overflowY: overflowY ? 'auto' : 'hidden',
width,
}}
>
{renderContent({
height: Math.max(contentHeight || 0, height),
width: Math.max(contentWidth || 0, width),
})}
</div>
);
}

return renderContent({ height, width });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,23 @@
* under the License.
*/
/* eslint-disable sort-keys */
import React from 'react';
import PropTypes from 'prop-types';
import React, { CSSProperties, ReactNode } from 'react';
import { ParentSize } from '@vx/responsive';
// eslint-disable-next-line import/no-unresolved
import * as CSS from 'csstype';

const propTypes = {
className: PropTypes.string,
width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
legendJustifyContent: PropTypes.oneOf(['center', 'flex-start', 'flex-end']),
position: PropTypes.oneOf(['top', 'left', 'bottom', 'right']),
renderChart: PropTypes.func.isRequired,
renderLegend: PropTypes.func.isRequired,
hideLegend: PropTypes.bool,
};
const defaultProps = {
className: '',
width: 'auto',
height: 'auto',
legendJustifyContent: undefined,
position: 'top',
hideLegend: false,
type Props = {
className: string;
width: number | string;
height: number | string;
legendJustifyContent: 'center' | 'flex-start' | 'flex-end';
position: 'top' | 'left' | 'bottom' | 'right';
renderChart: (dim: { width: number; height: number }) => ReactNode;
renderLegend: (params: { direction: string }) => ReactNode;
hideLegend: boolean;
};

const LEGEND_STYLE_BASE = {
const LEGEND_STYLE_BASE: CSSProperties = {
display: 'flex',
flexGrow: 0,
flexShrink: 0,
Expand All @@ -49,15 +42,24 @@ const LEGEND_STYLE_BASE = {
fontSize: '0.9em',
};

const CHART_STYLE_BASE = {
const CHART_STYLE_BASE: CSSProperties = {
flexGrow: 1,
flexShrink: 1,
flexBasis: 'auto',
position: 'relative',
};

class WithLegend extends React.Component {
getContainerDirection() {
class WithLegend extends React.PureComponent<Props, {}> {
static defaultProps = {
className: '',
width: 'auto',
height: 'auto',
legendJustifyContent: undefined,
position: 'top',
hideLegend: false,
};

getContainerDirection(): CSS.FlexDirectionProperty {
const { position } = this.props;
switch (position) {
case 'left':
Expand Down Expand Up @@ -101,13 +103,9 @@ class WithLegend extends React.Component {
hideLegend,
} = this.props;

if (hideLegend) {
return <div className={className}>{renderChart({ width, height })}</div>;
}

const isHorizontal = position === 'left' || position === 'right';

const style = {
const style: CSSProperties = {
display: 'flex',
flexDirection: this.getContainerDirection(),
};
Expand All @@ -118,31 +116,33 @@ class WithLegend extends React.Component {
style.height = height;
}

const chartStyle = { ...CHART_STYLE_BASE };
const chartStyle: CSSProperties = { ...CHART_STYLE_BASE };
if (isHorizontal) {
chartStyle.width = 0;
} else {
chartStyle.height = 0;
}

const legendDirection = isHorizontal ? 'column' : 'row';
const legendStyle = {
const legendStyle: CSSProperties = {
...LEGEND_STYLE_BASE,
flexDirection: legendDirection,
justifyContent: this.getLegendJustifyContent(),
};

return (
<div className={`with-legend ${className}`} style={style}>
<div className="legend-container" style={legendStyle}>
{renderLegend({
// Pass flexDirection for @vx/legend to arrange legend items
direction: legendDirection,
})}
</div>
{!hideLegend && (
<div className="legend-container" style={legendStyle}>
{renderLegend({
// Pass flexDirection for @vx/legend to arrange legend items
direction: legendDirection,
})}
</div>
)}
<div className="main-container" style={chartStyle}>
<ParentSize>
{parent =>
{(parent: { width: number; height: number }) =>
parent.width > 0 && parent.height > 0
? // Only render when necessary
renderChart(parent)
Expand All @@ -155,7 +155,4 @@ class WithLegend extends React.Component {
}
}

WithLegend.propTypes = propTypes;
WithLegend.defaultProps = defaultProps;

export default WithLegend;
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';

type Props = {
className?: string;
children: React.ReactNode;
};

const CONTAINER_STYLE = { padding: 8 };

class TooltipFrame extends React.PureComponent<Props, {}> {
static defaultProps = {
className: '',
};

render() {
const { className, children } = this.props;

return (
<div className={className} style={CONTAINER_STYLE}>
{children}
</div>
);
}
}

export default TooltipFrame;
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { CSSProperties } from 'react';

type Props = {
className?: string;
data: {
key: string;
keyStyle?: CSSProperties;
value: string | number;
valueStyle?: CSSProperties;
}[];
};

const VALUE_CELL_STYLE: CSSProperties = { paddingLeft: 8, textAlign: 'right' };

export default class TooltipTable extends React.PureComponent<Props, {}> {
static defaultProps = {
className: '',
data: [],
};

render() {
const { className, data } = this.props;

return (
<table className={className}>
<tbody>
{data.map(({ key, keyStyle, value, valueStyle }) => (
<tr key={key}>
<td style={keyStyle}>{key}</td>
<td style={valueStyle ? { ...VALUE_CELL_STYLE, ...valueStyle } : VALUE_CELL_STYLE}>
{value}
</td>
</tr>
))}
</tbody>
</table>
);
}
}

0 comments on commit 27227eb

Please sign in to comment.