/**
 * 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 { CategoricalColorNamespace , DataRecordValue , ensureIsInt , getColumnLabel , getMetricLabel , getNumberFormatter , getTimeFormatter , NumberFormatter , } from '@superset-ui/core' ; import { CallbackDataParams } from 'echarts/types/src/util/types' ; import { RadarSeriesDataItemOption } from 'echarts/types/src/chart/radar/RadarSeries' ; import { EChartsCoreOption , RadarSeriesOption } from 'echarts' ; import { DEFAULT_FORM_DATA as DEFAULT_RADAR_FORM_DATA , EchartsRadarChartProps , EchartsRadarFormData , EchartsRadarLabelType , RadarChartTransformedProps , } from './types' ; import { DEFAULT_LEGEND_FORM_DATA } from '../types' ; import { extractGroupbyLabel , getChartPadding , getColtypesMapping , getLegendProps , } from '../utils/series' ; import { defaultGrid , defaultTooltip } from '../defaults' ; import { OpacityEnum } from '../constants' ; export function formatLabel ( { params , labelType , numberFormatter , } ) { const { name = '' , value } = params ; const formattedValue = numberFormatter ( value as number ) ; switch ( labelType ) { case EchartsRadarLabelType . Value : return formattedValue ; case EchartsRadarLabelType . KeyValue : return `${ name }: ${ formattedValue }` ; default : return name ; } } export default function transformProps ( chartProps ) { const { formData , height , hooks , filterState , queriesData , width } = chartProps ; const { data = [ ] } = queriesData [ 0 ] ; const coltypeMapping = getColtypesMapping ( queriesData [ 0 ] ) ; const { colorScheme , groupby , labelType , labelPosition , legendOrientation , legendType , legendMargin , metrics = [ ] , numberFormat , dateFormat , showLabels , showLegend , isCircle , columnConfig , } = { ... DEFAULT_LEGEND_FORM_DATA , ... DEFAULT_RADAR_FORM_DATA , ... formData , } ; const { setDataMask = ( ) => { } } = hooks ; const colorFn = CategoricalColorNamespace . getScale ( colorScheme as string ) ; const numberFormatter = getNumberFormatter ( numberFormat ) ; const formatter = ( params ) => formatLabel ( { params , numberFormatter , labelType , } ) ; const metricLabels = metrics . map ( getMetricLabel ) ; const groupbyLabels = groupby . map ( getColumnLabel ) ; const metricLabelAndMaxValueMap = new Map < string , number > ( ) ; const columnsLabelMap = new Map < string , DataRecordValue [ ] > ( ) ; const transformedData = [ ] ; data . forEach ( datum => { const joinedName = extractGroupbyLabel ( { datum , groupby : groupbyLabels , coltypeMapping , timeFormatter : getTimeFormatter ( dateFormat ) , } ) ; columnsLabelMap . set ( joinedName , groupbyLabels . map ( col => datum [ col ] ) ) ; for ( const [ metricLabel , value ] of Object . entries ( datum ) ) { if ( metricLabelAndMaxValueMap . has ( metricLabel ) ) { metricLabelAndMaxValueMap . set ( metricLabel , Math . max ( value as number , ensureIsInt ( metricLabelAndMaxValueMap . get ( metricLabel ) , Number . MIN_SAFE_INTEGER ) ) ) ; } else { metricLabelAndMaxValueMap . set ( metricLabel , value as number ) ; } } const isFiltered = filterState . selectedValues && ! filterState . selectedValues . includes ( joinedName ) ; transformedData . push ( { value : metricLabels . map ( metricLabel => datum [ metricLabel ] ) , name : joinedName , itemStyle : { color : colorFn ( joinedName ) , opacity : isFiltered ? OpacityEnum . Transparent : OpacityEnum . NonTransparent , } , lineStyle : { opacity : isFiltered ? OpacityEnum . SemiTransparent : OpacityEnum . NonTransparent , } , label : { show : showLabels , position : labelPosition , formatter , } , } as RadarSeriesDataItemOption ) ; } ) ; const selectedValues = ( filterState . selectedValues || [ ] ) . reduce ( ( acc , selectedValue ) => { const index = transformedData . findIndex ( ( { name } ) => name === selectedValue ) ; return { ... acc , [ index ] : selectedValue , } ; } , { } ) ; const indicator = metricLabels . map ( metricLabel => { const maxValueInControl = columnConfig ?. [ metricLabel ] ?. radarMetricMaxValue ; const metricValueAsMax = metricLabelAndMaxValueMap . get ( metricLabel ) === 0 ? Number . MAX_SAFE_INTEGER : metricLabelAndMaxValueMap . get ( metricLabel ) ; const max = maxValueInControl === null ? metricValueAsMax : maxValueInControl ; return { name : metricLabel , max , } ; } ) ; const series = [ { type : 'radar' , ... getChartPadding ( showLegend , legendOrientation , legendMargin ) , animation : false , emphasis : { label : { show : true , fontWeight : 'bold' , backgroundColor : 'white' , } , } , data : transformedData , } , ] ; const echartOptions = { grid : { ... defaultGrid , } , tooltip : { ... defaultTooltip , trigger : 'item' , } , legend : { ... getLegendProps ( legendType , legendOrientation , showLegend ) , data : Array . from ( columnsLabelMap . keys ( ) ) , } , series , radar : { shape : isCircle ? 'circle' : 'polygon' , indicator , } , } ; return { formData , width , height , echartOptions , setDataMask , labelMap : Object . fromEntries ( columnsLabelMap ) , groupby , selectedValues , } ; }