import { Mark , Facet , SGItem , SGMark , DataFrame } from '@chart-parts/interfaces' ; import { createMark } from '@chart-parts/scenegraph' ; import { SceneFrame } from '../context/SceneFrame' ; import { createBoundItem } from './createBoundItem' ; ignore export interface FacetedData { name : string ; keyRowName ? : string ; facets : DataFacet [ ] ; } ignore export interface DataFacet { parent ? : any ; key : string ; data : any [ ] ; } type BoundData = any [ ] | FacetedData ; ignore export function processMark ( mark , frame ) { const markFrame = frame . pushMark ( mark ) ; const boundData = getBoundData ( mark , markFrame ) ; const items = createItems ( markFrame , boundData ) ; return createMark ( mark . type , items ) ; } function createItems ( frame , boundData ) { if ( Array . isArray ( boundData ) ) { return createItemPerDataRow ( frame , boundData ) ; } return createItemPerFacet ( frame , boundData ) ; } param frame param partitions function createItemPerFacet ( frame , { name , keyRowName , facets } ) { return facets . map ( ( facet , index ) => { const newData = { [ name ] : facet . data , } ; if ( keyRowName ) { newData [ keyRowName ] = facet . parent ; } const facetFrame = frame . pushData ( newData , facet . key ) ; return createBoundItem ( facetFrame , facet . parent || facet . data , index , facets ) ; } ) ; } param frame param data function createItemPerDataRow ( frame , data ) { return data . map ( ( row , index ) => createBoundItem ( frame , row , index , data ) ) ; } param mark param dataFrame function getBoundData ( mark , frame ) { const { table , facet } = mark ; const isSingleton = ! table && ! facet ; if ( isSingleton ) { return [ frame . boundDataItem ] ; } if ( ! table ) { throw new Error ( 'table must be set when facet is set' ) ; } const sourceTable = frame . data [ table ] ; if ( facet ) { const facetSourceTable = facet . table || table ; if ( ! facetSourceTable ) { throw new Error ( 'mark does not have table or faceting table defined' ) ; } if ( ! facet . groupBy ) { throw new Error ( 'faceting must groupBy defined' ) ; } const facetSource = frame . data [ facetSourceTable ] ; const result = createFacetedData ( facet , facetSource , sourceTable ) ; return result ; } else { if ( ! sourceTable ) { throw new Error ( `could not find table ${ table }` ) ; } return sourceTable ; } } function createFacetedData ( facet , facetSourceTable , markSourceTable ) { if ( ! facet . groupBy ) { throw new Error ( 'facet.groupBy must be defined' ) ; } const getKey = keyGetter ( facet . groupBy ) ; const facetMap = new Map < string , DataFacet > ( ) ; const markMap = new Map < string , any > ( ) ; const facets = [ ] ; if ( markSourceTable ) { markSourceTable . forEach ( markRow => { const key = getKey ( markRow ) ; markMap . set ( key , markRow ) ; } ) ; } facetSourceTable . forEach ( ( row ) => { const key = getKey ( row ) ; if ( ! facetMap . has ( key ) ) { const parent = markMap . get ( key ) ; const newFacet = { data : [ ] , key , parent , } ; facets . push ( newFacet ) ; facetMap . set ( key , newFacet ) ; } const f = facetMap . get ( key ) ; f ?. data . push ( row ) ; } ) ; const result = { name : facet . name , keyRowName : facet . keyRowName , facets , } ; return result ; } function keyGetter ( groupBy ) { if ( typeof groupBy === 'function' ) { return groupBy ; } else { const groupByKeys = typeof groupBy === 'string' ? [ groupBy ] : groupBy ; return ( row ) => groupByKeys . map ( g => row [ g ] ) . join ( '|' ) ; } }