import _ from 'lodash' ; import Package from '@/data/package/package' ; import TabularDataset from '@/data/tabular-dataset' ; import { INDEX_COLUMN } from '@/common/constants' ; import { VisualProperties } from '@/data/visuals' ; interface Items { [ index ] : SubsetItem ; } export interface SubsetItem { index : number ; visuals : VisualProperties ; } export default class SubsetPackage extends Package { private dataset : TabularDataset | undefined = undefined ; private items : Items = { } ; constructor ( dataset ? , includeItems ? ) { super ( ) ; this . dataset = dataset ; if ( includeItems !== false ) { this . initItems ( ) ; } } public hasDataset ( ) { return this . dataset !== undefined ; } public getDataset ( ) { return this . dataset ; } public getItems ( ) { return _ . toArray ( this . items ) ; } public getItemIndices ( ) { return _ . keys ( this . items ) . map ( index => + index ) ; } public hasItem ( item ) { return ( item instanceof Object ? ( item as SubsetItem ) . index : item ) in this . items ; } public addItem ( item ) { if ( ! ( item . index in this . items ) ) { this . items [ item . index ] = item ; } else { const oldVisuals = this . items [ item . index ] . visuals ; this . items [ item . index ] = { index : item . index , visuals : _ . extend ( { } , oldVisuals , item . visuals ) } ; } } public addItemIndex ( index ) { if ( ! ( index in this . items ) ) { this . items [ index ] = { index , visuals : { } } ; } } public addItemIndices ( indices ) { for ( const index of indices ) { this . addItemIndex ( index ) ; } } public filterItems ( condition ) { const indices = this . getItemIndices ( ) ; for ( const index of indices ) { const item = this . items [ index ] ; if ( ! condition ( item ) ) { this . removeItem ( item ) ; } } } public getItem ( index ) { return this . items [ index ] ; } public removeItem ( item ) { if ( item . index in this . items ) { delete this . items [ item . index ] ; } } public removeItemIndex ( index ) { if ( index in this . items ) { delete this . items [ index ] ; } } /**
     * Clears the items in the subset. Note that this does not clear the dataset.
     */ public clearItems ( ) { this . items = { } ; } /**
     * Clears the dataset and items.
     */ public clearDataset ( ) { this . dataset = undefined ; } public numItems ( ) { return _ . size ( this . items ) ; } /**
     * Returns a deep copy of the package.
     */ public clone ( ) { const pkg = new SubsetPackage ( ) ; pkg . subsetFrom ( this ) ; return pkg ; } /**
     * Returns a deep copy of the package with only items defined in "items".
     */ public subset ( items ) { const pkg = new SubsetPackage ( ) ; pkg . subsetFrom ( this , items ) ; return pkg ; } /**
     * Checks if the given package is the same as the previous one.
     * A package is different if:
     * - the dataset changes
     * - the subset changes
     * - any visual properties of the subset change
     */ public isSamePackage ( pkg ) { if ( this . dataset !== pkg . dataset || ! this . dataset ) { return false ; } return _ . isEqual ( this . items , pkg . items ) ; } /**
     * Produces a 2D array in which each subarray is a group of items.
     * Items with the same value on "column" are placed in a group.
     */ public groupItems ( columnIndex ) { if ( columnIndex === null ) { return [ this . getItemIndices ( ) ] ; } const groups = [ ] ; const valueSet = { } ; let groupCounter = 0 ; _ . each ( this . items , ( item , itemIndexStr ) => { const itemIndex = + itemIndexStr ; const value = columnIndex === INDEX_COLUMN ? itemIndex : ( this . dataset as TabularDataset ) . getCell ( itemIndex , columnIndex ) ; if ( value in valueSet ) { const group = valueSet [ value ] ; groups [ group ] . push ( itemIndex ) ; } else { valueSet [ value ] = groupCounter ; groups [ groupCounter ++ ] = [ itemIndex ] ; } } ) ; return groups ; } param items private subsetFrom ( pkg , items ? ) { this . dataset = pkg . dataset ; if ( ! items ) { this . items = _ . cloneDeep ( pkg . items ) ; } else { const newItems = { } ; for ( const index of items ) { if ( index in pkg . items ) { newItems [ index ] = _ . cloneDeep ( pkg . items [ index ] ) ; } } this . items = newItems ; } } private initItems ( ) { if ( ! this . dataset ) { return ; } for ( let index = 0 ; index < this . dataset . numRows ( ) ; index ++ ) { this . items [ index ] = { index , visuals : { } } ; } } }