Skip to content
This repository has been archived by the owner on Jun 25, 2020. It is now read-only.

Commit

Permalink
feat: improve line chart margin/axis and add buildquery (#66)
Browse files Browse the repository at this point in the history
* fix: fallback to default margin when margin is partially set

* feat: can disable axis title

* feat: adjust margin according to axis title visibility

* feat: include margin in formData

* feat: add buildQuery

* fix: address kyle comments

* fix: remove string false
  • Loading branch information
kristw committed Apr 18, 2019
1 parent eb9ffb5 commit 9c9dd9d
Show file tree
Hide file tree
Showing 12 changed files with 96 additions and 65 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
],
"license": "Apache-2.0",
"devDependencies": {
"@superset-ui/build-config": "^0.0.8",
"@superset-ui/build-config": "^0.0.9",
"@superset-ui/commit-config": "^0.0.9",
"@superset-ui/chart": "^0.11.3",
"@superset-ui/color": "^0.11.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/superset-ui-plugins-demo/.storybook/addons.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// note that the import order here determines the order in the UI!
import '@storybook/addon-knobs/register';
import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';
import '@storybook/addon-knobs/register';
import 'storybook-addon-jsx/register';
12 changes: 6 additions & 6 deletions packages/superset-ui-plugins-demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@
"dependencies": {
"@babel/polyfill": "^7.4.3",
"@data-ui/event-flow": "^0.0.54",
"@storybook/addon-actions": "^5.0.6",
"@storybook/addon-knobs": "^5.0.6",
"@storybook/addon-links": "^5.0.6",
"@storybook/addons": "^5.0.6",
"@storybook/react": "^5.0.6",
"@storybook/addon-actions": "^5.0.9",
"@storybook/addon-knobs": "^5.0.9",
"@storybook/addon-links": "^5.0.9",
"@storybook/addons": "^5.0.9",
"@storybook/react": "^5.0.9",
"@types/react": "^16.8.8",
"@types/storybook__addon-knobs": "^4.0.4",
"@types/storybook__addon-knobs": "^4.0.5",
"bootstrap": "^4.3.1",
"react": "^16.6.0",
"storybook-addon-jsx": "^7.1.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@ export default [
type: 'time',
},
axis: {
orient: radios('x.axis.orient', ['top', 'bottom'], 'bottom'),
title: 'Time',
orient: radios('x.axis.orient', { top: 'top', bottom: 'bottom' }, 'bottom'),
title: radios(
'x.axis.title',
{ enable: 'Time', disable: '', '': undefined },
'Time',
),
},
},
y: {
Expand All @@ -35,8 +39,16 @@ export default [
type: 'linear',
},
axis: {
orient: radios('y.axis.orient', ['left', 'right'], 'left'),
title: 'Score',
orient: radios(
'y.axis.orient',
{ left: 'left', right: 'right', '': undefined },
'left',
),
title: radios(
'y.axis.title',
{ enable: 'Score', disable: '', '': undefined },
'Score',
),
},
},
color: {
Expand Down
10 changes: 10 additions & 0 deletions packages/superset-ui-preset-chart-xy/src/Line/ChartFormData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ChartFormData } from '@superset-ui/chart';
import { Margin } from '@superset-ui/dimension';
import { Encoding } from './Encoder';

type LineFormData = ChartFormData & {
encoding: Encoding;
margin?: Margin;
};

export default LineFormData;
6 changes: 4 additions & 2 deletions packages/superset-ui-preset-chart-xy/src/Line/Line.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ import ChartLegend from '../components/ChartLegend';

chartTheme.gridStyles.stroke = '#f1f3f5';

const DEFAULT_MARGIN = { top: 20, right: 20, left: 20, bottom: 20 };

const defaultProps = {
className: '',
margin: { top: 20, right: 20, left: 20, bottom: 20 },
margin: DEFAULT_MARGIN,
theme: chartTheme,
};

