mirror of
https://github.com/apache/superset.git
synced 2024-09-18 19:49:37 -04:00
feat(plugin-chart-echarts): add series sorting (#23392)
This commit is contained in:
parent
da3791ad3d
commit
0c454c6442
@ -34,6 +34,7 @@ import {
|
|||||||
onlyTotalControl,
|
onlyTotalControl,
|
||||||
showValueControl,
|
showValueControl,
|
||||||
richTooltipSection,
|
richTooltipSection,
|
||||||
|
seriesOrderSection,
|
||||||
} from '../../controls';
|
} from '../../controls';
|
||||||
import { AreaChartExtraControlsOptions } from '../../constants';
|
import { AreaChartExtraControlsOptions } from '../../constants';
|
||||||
|
|
||||||
@ -62,6 +63,7 @@ const config: ControlPanelConfig = {
|
|||||||
label: t('Chart Options'),
|
label: t('Chart Options'),
|
||||||
expanded: true,
|
expanded: true,
|
||||||
controlSetRows: [
|
controlSetRows: [
|
||||||
|
...seriesOrderSection,
|
||||||
['color_scheme'],
|
['color_scheme'],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
@ -38,6 +38,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
legendSection,
|
legendSection,
|
||||||
richTooltipSection,
|
richTooltipSection,
|
||||||
|
seriesOrderSection,
|
||||||
showValueSection,
|
showValueSection,
|
||||||
} from '../../../controls';
|
} from '../../../controls';
|
||||||
|
|
||||||
@ -301,6 +302,7 @@ const config: ControlPanelConfig = {
|
|||||||
label: t('Chart Options'),
|
label: t('Chart Options'),
|
||||||
expanded: true,
|
expanded: true,
|
||||||
controlSetRows: [
|
controlSetRows: [
|
||||||
|
...seriesOrderSection,
|
||||||
['color_scheme'],
|
['color_scheme'],
|
||||||
...showValueSection,
|
...showValueSection,
|
||||||
[
|
[
|
||||||
|
@ -35,6 +35,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
legendSection,
|
legendSection,
|
||||||
richTooltipSection,
|
richTooltipSection,
|
||||||
|
seriesOrderSection,
|
||||||
showValueSection,
|
showValueSection,
|
||||||
} from '../../../controls';
|
} from '../../../controls';
|
||||||
|
|
||||||
@ -64,6 +65,7 @@ const config: ControlPanelConfig = {
|
|||||||
label: t('Chart Options'),
|
label: t('Chart Options'),
|
||||||
expanded: true,
|
expanded: true,
|
||||||
controlSetRows: [
|
controlSetRows: [
|
||||||
|
...seriesOrderSection,
|
||||||
['color_scheme'],
|
['color_scheme'],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
@ -34,6 +34,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
legendSection,
|
legendSection,
|
||||||
richTooltipSection,
|
richTooltipSection,
|
||||||
|
seriesOrderSection,
|
||||||
showValueSection,
|
showValueSection,
|
||||||
} from '../../../controls';
|
} from '../../../controls';
|
||||||
|
|
||||||
@ -60,6 +61,7 @@ const config: ControlPanelConfig = {
|
|||||||
label: t('Chart Options'),
|
label: t('Chart Options'),
|
||||||
expanded: true,
|
expanded: true,
|
||||||
controlSetRows: [
|
controlSetRows: [
|
||||||
|
...seriesOrderSection,
|
||||||
['color_scheme'],
|
['color_scheme'],
|
||||||
...showValueSection,
|
...showValueSection,
|
||||||
[
|
[
|
||||||
|
@ -34,6 +34,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
legendSection,
|
legendSection,
|
||||||
richTooltipSection,
|
richTooltipSection,
|
||||||
|
seriesOrderSection,
|
||||||
showValueSectionWithoutStack,
|
showValueSectionWithoutStack,
|
||||||
} from '../../../controls';
|
} from '../../../controls';
|
||||||
|
|
||||||
@ -60,6 +61,7 @@ const config: ControlPanelConfig = {
|
|||||||
label: t('Chart Options'),
|
label: t('Chart Options'),
|
||||||
expanded: true,
|
expanded: true,
|
||||||
controlSetRows: [
|
controlSetRows: [
|
||||||
|
...seriesOrderSection,
|
||||||
['color_scheme'],
|
['color_scheme'],
|
||||||
...showValueSectionWithoutStack,
|
...showValueSectionWithoutStack,
|
||||||
[
|
[
|
||||||
|
@ -32,6 +32,7 @@ import { DEFAULT_FORM_DATA, TIME_SERIES_DESCRIPTION_TEXT } from '../constants';
|
|||||||
import {
|
import {
|
||||||
legendSection,
|
legendSection,
|
||||||
richTooltipSection,
|
richTooltipSection,
|
||||||
|
seriesOrderSection,
|
||||||
showValueSection,
|
showValueSection,
|
||||||
} from '../../controls';
|
} from '../../controls';
|
||||||
|
|
||||||
@ -60,6 +61,7 @@ const config: ControlPanelConfig = {
|
|||||||
label: t('Chart Options'),
|
label: t('Chart Options'),
|
||||||
expanded: true,
|
expanded: true,
|
||||||
controlSetRows: [
|
controlSetRows: [
|
||||||
|
...seriesOrderSection,
|
||||||
['color_scheme'],
|
['color_scheme'],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
@ -25,6 +25,7 @@ import {
|
|||||||
} from './types';
|
} from './types';
|
||||||
import {
|
import {
|
||||||
DEFAULT_LEGEND_FORM_DATA,
|
DEFAULT_LEGEND_FORM_DATA,
|
||||||
|
DEFAULT_SORT_SERIES_DATA,
|
||||||
DEFAULT_TITLE_FORM_DATA,
|
DEFAULT_TITLE_FORM_DATA,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
|
|
||||||
@ -32,6 +33,7 @@ import {
|
|||||||
export const DEFAULT_FORM_DATA: EchartsTimeseriesFormData = {
|
export const DEFAULT_FORM_DATA: EchartsTimeseriesFormData = {
|
||||||
...DEFAULT_LEGEND_FORM_DATA,
|
...DEFAULT_LEGEND_FORM_DATA,
|
||||||
...DEFAULT_TITLE_FORM_DATA,
|
...DEFAULT_TITLE_FORM_DATA,
|
||||||
|
...DEFAULT_SORT_SERIES_DATA,
|
||||||
annotationLayers: sections.annotationLayers,
|
annotationLayers: sections.annotationLayers,
|
||||||
area: false,
|
area: false,
|
||||||
forecastEnabled: sections.FORECAST_DEFAULT_DATA.forecastEnabled,
|
forecastEnabled: sections.FORECAST_DEFAULT_DATA.forecastEnabled,
|
||||||
@ -63,6 +65,8 @@ export const DEFAULT_FORM_DATA: EchartsTimeseriesFormData = {
|
|||||||
onlyTotal: false,
|
onlyTotal: false,
|
||||||
percentageThreshold: 0,
|
percentageThreshold: 0,
|
||||||
orientation: OrientationType.vertical,
|
orientation: OrientationType.vertical,
|
||||||
|
sort_series_type: 'sum',
|
||||||
|
sort_series_ascending: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TIME_SERIES_DESCRIPTION_TEXT: string = t(
|
export const TIME_SERIES_DESCRIPTION_TEXT: string = t(
|
||||||
|
@ -136,6 +136,8 @@ export default function transformProps(
|
|||||||
showLegend,
|
showLegend,
|
||||||
showValue,
|
showValue,
|
||||||
sliceId,
|
sliceId,
|
||||||
|
sortSeriesType,
|
||||||
|
sortSeriesAscending,
|
||||||
timeGrainSqla,
|
timeGrainSqla,
|
||||||
timeCompare,
|
timeCompare,
|
||||||
stack,
|
stack,
|
||||||
@ -197,6 +199,8 @@ export default function transformProps(
|
|||||||
stack,
|
stack,
|
||||||
totalStackedValues,
|
totalStackedValues,
|
||||||
isHorizontal,
|
isHorizontal,
|
||||||
|
sortSeriesType,
|
||||||
|
sortSeriesAscending,
|
||||||
});
|
});
|
||||||
const showValueIndexes = extractShowValueIndexes(rawSeries, {
|
const showValueIndexes = extractShowValueIndexes(rawSeries, {
|
||||||
stack,
|
stack,
|
||||||
@ -418,7 +422,7 @@ export default function transformProps(
|
|||||||
forecastValue.sort((a, b) => b.data[yIndex] - a.data[yIndex]);
|
forecastValue.sort((a, b) => b.data[yIndex] - a.data[yIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const rows: Array<string> = [`${tooltipFormatter(xValue)}`];
|
const rows: string[] = [];
|
||||||
const forecastValues: Record<string, ForecastValue> =
|
const forecastValues: Record<string, ForecastValue> =
|
||||||
extractForecastValuesFromTooltipParams(forecastValue, isHorizontal);
|
extractForecastValuesFromTooltipParams(forecastValue, isHorizontal);
|
||||||
|
|
||||||
@ -435,6 +439,10 @@ export default function transformProps(
|
|||||||
rows.push(`<span style="opacity: 0.7">${content}</span>`);
|
rows.push(`<span style="opacity: 0.7">${content}</span>`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (stack) {
|
||||||
|
rows.reverse();
|
||||||
|
}
|
||||||
|
rows.unshift(`${tooltipFormatter(xValue)}`);
|
||||||
return rows.join('<br />');
|
return rows.join('<br />');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -20,11 +20,13 @@
|
|||||||
import { JsonValue, t, TimeGranularity } from '@superset-ui/core';
|
import { JsonValue, t, TimeGranularity } from '@superset-ui/core';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import {
|
import {
|
||||||
LegendFormData,
|
|
||||||
TitleFormData,
|
|
||||||
LabelPositionEnum,
|
LabelPositionEnum,
|
||||||
|
LegendFormData,
|
||||||
LegendOrientation,
|
LegendOrientation,
|
||||||
LegendType,
|
LegendType,
|
||||||
|
SortSeriesData,
|
||||||
|
SortSeriesType,
|
||||||
|
TitleFormData,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
// eslint-disable-next-line import/prefer-default-export
|
// eslint-disable-next-line import/prefer-default-export
|
||||||
@ -114,3 +116,8 @@ export const TOOLTIP_POINTER_MARGIN = 10;
|
|||||||
// If no satisfactory position can be found, how far away
|
// If no satisfactory position can be found, how far away
|
||||||
// from the edge of the window should the tooltip be kept
|
// from the edge of the window should the tooltip be kept
|
||||||
export const TOOLTIP_OVERFLOW_MARGIN = 5;
|
export const TOOLTIP_OVERFLOW_MARGIN = 5;
|
||||||
|
|
||||||
|
export const DEFAULT_SORT_SERIES_DATA: SortSeriesData = {
|
||||||
|
sort_series_type: SortSeriesType.Sum,
|
||||||
|
sort_series_ascending: false,
|
||||||
|
};
|
||||||
|
@ -24,8 +24,12 @@ import {
|
|||||||
ControlSetRow,
|
ControlSetRow,
|
||||||
sharedControls,
|
sharedControls,
|
||||||
} from '@superset-ui/chart-controls';
|
} from '@superset-ui/chart-controls';
|
||||||
import { DEFAULT_LEGEND_FORM_DATA } from './constants';
|
import {
|
||||||
|
DEFAULT_LEGEND_FORM_DATA,
|
||||||
|
DEFAULT_SORT_SERIES_DATA,
|
||||||
|
} from './constants';
|
||||||
import { DEFAULT_FORM_DATA } from './Timeseries/constants';
|
import { DEFAULT_FORM_DATA } from './Timeseries/constants';
|
||||||
|
import { SortSeriesType } from './types';
|
||||||
|
|
||||||
const { legendMargin, legendOrientation, legendType, showLegend } =
|
const { legendMargin, legendOrientation, legendType, showLegend } =
|
||||||
DEFAULT_LEGEND_FORM_DATA;
|
DEFAULT_LEGEND_FORM_DATA;
|
||||||
@ -212,3 +216,41 @@ export const richTooltipSection: ControlSetRow[] = [
|
|||||||
[tooltipSortByMetricControl],
|
[tooltipSortByMetricControl],
|
||||||
[tooltipTimeFormatControl],
|
[tooltipTimeFormatControl],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const sortSeriesType: ControlSetItem = {
|
||||||
|
name: 'sort_series_type',
|
||||||
|
config: {
|
||||||
|
type: 'SelectControl',
|
||||||
|
freeForm: false,
|
||||||
|
label: t('Sort Series By'),
|
||||||
|
choices: [
|
||||||
|
[SortSeriesType.Name, t('Category name')],
|
||||||
|
[SortSeriesType.Sum, t('Total value')],
|
||||||
|
[SortSeriesType.Min, t('Minimum value')],
|
||||||
|
[SortSeriesType.Max, t('Maximum value')],
|
||||||
|
[SortSeriesType.Avg, t('Average value')],
|
||||||
|
],
|
||||||
|
default: DEFAULT_SORT_SERIES_DATA.sort_series_type,
|
||||||
|
renderTrigger: true,
|
||||||
|
description: t(
|
||||||
|
'Based on what should series be ordered on the chart and legend',
|
||||||
|
),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const sortSeriesAscending: ControlSetItem = {
|
||||||
|
name: 'sort_series_ascending',
|
||||||
|
config: {
|
||||||
|
type: 'CheckboxControl',
|
||||||
|
label: t('Sort Series Ascending'),
|
||||||
|
default: DEFAULT_SORT_SERIES_DATA.sort_series_ascending,
|
||||||
|
renderTrigger: true,
|
||||||
|
description: t('Sort series in ascending order'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const seriesOrderSection: ControlSetRow[] = [
|
||||||
|
[<div className="section-header">{t('Series Order')}</div>],
|
||||||
|
[sortSeriesType],
|
||||||
|
[sortSeriesAscending],
|
||||||
|
];
|
||||||
|
@ -167,4 +167,17 @@ export interface TreePathInfo {
|
|||||||
value: number | number[];
|
value: number | number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum SortSeriesType {
|
||||||
|
Name = 'name',
|
||||||
|
Max = 'max',
|
||||||
|
Min = 'min',
|
||||||
|
Sum = 'sum',
|
||||||
|
Avg = 'avg',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SortSeriesData = {
|
||||||
|
sort_series_type: SortSeriesType;
|
||||||
|
sort_series_ascending: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export * from './Timeseries/types';
|
export * from './Timeseries/types';
|
||||||
|
@ -30,12 +30,18 @@ import {
|
|||||||
AxisType,
|
AxisType,
|
||||||
} from '@superset-ui/core';
|
} from '@superset-ui/core';
|
||||||
import { format, LegendComponentOption, SeriesOption } from 'echarts';
|
import { format, LegendComponentOption, SeriesOption } from 'echarts';
|
||||||
|
import { sumBy, meanBy, minBy, maxBy, orderBy } from 'lodash';
|
||||||
import {
|
import {
|
||||||
AreaChartExtraControlsValue,
|
AreaChartExtraControlsValue,
|
||||||
NULL_STRING,
|
NULL_STRING,
|
||||||
TIMESERIES_CONSTANTS,
|
TIMESERIES_CONSTANTS,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
import { LegendOrientation, LegendType, StackType } from '../types';
|
import {
|
||||||
|
LegendOrientation,
|
||||||
|
LegendType,
|
||||||
|
SortSeriesType,
|
||||||
|
StackType,
|
||||||
|
} from '../types';
|
||||||
import { defaultLegendPadding } from '../defaults';
|
import { defaultLegendPadding } from '../defaults';
|
||||||
|
|
||||||
function isDefined<T>(value: T | undefined | null): boolean {
|
function isDefined<T>(value: T | undefined | null): boolean {
|
||||||
@ -108,6 +114,46 @@ export function extractShowValueIndexes(
|
|||||||
return showValueIndexes;
|
return showValueIndexes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function sortAndFilterSeries(
|
||||||
|
rows: DataRecord[],
|
||||||
|
xAxis: string,
|
||||||
|
extraMetricLabels: any[],
|
||||||
|
sortSeriesType?: SortSeriesType,
|
||||||
|
sortSeriesAscending?: boolean,
|
||||||
|
): string[] {
|
||||||
|
const seriesNames = Object.keys(rows[0])
|
||||||
|
.filter(key => key !== xAxis)
|
||||||
|
.filter(key => !extraMetricLabels.includes(key));
|
||||||
|
|
||||||
|
let aggregator: (name: string) => { name: string; value: any };
|
||||||
|
|
||||||
|
switch (sortSeriesType) {
|
||||||
|
case SortSeriesType.Sum:
|
||||||
|
aggregator = name => ({ name, value: sumBy(rows, name) });
|
||||||
|
break;
|
||||||
|
case SortSeriesType.Min:
|
||||||
|
aggregator = name => ({ name, value: minBy(rows, name)?.[name] });
|
||||||
|
break;
|
||||||
|
case SortSeriesType.Max:
|
||||||
|
aggregator = name => ({ name, value: maxBy(rows, name)?.[name] });
|
||||||
|
break;
|
||||||
|
case SortSeriesType.Avg:
|
||||||
|
aggregator = name => ({ name, value: meanBy(rows, name) });
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
aggregator = name => ({ name, value: name.toLowerCase() });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortedValues = seriesNames.map(aggregator);
|
||||||
|
|
||||||
|
return orderBy(
|
||||||
|
sortedValues,
|
||||||
|
['value'],
|
||||||
|
[sortSeriesAscending ? 'asc' : 'desc'],
|
||||||
|
).map(({ name }) => name);
|
||||||
|
}
|
||||||
|
|
||||||
export function extractSeries(
|
export function extractSeries(
|
||||||
data: DataRecord[],
|
data: DataRecord[],
|
||||||
opts: {
|
opts: {
|
||||||
@ -118,6 +164,8 @@ export function extractSeries(
|
|||||||
stack?: StackType;
|
stack?: StackType;
|
||||||
totalStackedValues?: number[];
|
totalStackedValues?: number[];
|
||||||
isHorizontal?: boolean;
|
isHorizontal?: boolean;
|
||||||
|
sortSeriesType?: SortSeriesType;
|
||||||
|
sortSeriesAscending?: boolean;
|
||||||
} = {},
|
} = {},
|
||||||
): SeriesOption[] {
|
): SeriesOption[] {
|
||||||
const {
|
const {
|
||||||
@ -128,41 +176,47 @@ export function extractSeries(
|
|||||||
stack = false,
|
stack = false,
|
||||||
totalStackedValues = [],
|
totalStackedValues = [],
|
||||||
isHorizontal = false,
|
isHorizontal = false,
|
||||||
|
sortSeriesType,
|
||||||
|
sortSeriesAscending,
|
||||||
} = opts;
|
} = opts;
|
||||||
if (data.length === 0) return [];
|
if (data.length === 0) return [];
|
||||||
const rows: DataRecord[] = data.map(datum => ({
|
const rows: DataRecord[] = data.map(datum => ({
|
||||||
...datum,
|
...datum,
|
||||||
[xAxis]: datum[xAxis],
|
[xAxis]: datum[xAxis],
|
||||||
}));
|
}));
|
||||||
|
const series = sortAndFilterSeries(
|
||||||
|
rows,
|
||||||
|
xAxis,
|
||||||
|
extraMetricLabels,
|
||||||
|
sortSeriesType,
|
||||||
|
sortSeriesAscending,
|
||||||
|
);
|
||||||
|
|
||||||
return Object.keys(rows[0])
|
return series.map(name => ({
|
||||||
.filter(key => key !== xAxis && key !== DTTM_ALIAS)
|
id: name,
|
||||||
.filter(key => !extraMetricLabels.includes(key))
|
name,
|
||||||
.map(key => ({
|
data: rows
|
||||||
id: key,
|
.map((row, idx) => {
|
||||||
name: key,
|
const isNextToDefinedValue =
|
||||||
data: rows
|
isDefined(rows[idx - 1]?.[name]) || isDefined(rows[idx + 1]?.[name]);
|
||||||
.map((row, idx) => {
|
const isFillNeighborValue =
|
||||||
const isNextToDefinedValue =
|
!isDefined(row[name]) &&
|
||||||
isDefined(rows[idx - 1]?.[key]) || isDefined(rows[idx + 1]?.[key]);
|
isNextToDefinedValue &&
|
||||||
const isFillNeighborValue =
|
fillNeighborValue !== undefined;
|
||||||
!isDefined(row[key]) &&
|
let value: DataRecordValue | undefined = row[name];
|
||||||
isNextToDefinedValue &&
|
if (isFillNeighborValue) {
|
||||||
fillNeighborValue !== undefined;
|
value = fillNeighborValue;
|
||||||
let value: DataRecordValue | undefined = row[key];
|
} else if (
|
||||||
if (isFillNeighborValue) {
|
stack === AreaChartExtraControlsValue.Expand &&
|
||||||
value = fillNeighborValue;
|
totalStackedValues.length > 0
|
||||||
} else if (
|
) {
|
||||||
stack === AreaChartExtraControlsValue.Expand &&
|
value = ((value || 0) as number) / totalStackedValues[idx];
|
||||||
totalStackedValues.length > 0
|
}
|
||||||
) {
|
return [row[xAxis], value];
|
||||||
value = ((value || 0) as number) / totalStackedValues[idx];
|
})
|
||||||
}
|
.filter(obs => !removeNulls || (obs[0] !== null && obs[1] !== null))
|
||||||
return [row[xAxis], value];
|
.map(obs => (isHorizontal ? [obs[1], obs[0]] : obs)),
|
||||||
})
|
}));
|
||||||
.filter(obs => !removeNulls || (obs[0] !== null && obs[1] !== null))
|
|
||||||
.map(obs => (isHorizontal ? [obs[1], obs[0]] : obs)),
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatSeriesName(
|
export function formatSeriesName(
|
||||||
|
@ -16,22 +16,66 @@
|
|||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import { getNumberFormatter, getTimeFormatter } from '@superset-ui/core';
|
import {
|
||||||
|
DataRecord,
|
||||||
|
getNumberFormatter,
|
||||||
|
getTimeFormatter,
|
||||||
|
} from '@superset-ui/core';
|
||||||
import {
|
import {
|
||||||
dedupSeries,
|
dedupSeries,
|
||||||
extractGroupbyLabel,
|
extractGroupbyLabel,
|
||||||
extractSeries,
|
extractSeries,
|
||||||
|
extractShowValueIndexes,
|
||||||
formatSeriesName,
|
formatSeriesName,
|
||||||
getChartPadding,
|
getChartPadding,
|
||||||
getLegendProps,
|
getLegendProps,
|
||||||
sanitizeHtml,
|
|
||||||
extractShowValueIndexes,
|
|
||||||
getOverMaxHiddenFormatter,
|
getOverMaxHiddenFormatter,
|
||||||
|
sanitizeHtml,
|
||||||
|
sortAndFilterSeries,
|
||||||
} from '../../src/utils/series';
|
} from '../../src/utils/series';
|
||||||
import { LegendOrientation, LegendType } from '../../src/types';
|
import { LegendOrientation, LegendType, SortSeriesType } from '../../src/types';
|
||||||
import { defaultLegendPadding } from '../../src/defaults';
|
import { defaultLegendPadding } from '../../src/defaults';
|
||||||
import { NULL_STRING } from '../../src/constants';
|
import { NULL_STRING } from '../../src/constants';
|
||||||
|
|
||||||
|
test('sortAndFilterSeries', () => {
|
||||||
|
const data: DataRecord[] = [
|
||||||
|
{ my_x_axis: 'abc', x: 1, y: 0, z: 2 },
|
||||||
|
{ my_x_axis: 'foo', x: null, y: 10, z: 5 },
|
||||||
|
{ my_x_axis: null, x: 4, y: 3, z: 7 },
|
||||||
|
];
|
||||||
|
|
||||||
|
expect(
|
||||||
|
sortAndFilterSeries(data, 'my_x_axis', [], SortSeriesType.Min, true),
|
||||||
|
).toEqual(['y', 'x', 'z']);
|
||||||
|
expect(
|
||||||
|
sortAndFilterSeries(data, 'my_x_axis', [], SortSeriesType.Min, false),
|
||||||
|
).toEqual(['z', 'x', 'y']);
|
||||||
|
expect(
|
||||||
|
sortAndFilterSeries(data, 'my_x_axis', [], SortSeriesType.Max, true),
|
||||||
|
).toEqual(['x', 'z', 'y']);
|
||||||
|
expect(
|
||||||
|
sortAndFilterSeries(data, 'my_x_axis', [], SortSeriesType.Max, false),
|
||||||
|
).toEqual(['y', 'z', 'x']);
|
||||||
|
expect(
|
||||||
|
sortAndFilterSeries(data, 'my_x_axis', [], SortSeriesType.Avg, true),
|
||||||
|
).toEqual(['x', 'y', 'z']);
|
||||||
|
expect(
|
||||||
|
sortAndFilterSeries(data, 'my_x_axis', [], SortSeriesType.Avg, false),
|
||||||
|
).toEqual(['z', 'y', 'x']);
|
||||||
|
expect(
|
||||||
|
sortAndFilterSeries(data, 'my_x_axis', [], SortSeriesType.Sum, true),
|
||||||
|
).toEqual(['x', 'y', 'z']);
|
||||||
|
expect(
|
||||||
|
sortAndFilterSeries(data, 'my_x_axis', [], SortSeriesType.Sum, false),
|
||||||
|
).toEqual(['z', 'y', 'x']);
|
||||||
|
expect(
|
||||||
|
sortAndFilterSeries(data, 'my_x_axis', [], SortSeriesType.Name, true),
|
||||||
|
).toEqual(['x', 'y', 'z']);
|
||||||
|
expect(
|
||||||
|
sortAndFilterSeries(data, 'my_x_axis', [], SortSeriesType.Name, false),
|
||||||
|
).toEqual(['z', 'y', 'x']);
|
||||||
|
});
|
||||||
|
|
||||||
describe('extractSeries', () => {
|
describe('extractSeries', () => {
|
||||||
it('should generate a valid ECharts timeseries series object', () => {
|
it('should generate a valid ECharts timeseries series object', () => {
|
||||||
const data = [
|
const data = [
|
||||||
|
Loading…
Reference in New Issue
Block a user