import { Colors } from '../../../common/colors' ; import { ConfigItem , Numeric } from '../../../common/config_objects' ; import { GOLDEN_RATIO , TAU } from '../../../common/constants' ; import { FONT_STYLES , FONT_VARIANTS } from '../../../common/text_utils' ; import { ColorVariant } from '../../../utils/common' ; import { PartitionLayout } from './types/config_types' ; import { ShapeTreeNode } from './types/viewmodel_types' ; import { AGGREGATE_KEY , STATISTICS_KEY } from './utils/group_by_rollup' ; function significantDigitCount ( d ) { let n = Math . abs ( parseFloat ( String ( d ) . replace ( '.' , '' ) ) ) ; if ( n === 0 ) { return 0 ; } while ( n !== 0 && n % 10 === 0 ) { n /= 10 ; } return Math . floor ( Math . log ( n ) / Math . LN10 ) + 1 ; } internal export function sumValueGetter ( node ) { return node [ AGGREGATE_KEY ] ; } public export const MODEL_KEY = 'parent' ; public export function percentValueGetter ( node ) { return ( 100 * node [ AGGREGATE_KEY ] ) / node [ MODEL_KEY ] [ STATISTICS_KEY ] . globalAggregate ; } public export function ratioValueGetter ( node ) { return node [ AGGREGATE_KEY ] / node [ MODEL_KEY ] [ STATISTICS_KEY ] . globalAggregate ; } public export const VALUE_GETTERS = Object . freeze ( { percent : percentValueGetter , ratio : ratioValueGetter } as const ) ; public export type ValueGetterName = keyof typeof VALUE_GETTERS ; public export function defaultPartitionValueFormatter ( d ) { return Math . abs ( d ) >= 10000000 || Math . abs ( d ) < 0.001 ? d . toExponential ( Math . min ( 2 , Math . max ( 0 , significantDigitCount ( d ) - 1 ) ) ) : d . toLocaleString ( undefined , { maximumSignificantDigits : 4 , maximumFractionDigits : 3 , useGrouping : true , } ) ; } internal export function percentFormatter ( d ) { return `${ Math . round ( d ) }%` ; } const fontSettings = { fontFamily : { dflt : 'Sans-Serif' , type : 'string' , } , fontSize : { dflt : 12 , min : 4 , max : 32 , type : 'number' } , fontStyle : { dflt : 'normal' , type : 'string' , values : FONT_STYLES , } , fontVariant : { dflt : 'normal' , type : 'string' , values : FONT_VARIANTS , } , fontWeight : { dflt : 400 , min : 100 , max : 900 , type : 'number' } , } ; const valueFont = { type : 'group' , values : { fontWeight : fontSettings . fontWeight , fontStyle : fontSettings . fontStyle , fontVariant : fontSettings . fontVariant , } , } ; internal export const configMetadata = { width : { dflt : 300 , min : 0 , max : 1024 , type : 'number' , reconfigurable : false } , height : { dflt : 150 , min : 0 , max : 1024 , type : 'number' , reconfigurable : false } , margin : { type : 'group' , values : { left : { dflt : 0 , min : - 0.25 , max : 0.25 , type : 'number' } , right : { dflt : 0 , min : - 0.25 , max : 0.25 , type : 'number' } , top : { dflt : 0 , min : - 0.25 , max : 0.25 , type : 'number' } , bottom : { dflt : 0 , min : - 0.25 , max : 0.25 , type : 'number' } , } , } , outerSizeRatio : new Numeric ( { dflt : 1 / GOLDEN_RATIO , min : 0.25 , max : 1 , reconfigurable : true , documentation : 'The diameter of the entire circle, relative to the smaller of the usable rectangular size (smaller of width/height minus the margins)' , } ) , emptySizeRatio : new Numeric ( { dflt : 0 , min : 0 , max : 0.8 , reconfigurable : true , documentation : 'The diameter of the inner circle, relative to `outerSizeRatio`' , } ) , clockwiseSectors : { dflt : true , type : 'boolean' , documentation : 'Largest to smallest sectors are positioned in a clockwise order' , } , specialFirstInnermostSector : { dflt : true , type : 'boolean' , documentation : 'Starts placement with the second largest slice, for the innermost pie/ring' , } , fontFamily : { dflt : 'Sans-Serif' , type : 'string' , } , minFontSize : { dflt : 8 , min : 0.1 , max : 8 , type : 'number' , reconfigurable : true } , maxFontSize : { dflt : 64 , min : 0.1 , max : 64 , type : 'number' } , idealFontSizeJump : { dflt : 1.05 , min : 1.05 , max : GOLDEN_RATIO , type : 'number' , reconfigurable : false , } , maximizeFontSize : { dflt : false , type : 'boolean' , } , partitionLayout : { dflt : PartitionLayout . sunburst , type : 'string' , values : Object . keys ( PartitionLayout ) , } , drilldown : { dflt : false , type : 'boolean' , } , circlePadding : { dflt : 2 , min : 0.0 , max : 8 , type : 'number' } , radialPadding : { dflt : TAU / 360 , min : 0 , max : 0.035 , type : 'number' } , horizontalTextAngleThreshold : { dflt : TAU / 12 , min : 0 , max : TAU , type : 'number' } , horizontalTextEnforcer : { dflt : 1 , min : 0 , max : 1 , type : 'number' } , maxRowCount : { dflt : 12 , min : 1 , max : 16 , type : 'number' } , fillOutside : { dflt : false , type : 'boolean' } , radiusOutside : { dflt : 128 , min : 0 , max : 1024 , type : 'number' } , fillRectangleWidth : { dflt : Infinity , reconfigurable : false , type : 'number' } , fillRectangleHeight : { dflt : Infinity , reconfigurable : false , type : 'number' } , fillLabel : { type : 'group' , values : { textColor : { type : 'color' , dflt : ColorVariant . Adaptive } , ... fontSettings , valueGetter : { dflt : sumValueGetter , type : 'function' , } , valueFormatter : { dflt : defaultPartitionValueFormatter , type : 'function' , } , valueFont , padding : { type : 'group' , values : { top : { dflt : 2 , min : 0 , max : 20 , type : 'number' , reconfigurable : true , documentation : 'Top padding for fill text' , } , bottom : { dflt : 2 , min : 0 , max : 20 , type : 'number' , reconfigurable : true , documentation : 'Bottom padding for fill text' , } , left : { dflt : 2 , min : 0 , max : 20 , type : 'number' , reconfigurable : true , documentation : 'Left padding for fill text' , } , right : { dflt : 2 , min : 0 , max : 20 , type : 'number' , reconfigurable : true , documentation : 'Right padding for fill text' , } , } , } , clipText : { type : 'boolean' , dflt : false , documentation : "Renders, but clips, text that's longer than what would fit in a box entirely" , } , } , } , linkLabel : { type : 'group' , values : { maximumSection : { dflt : 10 , min : 0 , max : 10000 , type : 'number' , reconfigurable : true , documentation : 'Uses linked labels below this limit of the outer sector arc length (in pixels)' , } , ... fontSettings , gap : { dflt : 10 , min : 6 , max : 16 , type : 'number' } , spacing : { dflt : 2 , min : 0 , max : 16 , type : 'number' } , horizontalStemLength : { dflt : 10 , min : 6 , max : 16 , type : 'number' } , radiusPadding : { dflt : 10 , min : 6 , max : 16 , type : 'number' } , lineWidth : { dflt : 1 , min : 0.1 , max : 2 , type : 'number' } , maxCount : { dflt : 36 , min : 2 , max : 64 , type : 'number' , documentation : 'Limits the total count of linked labels. The first N largest slices are kept.' , } , maxTextLength : { dflt : 100 , min : 2 , max : 200 , documentation : 'Limits the total number of characters in linked labels.' , } , textColor : { dflt : ColorVariant . Adaptive , type : 'color' } , minimumStemLength : { dflt : 0 , min : 0 , max : 16 , type : 'number' , reconfigurable : false , } , stemAngle : { dflt : TAU / 8 , min : 0 , max : TAU , type : 'number' , reconfigurable : false , } , valueFont , } , } , backgroundColor : { dflt : Colors . White . keyword , type : 'color' } , sectorLineWidth : { dflt : 1 , min : 0 , max : 4 , type : 'number' } , sectorLineStroke : { dflt : Colors . White . keyword , type : 'string' } , animation : { type : 'group' , values : { duration : { dflt : 0 , min : 0 , max : 3000 , type : 'number' } } } , } ; internal export type AdditiveAggregation = 'count' | 'sum' ;