import { format } from 'd3-format' ; import { boxplotBuilder , IAdvancedBoxPlotData , IEventListener } from '../internal' ; import { dialogAddons , SortByDefault , toolbar } from './annotations' ; import ArrayColumn , { IArrayColumnDesc } from './ArrayColumn' ; import Column , { dirty , dirtyCaches , dirtyHeader , dirtyValues , groupRendererChanged , labelChanged , metaDataChanged , rendererTypeChanged , summaryRendererChanged , visibilityChanged , widthChanged , } from './Column' ; import type { IArrayDesc } from './IArrayColumn' ; import { IDataRow , ECompareValueType , ITypeFactory } from './interfaces' ; import { DEFAULT_FORMATTER , getBoxPlotNumber , isDummyNumberFilter , noNumberFilter , restoreNumberFilter , toCompareBoxPlotValue , } from './internalNumber' ; import { EAdvancedSortMethod , IColorMappingFunction , IMappingFunction , INumberDesc , INumberFilter , INumbersColumn , } from './INumberColumn' ; import { restoreMapping } from './MappingFunction' ; import { isMissingValue } from './missing' ; import NumberColumn from './NumberColumn' ; import type { dataLoaded } from './ValueColumn' ; import type ValueColumn from './ValueColumn' ; import { integrateDefaults } from './internal' ; export interface INumbersDesc extends IArrayDesc , INumberDesc { readonly sort ? : EAdvancedSortMethod ; } export declare type INumbersColumnDesc = INumbersDesc & IArrayColumnDesc < number > ; asMemberOf event export declare function mappingChanged_NCS ( previous , current ) ; asMemberOf event export declare function colorMappingChanged_NCS ( previous , current ) ; asMemberOf event export declare function sortMethodChanged_NCS ( previous , current ) ; asMemberOf event export declare function filterChanged_NCS ( previous , current ) ; @ toolbar ( 'rename' , 'clone' , 'sort' , 'sortBy' , 'filterNumber' , 'colorMapped' , 'editMapping' ) @ dialogAddons ( 'sort' , 'sortNumbers' ) @ SortByDefault ( 'descending' ) export default class NumbersColumn extends ArrayColumn < number > implements INumbersColumn { static readonly EVENT_MAPPING_CHANGED = NumberColumn . EVENT_MAPPING_CHANGED ; static readonly EVENT_COLOR_MAPPING_CHANGED = NumberColumn . EVENT_COLOR_MAPPING_CHANGED ; static readonly EVENT_SORTMETHOD_CHANGED = NumberColumn . EVENT_SORTMETHOD_CHANGED ; static readonly EVENT_FILTER_CHANGED = NumberColumn . EVENT_FILTER_CHANGED ; static readonly CENTER = 0 ; private readonly numberFormat : ( n : number ) => string = DEFAULT_FORMATTER ; private sort : EAdvancedSortMethod ; private mapping : IMappingFunction ; private original : IMappingFunction ; private colorMapping : IColorMappingFunction ; type { { min : number , max : number } } private private currentFilter : INumberFilter = noNumberFilter ( ) ; constructor ( id , desc , factory ) { super ( id , integrateDefaults ( desc , Object . assign ( { renderer : 'heatmap' , groupRenderer : 'heatmap' , summaryRenderer : 'histogram' , } , desc . dataLength != null && ! Number . isNaN ( desc . dataLength ) ? { width : Math . min ( Math . max ( 100 , desc . dataLength ! * 10 ) , 500 ) , } : { } ) ) ) ; this . mapping = restoreMapping ( desc , factory ) ; this . original = this . mapping . clone ( ) ; this . colorMapping = factory . colorMappingFunction ( desc . colorMapping || desc . color ) ; if ( desc . numberFormat ) { this . numberFormat = format ( desc . numberFormat ) ; } this . sort = desc . sort || EAdvancedSortMethod . median ; } getNumberFormat ( ) { return this . numberFormat ; } toCompareValue ( row ) { return toCompareBoxPlotValue ( this , row ) ; } toCompareValueType ( ) { return ECompareValueType . FLOAT ; } getRawNumbers ( row ) { return this . getRawValue ( row ) ; } getBoxPlotData ( row ) { const data = this . getRawValue ( row ) ; if ( data == null ) { return null ; } const b = boxplotBuilder ( ) ; for ( const d of data ) { b . push ( isMissingValue ( d ) ? NaN : this . mapping . apply ( d ) ) ; } return b . build ( ) ; } getRange ( ) { return this . mapping . getRange ( this . numberFormat ) ; } getRawBoxPlotData ( row ) { const data = this . getRawValue ( row ) ; if ( data == null ) { return null ; } const b = boxplotBuilder ( ) ; for ( const d of data ) { b . push ( isMissingValue ( d ) ? NaN : d ) ; } return b . build ( ) ; } getNumbers ( row ) { return this . getValues ( row ) ; } getNumber ( row ) { return getBoxPlotNumber ( this , row , 'normalized' ) ; } getRawNumber ( row ) { return getBoxPlotNumber ( this , row , 'raw' ) ; } getValue ( row ) { const v = this . getValues ( row ) ; return v . every ( Number . isNaN ) ? null : v ; } getValues ( row ) { return this . getRawValue ( row ) . map ( ( d ) => ( Number . isNaN ( d ) ? NaN : this . mapping . apply ( d ) ) ) ; } iterNumber ( row ) { const v = this . getNumbers ( row ) ; if ( v . every ( Number . isNaN ) ) { return [ NaN ] ; } return v ; } iterRawNumber ( row ) { const v = this . getRawNumbers ( row ) ; if ( v . every ( Number . isNaN ) ) { return [ NaN ] ; } return v ; } getRawValue ( row ) { const r = super . getRaw ( row ) ; return r == null ? [ ] : r . map ( ( d ) => ( isMissingValue ( d ) ? NaN : + d ) ) ; } getExportValue ( row , format ) { return format === 'json' ? this . getRawValue ( row ) : super . getExportValue ( row , format ) ; } getLabels ( row ) { return this . getRawValue ( row ) . map ( this . numberFormat ) ; } getSortMethod ( ) { return this . sort ; } setSortMethod ( sort ) { if ( this . sort === sort ) { return ; } this . fire ( [ NumbersColumn . EVENT_SORTMETHOD_CHANGED , NumberColumn . EVENT_DIRTY_HEADER , NumberColumn . EVENT_DIRTY_VALUES , NumbersColumn . EVENT_DIRTY_CACHES , NumberColumn . EVENT_DIRTY , ] , this . sort , ( this . sort = sort ) ) ; if ( ! this . isSortedByMe ( ) . asc ) { this . sortByMe ( ) ; } } dump ( toDescRef ) { const r = super . dump ( toDescRef ) ; r . sortMethod = this . getSortMethod ( ) ; r . filter = ! isDummyNumberFilter ( this . currentFilter ) ? this . currentFilter : null ; r . map = this . mapping . toJSON ( ) ; r . colorMapping = this . colorMapping . toJSON ( ) ; return r ; } restore ( dump , factory ) { super . restore ( dump , factory ) ; if ( dump . sortMethod ) { this . sort = dump . sortMethod ; } if ( dump . filter ) { this . currentFilter = restoreNumberFilter ( dump . filter ) ; } if ( dump . map || dump . domain ) { this . mapping = restoreMapping ( dump , factory ) ; } if ( dump . colorMapping ) { this . colorMapping = factory . colorMappingFunction ( dump . colorMapping ) ; } } protected createEventList ( ) { return super . createEventList ( ) . concat ( [ NumbersColumn . EVENT_COLOR_MAPPING_CHANGED , NumbersColumn . EVENT_MAPPING_CHANGED , NumbersColumn . EVENT_SORTMETHOD_CHANGED , NumbersColumn . EVENT_FILTER_CHANGED , ] ) ; } on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) ; on ( type , listener ) { return super . on ( type as any , listener ) ; } getOriginalMapping ( ) { return this . original . clone ( ) ; } getMapping ( ) { return this . mapping . clone ( ) ; } setMapping ( mapping ) { if ( this . mapping . eq ( mapping ) ) { return ; } this . fire ( [ NumbersColumn . EVENT_MAPPING_CHANGED , Column . EVENT_DIRTY_HEADER , Column . EVENT_DIRTY_VALUES , Column . EVENT_DIRTY_CACHES , Column . EVENT_DIRTY , ] , this . mapping . clone ( ) , ( this . mapping = mapping ) ) ; } getColor ( row ) { return NumberColumn . prototype . getColor . call ( this , row ) ; } getColorMapping ( ) { return this . colorMapping . clone ( ) ; } setColorMapping ( mapping ) { if ( this . colorMapping . eq ( mapping ) ) { return ; } this . fire ( [ NumbersColumn . EVENT_COLOR_MAPPING_CHANGED , Column . EVENT_DIRTY_HEADER , Column . EVENT_DIRTY_VALUES , Column . EVENT_DIRTY_CACHES , Column . EVENT_DIRTY , ] , this . colorMapping . clone ( ) , ( this . colorMapping = mapping ) ) ; } isFiltered ( ) { return NumberColumn . prototype . isFiltered . call ( this ) ; } getFilter ( ) { return NumberColumn . prototype . getFilter . call ( this ) ; } setFilter ( value ) { NumberColumn . prototype . setFilter . call ( this , value ) ; } filter ( row ) { return NumberColumn . prototype . filter . call ( this , row ) ; } clearFilter ( ) { return NumberColumn . prototype . clearFilter . call ( this ) ; } }