'use strict' ; import { State , store } from '../store' ; import { MarkRecord } from '../store/factory/Mark' ; import { TextRecord } from '../store/factory/marks/Text' ; import { InteractionRecord } from '../store/factory/Interaction' ; import { WidgetRecord } from '../store/factory/Widget' ; const Bounds = require ( 'vega-scenegraph' ) . Bounds ; const getInVis = require ( './immutable-utils' ) . getInVis ; param { ImmutableMap } mark param { ImmutableMap } state returns { ImmutableMap | null } function getParent ( mark , state ) { state = state || store . getState ( ) ; return getInVis ( state , 'marks.' + mark . _parent ) || null ; } param { ImmutableMap } primitive param { ImmutableMap } state returns { ImmutableMap [ ] } function getParents ( primitive , state ) { if ( ! primitive ) { return [ ] ; } let current = primitive . get ( '_parent' ) && getParent ( primitive , state ) ; if ( ! current ) { return [ ] ; } const parents = [ current ] ; while ( current && current . _parent ) { current = getParent ( current , state ) ; if ( current ) { parents . push ( current ) ; } } return parents ; } param { ImmutableMap [ ] } primitives returns { Array } function getGroupIds ( primitives ) { return primitives . reduce ( function ( groupIds , primitive ) { if ( primitive . get ( 'type' ) === 'group' ) { groupIds . push ( primitive . get ( '_id' ) ) ; } return groupIds ; } , [ ] ) ; } param { number } markId param { ImmutableMap } state returns { number [ ] } export function getParentGroupIds ( markId , state ) { state = state || store . getState ( ) ; return getGroupIds ( getParents ( getInVis ( state , 'marks.' + markId ) , state ) ) ; } param { number } id param { ImmutableMap } state returns { number | null } export function getClosestGroupId ( id ? , state ? ) { state = state || store . getState ( ) ; const markId = id || state . getIn ( [ 'inspector' , 'encodings' , 'selectedId' ] ) ; let mark = getInVis ( state , 'marks.' + markId ) ; if ( ! mark ) { const interaction = state . getIn ( [ 'vis' , 'present' , 'interactions' , String ( markId ) ] ) ; if ( interaction && interaction . groupId ) { return interaction . groupId ; } const widget = state . getIn ( [ 'vis' , 'present' , 'widgets' , String ( markId ) ] ) ; if ( widget && widget . groupId ) { return widget . groupId ; } const groups = state . getIn ( [ 'vis' , 'present' , 'marks' ] ) . filter ( mark => mark . type === 'group' ) ; if ( groups . size === 1 ) { return groups . first ( ) . _id ; } return getInVis ( state , 'scene._id' ) ; } if ( mark . get ( 'type' ) === 'group' || mark . get ( 'type' ) === 'scene' ) { return mark . get ( '_id' ) ; } return getClosestGroupId ( mark . get ( '_parent' ) , state ) ; } param { Object } item param { number [ ] } path returns { Object | null } function findInItemTree ( item , path ) { const vis = document . querySelector ( '.vis-container' ) , offset = { x : 0 , y : 0 } ; let itemX = + Number . MAX_VALUE , itemY = + Number . MAX_VALUE , intersects , closest , role ; for ( let i = path . length - 1 ; i >= 0 ; -- i ) { const id = path [ i ] ; offset . x += + item . x || 0 ; offset . y += + item . y || 0 ; for ( let items = item . items , j = 0 , len = items . length ; j < len ; ++ j ) { role = items [ j ] . role ; item = role && + role . split ( 'lyra_' ) [ 1 ] === id ? items [ j ] . items [ 0 ] : null ; if ( item !== null ) { break ; } } if ( item === null ) { break ; } } const viewport = new Bounds ( { x1 : vis . scrollLeft , x2 : 300 + vis . scrollLeft , y1 : vis . scrollTop , y2 : 200 + vis . scrollTop } ) ; if ( item && item . mark . items . length > 1 ) { for ( let i = 0 , items = item . mark . items , len = items . length ; i < len ; ++ i ) { item = items [ i ] ; const bounds = item . bounds ; const closer = bounds && ( bounds . x1 < itemX || bounds . y1 < itemY ) ; if ( ! bounds ) { break ; } if ( viewport . encloses ( bounds ) ) { closest = intersects = null ; break ; } else if ( viewport . intersects ( bounds ) && closer ) { intersects = item ; itemX = bounds . x1 ; itemY = bounds . y1 ; } else if ( closer ) { closest = item ; itemX = bounds . x1 ; itemY = bounds . y1 ; } } } return intersects || closest || item ; } module . exports = { getParent : getParent , getParentGroupIds : getParentGroupIds , getParents : getParents , getGroupIds : getGroupIds , getClosestGroupId : getClosestGroupId , findInItemTree : findInItemTree } ;