superset transformProps 源码
superset transformProps 代码
文件路径:/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import {
QueryFormMetric,
CategoricalColorNamespace,
CategoricalColorScale,
DataRecord,
getNumberFormatter,
getMetricLabel,
getColumnLabel,
} from '@superset-ui/core';
import { EChartsCoreOption, GaugeSeriesOption } from 'echarts';
import { GaugeDataItemOption } from 'echarts/types/src/chart/gauge/GaugeSeries';
import { CallbackDataParams } from 'echarts/types/src/util/types';
import range from 'lodash/range';
import { parseNumbersList } from '../utils/controls';
import {
DEFAULT_FORM_DATA as DEFAULT_GAUGE_FORM_DATA,
EchartsGaugeFormData,
AxisTickLineStyle,
GaugeChartTransformedProps,
EchartsGaugeChartProps,
} from './types';
import {
defaultGaugeSeriesOption,
INTERVAL_GAUGE_SERIES_OPTION,
OFFSETS,
FONT_SIZE_MULTIPLIERS,
} from './constants';
import { OpacityEnum } from '../constants';
const setIntervalBoundsAndColors = (
intervals: string,
intervalColorIndices: string,
colorFn: CategoricalColorScale,
normalizer: number,
): Array<[number, string]> => {
let intervalBoundsNonNormalized;
let intervalColorIndicesArray;
try {
intervalBoundsNonNormalized = parseNumbersList(intervals, ',');
intervalColorIndicesArray = parseNumbersList(intervalColorIndices, ',');
} catch (error) {
intervalBoundsNonNormalized = [] as number[];
intervalColorIndicesArray = [] as number[];
}
const intervalBounds = intervalBoundsNonNormalized.map(
bound => bound / normalizer,
);
const intervalColors = intervalColorIndicesArray.map(
ind => colorFn.colors[(ind - 1) % colorFn.colors.length],
);
return intervalBounds.map((val, idx) => {
const color = intervalColors[idx];
return [val, color || colorFn.colors[idx]];
});
};
const calculateAxisLineWidth = (
data: DataRecord[],
fontSize: number,
overlap: boolean,
): number => (overlap ? fontSize : data.length * fontSize);
const calculateMin = (data: GaugeDataItemOption[]) =>
2 * Math.min(...data.map(d => d.value as number).concat([0]));
const calculateMax = (data: GaugeDataItemOption[]) =>
2 * Math.max(...data.map(d => d.value as number).concat([0]));
export default function transformProps(
chartProps: EchartsGaugeChartProps,
): GaugeChartTransformedProps {
const { width, height, formData, queriesData, hooks, filterState, theme } =
chartProps;
const gaugeSeriesOptions = defaultGaugeSeriesOption(theme);
const {
groupby,
metric,
minVal,
maxVal,
colorScheme,
fontSize,
numberFormat,
animation,
showProgress,
overlap,
roundCap,
showAxisTick,
showSplitLine,
splitNumber,
startAngle,
endAngle,
showPointer,
intervals,
intervalColorIndices,
valueFormatter,
emitFilter,
sliceId,
}: EchartsGaugeFormData = { ...DEFAULT_GAUGE_FORM_DATA, ...formData };
const data = (queriesData[0]?.data || []) as DataRecord[];
const numberFormatter = getNumberFormatter(numberFormat);
const colorFn = CategoricalColorNamespace.getScale(colorScheme as string);
const axisLineWidth = calculateAxisLineWidth(data, fontSize, overlap);
const groupbyLabels = groupby.map(getColumnLabel);
const formatValue = (value: number) =>
valueFormatter.replace('{value}', numberFormatter(value));
const axisTickLength = FONT_SIZE_MULTIPLIERS.axisTickLength * fontSize;
const splitLineLength = FONT_SIZE_MULTIPLIERS.splitLineLength * fontSize;
const titleOffsetFromTitle =
FONT_SIZE_MULTIPLIERS.titleOffsetFromTitle * fontSize;
const detailOffsetFromTitle =
FONT_SIZE_MULTIPLIERS.detailOffsetFromTitle * fontSize;
const columnsLabelMap = new Map<string, string[]>();
const transformedData: GaugeDataItemOption[] = data.map(
(data_point, index) => {
const name = groupbyLabels
.map(column => `${column}: ${data_point[column]}`)
.join(', ');
columnsLabelMap.set(
name,
groupbyLabels.map(col => data_point[col] as string),
);
let item: GaugeDataItemOption = {
value: data_point[getMetricLabel(metric as QueryFormMetric)] as number,
name,
itemStyle: {
color: colorFn(index, sliceId),
},
title: {
offsetCenter: [
'0%',
`${index * titleOffsetFromTitle + OFFSETS.titleFromCenter}%`,
],
fontSize,
},
detail: {
offsetCenter: [
'0%',
`${
index * titleOffsetFromTitle +
OFFSETS.titleFromCenter +
detailOffsetFromTitle
}%`,
],
fontSize: FONT_SIZE_MULTIPLIERS.detailFontSize * fontSize,
},
};
if (
filterState.selectedValues &&
!filterState.selectedValues.includes(name)
) {
item = {
...item,
itemStyle: {
color: colorFn(index, sliceId),
opacity: OpacityEnum.SemiTransparent,
},
detail: {
show: false,
},
title: {
show: false,
},
};
}
return item;
},
);
const { setDataMask = () => {}, onContextMenu } = hooks;
const min = minVal ?? calculateMin(transformedData);
const max = maxVal ?? calculateMax(transformedData);
const axisLabels = range(min, max, (max - min) / splitNumber);
const axisLabelLength = Math.max(
...axisLabels.map(label => numberFormatter(label).length).concat([1]),
);
const normalizer = max;
const intervalBoundsAndColors = setIntervalBoundsAndColors(
intervals,
intervalColorIndices,
colorFn,
normalizer,
);
const splitLineDistance =
axisLineWidth + splitLineLength + OFFSETS.ticksFromLine;
const axisLabelDistance =
FONT_SIZE_MULTIPLIERS.axisLabelDistance *
fontSize *
FONT_SIZE_MULTIPLIERS.axisLabelLength *
axisLabelLength +
(showSplitLine ? splitLineLength : 0) +
(showAxisTick ? axisTickLength : 0) +
OFFSETS.ticksFromLine -
axisLineWidth;
const axisTickDistance =
axisLineWidth + axisTickLength + OFFSETS.ticksFromLine;
const progress = {
show: showProgress,
overlap,
roundCap,
width: fontSize,
};
const splitLine = {
show: showSplitLine,
distance: -splitLineDistance,
length: splitLineLength,
lineStyle: {
width: FONT_SIZE_MULTIPLIERS.splitLineWidth * fontSize,
color: gaugeSeriesOptions.splitLine?.lineStyle?.color,
},
};
const axisLine = {
roundCap,
lineStyle: {
width: axisLineWidth,
color: gaugeSeriesOptions.axisLine?.lineStyle?.color,
},
};
const axisLabel = {
distance: -axisLabelDistance,
fontSize,
formatter: numberFormatter,
color: gaugeSeriesOptions.axisLabel?.color,
};
const axisTick = {
show: showAxisTick,
distance: -axisTickDistance,
length: axisTickLength,
lineStyle: gaugeSeriesOptions.axisTick?.lineStyle as AxisTickLineStyle,
};
const detail = {
valueAnimation: animation,
formatter: (value: number) => formatValue(value),
color: gaugeSeriesOptions.detail?.color,
};
const tooltip = {
formatter: (params: CallbackDataParams) => {
const { name, value } = params;
return `${name} : ${formatValue(value as number)}`;
},
};
let pointer;
if (intervalBoundsAndColors.length) {
splitLine.lineStyle.color =
INTERVAL_GAUGE_SERIES_OPTION.splitLine?.lineStyle?.color;
axisTick.lineStyle.color = INTERVAL_GAUGE_SERIES_OPTION?.axisTick?.lineStyle
?.color as string;
axisLabel.color = INTERVAL_GAUGE_SERIES_OPTION.axisLabel?.color;
axisLine.lineStyle.color = intervalBoundsAndColors;
pointer = {
show: showPointer,
showAbove: false,
itemStyle: INTERVAL_GAUGE_SERIES_OPTION.pointer?.itemStyle,
};
} else {
pointer = {
show: showPointer,
showAbove: false,
};
}
const series: GaugeSeriesOption[] = [
{
type: 'gauge',
startAngle,
endAngle,
min,
max,
progress,
animation,
axisLine: axisLine as GaugeSeriesOption['axisLine'],
splitLine,
splitNumber,
axisLabel,
axisTick,
pointer,
detail,
tooltip,
radius:
Math.min(width, height) / 2 - axisLabelDistance - axisTickDistance,
center: ['50%', '55%'],
data: transformedData,
},
];
const echartOptions: EChartsCoreOption = {
tooltip: {
appendToBody: true,
trigger: 'item',
},
series,
};
return {
formData,
width,
height,
echartOptions,
setDataMask,
emitFilter,
labelMap: Object.fromEntries(columnsLabelMap),
groupby,
selectedValues: filterState.selectedValues || [],
onContextMenu,
};
}
相关信息
相关文章
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
7、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