Expand Down Expand Up @@ -153,7 +155,7 @@ class LineChart extends PureComponent<Props> {
const layout = new XYChartLayout({
width,
height,
margin,
margin: { ...DEFAULT_MARGIN, ...margin },
theme,
xEncoder: this.encoder.channels.x,
yEncoder: this.encoder.channels.y,
Expand Down
6 changes: 6 additions & 0 deletions packages/superset-ui-preset-chart-xy/src/Line/buildQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { buildQueryContext } from '@superset-ui/chart';
import ChartFormData from './ChartFormData';

export default function buildQuery(formData: ChartFormData) {
return buildQueryContext(formData);
}
5 changes: 4 additions & 1 deletion packages/superset-ui-preset-chart-xy/src/Line/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { ChartPlugin } from '@superset-ui/chart';
import metadata from './metadata';
import transformProps from './transformProps';
import buildQuery from './buildQuery';
import ChartFormData from './ChartFormData';

export default class LineChartPlugin extends ChartPlugin {
export default class LineChartPlugin extends ChartPlugin<ChartFormData> {
constructor() {
super({
buildQuery,
loadChart: () => import('./Line'),
metadata,
transformProps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { ChartProps } from '@superset-ui/chart';

export default function transformProps(chartProps: ChartProps) {
const { width, height, formData, payload } = chartProps;
const { encoding } = formData;
const { encoding, margin } = formData;
const { data } = payload;

return {
data,
width,
height,
encoding,
margin,
};
}
91 changes: 44 additions & 47 deletions packages/superset-ui-preset-chart-xy/src/encodeable/AxisAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,20 @@ export default class AxisAgent<Def extends ChannelDef<Output>, Output extends Va
return this.format || this.channelEncoder.formatValue;
}

hasTitle() {
return this.getTitle() !== '';
}

getTitle() {
return this.config.title || this.channelEncoder.getTitle();
const { title } = this.config;

if (title === undefined || title === true) {
return this.channelEncoder.getTitle();
} else if (title === false || title === '') {
return '';
}

return title;
}

getTickLabels() {
Expand All @@ -79,16 +91,17 @@ export default class AxisAgent<Def extends ChannelDef<Output>, Output extends Va
return [];
}

// eslint-disable-next-line complexity
computeLayout({
axisLabelHeight = 20,
axisTitleHeight = 20,
axisWidth,
gapBetweenAxisLabelAndBorder = 8,
gapBetweenTickAndTickLabel = 4,
labelAngle = this.config.labelAngle,
tickLength,
tickTextStyle,
}: {
axisLabelHeight?: number;
axisTitleHeight?: number;
axisWidth: number;
gapBetweenAxisLabelAndBorder?: number;
gapBetweenTickAndTickLabel?: number;
Expand All @@ -110,68 +123,52 @@ export default class AxisAgent<Def extends ChannelDef<Output>, Output extends Va
const maxWidth = Math.max(...labelDimensions.map(d => d.width));

// TODO: Add other strategies: stagger, chop, wrap.
let strategy = labelOverlap;
if (strategy === 'auto') {
let strategyForLabelOverlap = labelOverlap;
if (strategyForLabelOverlap === 'auto') {
// cheap heuristic, can improve
const widthPerTick = axisWidth / tickLabels.length;
if (this.channelEncoder.isY() || maxWidth <= widthPerTick) {
strategy = 'flat';
strategyForLabelOverlap = 'flat';
} else {
strategy = 'rotate';
strategyForLabelOverlap = 'rotate';
}
}

const spaceForAxisTitle = this.hasTitle() ? labelPadding + axisTitleHeight : 0;
let tickTextAnchor;
let labelOffset: number = 0;
let requiredMargin =
tickLength + gapBetweenTickAndTickLabel + spaceForAxisTitle + gapBetweenAxisLabelAndBorder;

if (this.channelEncoder.isX()) {
let labelOffset = 0;
let layout: {
labelAngle: number;
tickTextAnchor?: string;
} = { labelAngle };

if (strategy === 'flat') {
labelOffset = labelDimensions[0].height + labelPadding;
layout = { labelAngle: 0 };
} else if (strategy === 'rotate') {
if (strategyForLabelOverlap === 'flat') {
const labelHeight = labelDimensions[0].height;
labelOffset = labelHeight + labelPadding;
requiredMargin += labelHeight;
} else if (strategyForLabelOverlap === 'rotate') {
const labelHeight = Math.ceil(Math.abs(maxWidth * Math.sin((labelAngle * Math.PI) / 180)));
labelOffset = labelHeight + labelPadding;
layout = {
labelAngle,
tickTextAnchor:
(orient === 'top' && labelAngle > 0) || (orient === 'bottom' && labelAngle < 0)
? 'end'
: 'start',
};
requiredMargin += labelHeight;
tickTextAnchor =
(orient === 'top' && labelAngle > 0) || (orient === 'bottom' && labelAngle < 0)
? 'end'
: 'start';
}

return {
...layout,
labelOffset,
labelOverlap: strategy,
minMargin: {
[orient]: Math.ceil(
tickLength +
gapBetweenTickAndTickLabel +
labelOffset +
axisLabelHeight +
gapBetweenAxisLabelAndBorder +
8,
),
},
orient,
};
requiredMargin += 8;
} else {
labelOffset = maxWidth + spaceForAxisTitle;
requiredMargin += maxWidth;
}

const labelOffset = Math.ceil(maxWidth + labelPadding + axisLabelHeight);

return {
labelAngle,
labelAngle: strategyForLabelOverlap === 'flat' ? 0 : labelAngle,
labelOffset,
labelOverlap,
labelOverlap: strategyForLabelOverlap,
minMargin: {
[orient]:
tickLength + gapBetweenTickAndTickLabel + labelOffset + gapBetweenAxisLabelAndBorder,
[orient]: Math.ceil(requiredMargin),
},
orient,
tickTextAnchor,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export default class ChannelEncoder<Def extends ChannelDef<Output>, Output exten
return this.definition.title || this.definition.field;
}

return undefined;
return '';
}

hasLegend() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface CoreAxis {
labelPadding: number;
orient: AxisOrient;
tickCount: number;
title?: string;
title?: string | boolean;
/** Explicitly set the visible axis tick values. */
values?: string[] | number[] | boolean[] | DateTime[];
}
Expand Down

0 comments on commit 9c9dd9d

Please sign in to comment.