feat(plugin-chart-echarts): support horizontal bar chart (#19918)

* feat(plugin-chart-echarts): support horizontal bar chart

* Update superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx

Co-authored-by: Evan Rusackas <evan@preset.io>

* Update superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts

Co-authored-by: Ville Brofeldt <33317356+villebro@users.noreply.github.com>

* Update superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts

Co-authored-by: Ville Brofeldt <33317356+villebro@users.noreply.github.com>

* Update superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx

Co-authored-by: Ville Brofeldt <33317356+villebro@users.noreply.github.com>

* improve controlpanel

* default value

* fix ut

Co-authored-by: Evan Rusackas <evan@preset.io>
Co-authored-by: Ville Brofeldt <33317356+villebro@users.noreply.github.com>
This commit is contained in:
Stephen Liu
2022-05-16 21:48:36 +08:00
committed by GitHub
parent d5802f7896
commit 9854d2d0e8
7 changed files with 322 additions and 138 deletions

View File

@@ -21,8 +21,11 @@ import { FeatureFlag, isFeatureEnabled, t } from '@superset-ui/core';
import {
ControlPanelConfig,
ControlPanelsContainerProps,
ControlSetRow,
ControlStateMapping,
D3_TIME_FORMAT_DOCS,
emitFilterControl,
formatSelectOptions,
sections,
sharedControls,
} from '@superset-ui/chart-controls';
@@ -30,6 +33,7 @@ import {
import {
DEFAULT_FORM_DATA,
EchartsTimeseriesContributionType,
OrientationType,
} from '../../types';
import {
legendSection,
@@ -49,7 +53,217 @@ const {
yAxisBounds,
zoomable,
xAxisLabelRotation,
orientation,
} = DEFAULT_FORM_DATA;
function createAxisTitleControl(axis: 'x' | 'y'): ControlSetRow[] {
const isXAxis = axis === 'x';
const isVertical = (controls: ControlStateMapping) =>
Boolean(controls?.orientation.value === OrientationType.vertical);
const isHorizental = (controls: ControlStateMapping) =>
Boolean(controls?.orientation.value === OrientationType.horizontal);
return [
[
{
name: 'x_axis_title',
config: {
type: 'TextControl',
label: t('Axis Title'),
renderTrigger: true,
default: '',
description: t('Changing this control takes effect instantly'),
visibility: ({ controls }: ControlPanelsContainerProps) =>
isXAxis ? isVertical(controls) : isHorizental(controls),
},
},
],
[
{
name: 'x_axis_title_margin',
config: {
type: 'SelectControl',
freeForm: true,
clearable: true,
label: t('AXIS TITLE MARGIN'),
renderTrigger: true,
default: sections.TITLE_MARGIN_OPTIONS[0],
choices: formatSelectOptions(sections.TITLE_MARGIN_OPTIONS),
description: t('Changing this control takes effect instantly'),
visibility: ({ controls }: ControlPanelsContainerProps) =>
isXAxis ? isVertical(controls) : isHorizental(controls),
},
},
],
[
{
name: 'y_axis_title',
config: {
type: 'TextControl',
label: t('Axis Title'),
renderTrigger: true,
default: '',
description: t('Changing this control takes effect instantly'),
visibility: ({ controls }: ControlPanelsContainerProps) =>
isXAxis ? isHorizental(controls) : isVertical(controls),
},
},
],
[
{
name: 'y_axis_title_margin',
config: {
type: 'SelectControl',
freeForm: true,
clearable: true,
label: t('AXIS TITLE MARGIN'),
renderTrigger: true,
default: sections.TITLE_MARGIN_OPTIONS[0],
choices: formatSelectOptions(sections.TITLE_MARGIN_OPTIONS),
description: t('Changing this control takes effect instantly'),
visibility: ({ controls }: ControlPanelsContainerProps) =>
isXAxis ? isHorizental(controls) : isVertical(controls),
},
},
],
[
{
name: 'y_axis_title_position',
config: {
type: 'SelectControl',
freeForm: true,
clearable: false,
label: t('AXIS TITLE POSITION'),
renderTrigger: true,
default: sections.TITLE_POSITION_OPTIONS[0],
choices: formatSelectOptions(sections.TITLE_POSITION_OPTIONS),
description: t('Changing this control takes effect instantly'),
visibility: ({ controls }: ControlPanelsContainerProps) =>
isXAxis ? isHorizental(controls) : isVertical(controls),
},
},
],
];
}
function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] {
const isXAxis = axis === 'x';
const isVertical = (controls: ControlStateMapping) =>
Boolean(controls?.orientation.value === OrientationType.vertical);
const isHorizental = (controls: ControlStateMapping) =>
Boolean(controls?.orientation.value === OrientationType.horizontal);
return [
[
{
name: 'x_axis_time_format',
config: {
...sharedControls.x_axis_time_format,
default: 'smart_date',
description: `${D3_TIME_FORMAT_DOCS}. ${t(
'When using other than adaptive formatting, labels may overlap.',
)}`,
visibility: ({ controls }: ControlPanelsContainerProps) =>
isXAxis ? isVertical(controls) : isHorizental(controls),
},
},
],
[
{
name: 'xAxisLabelRotation',
config: {
type: 'SelectControl',
freeForm: true,
clearable: false,
label: t('Rotate axis label'),
choices: [
[0, '0°'],
[45, '45°'],
],
default: xAxisLabelRotation,
renderTrigger: true,
description: t(
'Input field supports custom rotation. e.g. 30 for 30°',
),
visibility: ({ controls }: ControlPanelsContainerProps) =>
isXAxis ? isVertical(controls) : isHorizental(controls),
},
},
],
[
{
name: 'y_axis_format',
config: {
...sharedControls.y_axis_format,
label: t('Axis Format'),
visibility: ({ controls }: ControlPanelsContainerProps) =>
isXAxis ? isHorizental(controls) : isVertical(controls),
},
},
],
[
{
name: 'logAxis',
config: {
type: 'CheckboxControl',
label: t('Logarithmic axis'),
renderTrigger: true,
default: logAxis,
description: t('Logarithmic axis'),
visibility: ({ controls }: ControlPanelsContainerProps) =>
isXAxis ? isHorizental(controls) : isVertical(controls),
},
},
],
[
{
name: 'minorSplitLine',
config: {
type: 'CheckboxControl',
label: t('Minor Split Line'),
renderTrigger: true,
default: minorSplitLine,
description: t('Draw split lines for minor axis ticks'),
visibility: ({ controls }: ControlPanelsContainerProps) =>
isXAxis ? isHorizental(controls) : isVertical(controls),
},
},
],
[
{
name: 'truncateYAxis',
config: {
type: 'CheckboxControl',
label: t('Truncate Axis'),
default: truncateYAxis,
renderTrigger: true,
description: t('Its not recommended to truncate axis in Bar chart.'),
visibility: ({ controls }: ControlPanelsContainerProps) =>
isXAxis ? isHorizental(controls) : isVertical(controls),
},
},
],
[
{
name: 'y_axis_bounds',
config: {
type: 'BoundsControl',
label: t('Axis Bounds'),
renderTrigger: true,
default: yAxisBounds,
description: t(
'Bounds for the axis. When left empty, the bounds are ' +
'dynamically defined based on the min/max of the data. Note that ' +
"this feature will only expand the axis range. It won't " +
"narrow the data's extent.",
),
visibility: ({ controls }: ControlPanelsContainerProps) =>
Boolean(controls?.truncateYAxis?.value) &&
(isXAxis ? isHorizental(controls) : isVertical(controls)),
},
},
],
];
}
const config: ControlPanelConfig = {
controlPanelSections: [
sections.legacyTimeseriesTime,
@@ -87,7 +301,39 @@ const config: ControlPanelConfig = {
sections.advancedAnalyticsControls,
sections.annotationsAndLayersControls,
sections.forecastIntervalControls,
sections.titleControls,
{
label: t('Chart Orientation'),
expanded: true,
controlSetRows: [
[
{
name: 'orientation',
config: {
type: 'RadioButtonControl',
renderTrigger: true,
label: t('Bar orientation'),
default: orientation,
options: [
[OrientationType.vertical, t('Vertical')],
[OrientationType.horizontal, t('Horizontal')],
],
description: t('Orientation of bar chart'),
},
},
],
],
},
{
label: t('Chart Title'),
tabOverride: 'customize',
expanded: true,
controlSetRows: [
[<div className="section-header">{t('X Axis')}</div>],
...createAxisTitleControl('x'),
[<div className="section-header">{t('Y Axis')}</div>],
...createAxisTitleControl('y'),
],
},
{
label: t('Chart Options'),
expanded: true,
@@ -140,101 +386,10 @@ const config: ControlPanelConfig = {
],
...legendSection,
[<div className="section-header">{t('X Axis')}</div>],
[
{
name: 'x_axis_time_format',
config: {
...sharedControls.x_axis_time_format,
default: 'smart_date',
description: `${D3_TIME_FORMAT_DOCS}. ${t(
'When using other than adaptive formatting, labels may overlap.',
)}`,
},
},
],
[
{
name: 'xAxisLabelRotation',
config: {
type: 'SelectControl',
freeForm: true,
clearable: false,
label: t('Rotate x axis label'),
choices: [
[0, '0°'],
[45, '45°'],
],
default: xAxisLabelRotation,
renderTrigger: true,
description: t(
'Input field supports custom rotation. e.g. 30 for 30°',
),
},
},
],
// eslint-disable-next-line react/jsx-key
...createAxisControl('x'),
...richTooltipSection,
// eslint-disable-next-line react/jsx-key
[<div className="section-header">{t('Y Axis')}</div>],
['y_axis_format'],
[
{
name: 'logAxis',
config: {
type: 'CheckboxControl',
label: t('Logarithmic y-axis'),
renderTrigger: true,
default: logAxis,
description: t('Logarithmic y-axis'),
},
},
],
[
{
name: 'minorSplitLine',
config: {
type: 'CheckboxControl',
label: t('Minor Split Line'),
renderTrigger: true,
default: minorSplitLine,
description: t('Draw split lines for minor y-axis ticks'),
},
},
],
[
{
name: 'truncateYAxis',
config: {
type: 'CheckboxControl',
label: t('Truncate Y Axis'),
default: truncateYAxis,
renderTrigger: true,
description: t(
'Its not recommended to truncate y-axis in Bar chart.',
),
},
},
],
[
{
name: 'y_axis_bounds',
config: {
type: 'BoundsControl',
label: t('Y Axis Bounds'),
renderTrigger: true,
default: yAxisBounds,
description: t(
'Bounds for the Y-axis. When left empty, the bounds are ' +
'dynamically defined based on the min/max of the data. Note that ' +
"this feature will only expand the axis range. It won't " +
"narrow the data's extent.",
),
visibility: ({ controls }: ControlPanelsContainerProps) =>
Boolean(controls?.truncateYAxis?.value),
},
},
],
...createAxisControl('y'),
],
},
],