import * as d3 from 'd3' ; import * as _ from 'underscore' ; import { MarkModel } from './MarkModel' ; import * as serialize from './serialize' ; import * as utils from './utils' ; export class LinesModel extends MarkModel { defaults ( ) { return { ... MarkModel . prototype . defaults ( ) , _model_name : 'LinesModel' , _view_name : 'Lines' , x : [ ] , y : [ ] , color : null , scales_metadata : { x : { orientation : 'horizontal' , dimension : 'x' } , y : { orientation : 'vertical' , dimension : 'y' } , color : { dimension : 'color' } , } , colors : d3 . scaleOrdinal ( d3 . schemeCategory10 ) . range ( ) , fill_colors : d3 . scaleOrdinal ( d3 . schemeCategory10 ) . range ( ) , stroke_width : 2.0 , labels_visibility : 'none' , curves_subset : [ ] , line_style : 'solid' , interpolation : 'linear' , close_path : false , fill : 'none' , marker : null , marker_size : 64 , opacities : [ ] , fill_opacities : [ ] , } ; } initialize ( attributes , options ) { super . initialize ( attributes , options ) ; this . on_some_change ( [ 'x' , 'y' , 'color' ] , this . update_data , this ) ; this . on ( 'change:labels' , this . update_labels , this ) ; this . on_some_change ( [ 'preserve_domain' ] , this . update_domains , this ) ; this . update_data ( ) ; this . update_domains ( ) ; } update_data ( ) { this . dirty = true ; const that = this ; this . x_data = this . get ( 'x' ) ; this . y_data = this . get ( 'y' ) ; this . color_data = this . get ( 'color' ) || [ ] ; let curve_labels = this . get ( 'labels' ) ; if ( this . x_data . length === 0 || this . y_data . length === 0 ) { this . mark_data = [ ] ; } else { this . x_data = utils . is_array ( this . x_data [ 0 ] ) ? this . x_data : [ this . x_data ] ; this . y_data = utils . is_array ( this . y_data [ 0 ] ) ? this . y_data : [ this . y_data ] ; curve_labels = this . get_labels ( ) ; const y_length = this . y_data . length ; if ( this . x_data . length == 1 && y_length > 1 ) { this . mark_data = curve_labels . map ( ( name , i ) => { return { name : name , values : Array . prototype . map . call ( that . y_data [ i ] , ( d , j ) => { return { x : that . x_data [ 0 ] [ j ] , y : d , y0 : that . y_data [ Math . min ( i + 1 , y_length - 1 ) ] [ j ] , sub_index : j , } ; } ) , color : that . color_data [ i ] , index : i , } ; } ) ; } else { this . mark_data = curve_labels . map ( ( name , i ) => { const xy_data = d3 . zip ( that . x_data [ i ] , that . y_data [ i ] ) ; return { name : name , values : xy_data . map ( ( d , j ) => { return { x : d [ 0 ] , y : d [ 1 ] , y0 : that . y_data [ Math . min ( i + 1 , y_length - 1 ) ] [ j ] , sub_index : j , } ; } ) , color : that . color_data [ i ] , index : i , } ; } ) ; } } this . update_domains ( ) ; this . dirty = false ; this . trigger ( 'data_updated' ) ; } update_labels ( ) { const labels = this . get_labels ( ) ; this . mark_data . forEach ( ( element , i ) => { element . name = labels [ i ] ; } ) ; this . trigger ( 'labels_updated' ) ; } get_labels ( ) { let curve_labels = this . get ( 'labels' ) ; const data_length = this . x_data . length == 1 ? this . y_data . length : Math . min ( this . x_data . length , this . y_data . length ) ; if ( curve_labels . length > data_length ) { curve_labels = curve_labels . slice ( 0 , data_length ) ; } else if ( curve_labels . length < data_length ) { _ . range ( curve_labels . length , data_length ) . forEach ( ( index ) => { curve_labels [ index ] = 'C' + ( index + 1 ) ; } ) ; } return curve_labels ; } update_domains ( ) { if ( ! this . mark_data ) { return ; } const scales = this . getScales ( ) ; const x_scale = scales . x , y_scale = scales . y ; const color_scale = scales . color ; if ( ! this . get ( 'preserve_domain' ) . x ) { x_scale . computeAndSetDomain ( this . mark_data . map ( ( elem ) => { return elem . values . map ( ( d ) => { return d . x ; } ) ; } ) , this . model_id + '_x' ) ; } else { x_scale . delDomain ( [ ] , this . model_id + '_x' ) ; } if ( ! this . get ( 'preserve_domain' ) . y ) { y_scale . computeAndSetDomain ( this . mark_data . map ( ( elem ) => { return elem . values . map ( ( d ) => { return d . y ; } ) ; } ) , this . model_id + '_y' ) ; } else { y_scale . delDomain ( [ ] , this . model_id + '_y' ) ; } if ( color_scale !== null && color_scale !== undefined ) { if ( ! this . get ( 'preserve_domain' ) . color ) { color_scale . computeAndSetDomain ( this . mark_data . map ( ( elem ) => { return elem . color ; } ) , this . model_id + '_color' ) ; } else { color_scale . delDomain ( [ ] , this . model_id + '_color' ) ; } } } get_data_dict ( data , index ) { return data ; } static serializers = { ... MarkModel . serializers , x : serialize . array_or_json_serializer , y : serialize . array_or_json_serializer , color : serialize . array_or_json_serializer , } ; x_data : any [ ] ; y_data : any [ ] ; color_data : number [ ] ; } export class FlexLineModel extends LinesModel { defaults ( ) { return { ... LinesModel . prototype . defaults ( ) , _model_name : 'FlexLineModel' , _view_name : 'FlexLine' , x : [ ] , y : [ ] , color : null , scales_metadata : { x : { orientation : 'horizontal' , dimension : 'x' } , y : { orientation : 'vertical' , dimension : 'y' } , color : { dimension : 'color' } , } , colors : d3 . scaleOrdinal ( d3 . schemeCategory10 ) . range ( ) , fill_colors : d3 . scaleOrdinal ( d3 . schemeCategory10 ) . range ( ) , stroke_width : 2.0 , labels_visibility : 'none' , curves_subset : [ ] , line_style : 'solid' , interpolation : 'linear' , close_path : false , fill : 'none' , marker : null , marker_size : 64 , opacities : [ ] , fill_opacities : [ ] , } ; } update_data ( ) { this . dirty = true ; const that = this ; this . x_data = this . get ( 'x' ) ; this . y_data = this . get ( 'y' ) ; let curve_labels = this . get ( 'labels' ) ; if ( this . x_data . length === 0 || this . y_data . length === 0 ) { this . mark_data = [ ] ; this . data_len = 0 ; } else { this . x_data = ! _ . isNumber ( this . x_data [ 0 ] ) ? this . x_data : [ this . x_data ] ; this . y_data = ! _ . isNumber ( this . y_data [ 0 ] ) ? this . y_data : [ this . y_data ] ; curve_labels = this . get_labels ( ) ; const color_data = this . get ( 'color' ) || [ ] ; const width_data = [ this . get ( 'width' ) || [ ] ] ; this . data_len = Math . min ( this . x_data [ 0 ] . length , this . y_data [ 0 ] . length ) ; this . mark_data = [ { name : curve_labels [ 0 ] , values : _ . range ( this . data_len - 1 ) . map ( ( val , index ) => { return { x1 : that . x_data [ 0 ] [ index ] , y1 : that . y_data [ 0 ] [ index ] , x2 : that . x_data [ 0 ] [ index + 1 ] , y2 : that . y_data [ 0 ] [ index + 1 ] , color : color_data [ index ] , size : width_data [ 0 ] [ index ] , } ; } ) , } , ] ; } this . update_domains ( ) ; this . dirty = false ; this . trigger ( 'data_updated' ) ; } update_domains ( ) { if ( ! this . mark_data ) { return ; } const scales = this . getScales ( ) ; const x_scale = scales . x , y_scale = scales . y ; const color_scale = scales . color ; const width_scale = scales . width ; if ( ! this . get ( 'preserve_domain' ) . x ) { x_scale . computeAndSetDomain ( this . x_data [ 0 ] . slice ( 0 , this . data_len ) , this . model_id + '_x' ) ; } else { x_scale . delDomain ( [ ] , this . model_id + '_x' ) ; } if ( ! this . get ( 'preserve_domain' ) . y ) { y_scale . computeAndSetDomain ( this . y_data [ 0 ] . slice ( 0 , this . data_len ) , this . model_id + '_y' ) ; } else { y_scale . delDomain ( [ ] , this . model_id + '_y' ) ; } if ( color_scale !== null && color_scale !== undefined ) { if ( ! this . get ( 'preserve_domain' ) . color ) { color_scale . computeAndSetDomain ( this . mark_data . map ( ( elem ) => { return elem . values . map ( ( d ) => { return d . color ; } ) ; } ) , this . model_id + '_color' ) ; } else { color_scale . delDomain ( [ ] , this . model_id + '_color' ) ; } } if ( width_scale !== null && width_scale !== undefined ) { if ( ! this . get ( 'preserve_domain' ) . width ) { width_scale . computeAndSetDomain ( this . mark_data . map ( ( elem ) => { return elem . values . map ( ( d ) => { return d . size ; } ) ; } ) , this . model_id + '_width' ) ; } else { width_scale . delDomain ( [ ] , this . model_id + '_width' ) ; } } } static serializers = { ... LinesModel . serializers , width : serialize . array_or_json_serializer , } ; data_len : number ; }