import { extend , isArray } from 'vega' ; import { isDataRefDomain , isSignalRef } from 'vega-lite/build/src/vega.schema' ; import { State } from '../../store' ; import { RangeScale , Scale , ScaleRecord } from '../../store/factory/Scale' ; import { addScale , updateScaleProperty } from '../scaleActions' ; import { addScaleToGroup } from './helperActions' ; import { CompiledBinding } from './index' ; import { assignId } from '../../util/counter' ; import { ThunkDispatch } from 'redux-thunk' ; import { MarkRecord } from '../../store/factory/Mark' ; const imutils = require ( '../../util/immutable-utils' ) , getIn = imutils . getIn , getInVis = imutils . getInVis ; todo param { Function } dispatch param { ImmutableMap } state param { Object } parsed returns { void } export default function parseScales ( dispatch , state , parsed ) { const map = parsed . map . scales , dsMap = parsed . map . data , mark = parsed . mark , channel = parsed . channel ; let prev = getInVis ( state , 'scales.' + map [ channel ] ) , scaleId = prev && prev . _id , scales = parsed . output . scales as RangeScale [ ] ; if ( ! scales ) { return ; } scales = scales . filter ( s => s . name === channel ) ; if ( scales . length !== 1 ) { console . warn ( scales . length + ' scales found for ' + channel ) ; return ; } const def = parse ( scales [ 0 ] ) ; if ( ! prev || ! equals ( state , def , prev , dsMap ) ) { getInVis ( state , 'scales' ) . valueSeq ( ) . forEach ( function ( scale ) { if ( equals ( state , def , scale , dsMap ) ) { prev = scale ; scaleId = scale . _id ; return false ; } } ) ; } const otherMarksInGroup = state . getIn ( [ 'vis' , 'present' , 'marks' ] ) . valueSeq ( ) . filter ( x => x . type !== 'group' && x . type !== 'scene' && x . _id !== mark . _id && x . _parent === mark . _parent ) ; let didUnion = false ; otherMarksInGroup . forEach ( ( mark ) => { let markScale ; if ( channel === 'x' ) { markScale = ( mark . encode ?. update ?. x as any ) . scale ; } else if ( channel === 'y' ) { markScale = ( mark . encode ?. update ?. y as any ) . scale ; } if ( markScale ) { const scale = state . getIn ( [ 'vis' , 'present' , 'scales' , String ( markScale ) ] ) ; prev = scale ; scaleId = scale . _id ; const tempScale = createScale ( parsed , def ) ; const unionedDomain = scale . _domain . concat ( tempScale . _domain ) . filter ( ( value , idx , arr ) => arr . findIndex ( t => ( t . field === value . field ) ) === idx ) ; dispatch ( updateScaleProperty ( { property : '_domain' , value : unionedDomain } , scale . _id ) ) ; didUnion = true ; } } ) ; if ( ! didUnion && ( ! prev || ! equals ( state , def , prev , dsMap ) ) ) { scaleId = assignId ( dispatch , state ) ; const scale = createScale ( parsed , def ) . merge ( { _id : scaleId } ) ; dispatch ( addScale ( scale ) ) ; } map [ channel ] = scaleId ; dispatch ( addScaleToGroup ( scaleId , mark . _parent ) ) ; } private param { Object } def returns { Object } function parse ( def ) { const range = def . range ; if ( def . name === 'x' || ( isArray ( range ) && range . find ( r => isSignalRef ( r ) && r . signal === 'width' ) ) ) { def . range = 'width' ; } else if ( def . name === 'y' || ( isArray ( range ) && range . find ( r => isSignalRef ( r ) && r . signal === 'height' ) ) ) { def . range = 'height' ; } return def ; } private param { ImmutableMap } state param { string } markType param { Object } def param { Scale } scale param { Object } dsMap returns { boolean } function equals ( state , def , scale , dsMap ) { if ( scale . type !== def . type ) { return false ; } if ( JSON . stringify ( scale . range ) !== JSON . stringify ( def . range ) ) { return false ; } if ( isDataRefDomain ( def . domain ) && scale . _domain ) { const domain = scale . _domain [ 0 ] ; if ( domain . field !== def . domain . field ) { return false ; } const pipeline = getInVis ( state , `datasets.${ domain . data }._parent` ) ; if ( pipeline !== getInVis ( state , `datasets.${ dsMap [ def . domain . data ] }._parent` ) ) { return false ; } } return true ; } function createScale ( parsed , def ) { const { domain , ... rest } = def , props = isDataRefDomain ( domain ) ? extend ( { } , rest , { _domain : [ { data : parsed . map . data [ domain . data ] , field : domain . field } ] } ) : def ; return Scale ( props ) ; }