import { Layer , picking , project32 } from '@deck.gl/core' ; import GL from '@luma.gl/constants' ; import { Geometry , Model } from '@luma.gl/core' ; import { RGBA } from '../colors' ; import { Flow } from '../types' ; import FragmentShader from './FlowLinesLayerFragment.glsl' ; import VertexShader from './FlowLinesLayerVertex.glsl' ; import { LayerProps } from '../LayerProps' ; export interface Props extends LayerProps { id : string ; opacity ? : number ; pickable ? : boolean ; updateTriggers ? : { [ key ] : { } ; } ; data : Flow [ ] ; drawOutline : boolean ; outlineColor ? : RGBA ; outlineThickness ? : number ; thicknessUnit ? : number ; getSourcePosition ? : ( d : Flow ) => [ number , number ] ; getTargetPosition ? : ( d : Flow ) => [ number , number ] ; getColor ? : ( d : Flow ) => RGBA ; getThickness ? : ( d : Flow ) => number ; getPickable ? : ( d : Flow , { index } : { index : number ; } ) => number ; getEndpointOffsets ? : ( d : Flow ) => [ number , number ] ; } const DEFAULT_COLOR = [ 0 , 132 , 193 , 255 ] ; const INNER_SIDE_OUTLINE_THICKNESS = 1 ; class FlowLinesLayer extends Layer { static layerName : string = 'FlowLinesLayer' ; static defaultProps = { getSourcePosition : { type : 'accessor' , value : ( d ) => d . sourcePosition } , getTargetPosition : { type : 'accessor' , value : ( d ) => d . targetPosition } , getColor : { type : 'accessor' , value : DEFAULT_COLOR } , getThickness : { type : 'accessor' , value : ( d ) => d . thickness } , getPickable : { type : 'accessor' , value : ( d ) => 1.0 } , drawOutline : true , thicknessUnit : 10 , outlineThickness : 1 , outlineColor : [ 255 , 255 , 255 , 255 ] , parameters : { depthTest : false , } , } ; props ! : Props ; constructor ( props ) { super ( props ) ; } getShaders ( ) { return super . getShaders ( { vs : VertexShader , fs : FragmentShader , modules : [ project32 , picking ] , shaderCache : this . context . shaderCache , } ) ; } initializeState ( ) { const { attributeManager } = this . state ; attributeManager . addInstanced ( { instanceSourcePositions : { accessor : 'getSourcePosition' , size : 3 , transition : false , type : GL . DOUBLE , } , instanceTargetPositions : { accessor : 'getTargetPosition' , size : 3 , transition : false , type : GL . DOUBLE , } , instanceThickness : { accessor : 'getThickness' , size : 1 , transition : false , } , instanceEndpointOffsets : { accessor : 'getEndpointOffsets' , size : 2 , transition : false , } , instanceColors : { accessor : 'getColor' , size : 4 , type : GL . UNSIGNED_BYTE , transition : false , } , instancePickable : { accessor : 'getPickable' , size : 1 , transition : false , } , } ) ; } updateState ( { props , oldProps , changeFlags } ) { super . updateState ( { props , oldProps , changeFlags } ) ; if ( changeFlags . extensionsChanged ) { const { gl } = this . context ; if ( this . state . model ) { this . state . model . delete ( ) ; } this . setState ( { model : this . _getModel ( gl ) } ) ; this . getAttributeManager ( ) . invalidateAll ( ) ; } } draw ( { uniforms } ) { const { gl } = this . context ; const { outlineColor , thicknessUnit } = this . props ; gl . lineWidth ( 1 ) ; this . state . model . setUniforms ( { ... uniforms , outlineColor : outlineColor ! . map ( ( x ) => x / 255 ) , thicknessUnit : thicknessUnit ! * 2.0 , gap : 0.5 , } ) . draw ( ) ; } _getModel ( gl ) { let positions = [ ] ; let pixelOffsets = [ ] ; const { drawOutline , outlineThickness } = this . props ; if ( drawOutline ) { positions = positions . concat ( [ 0 , 0 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 1 , 0 , - 3 , 1 , 1 , - 3 , 1 , 0 , 0 , 1 , 2 , - 3 , 1 , 0 , - 3 , ] ) ; const tout = outlineThickness ! ; const tin = INNER_SIDE_OUTLINE_THICKNESS ; pixelOffsets = pixelOffsets . concat ( [ - tin , - tout , 1 , tout , - tout , 1 , - tin , tout , 1 , tout , - tout , 1 , - tin , 0 , 1 , tout , 0 , 1 , - tin , 3 * tout , 1 , 2 * tout , - tout , 1 , - tin , - tout , 1 , ] ) ; } positions = positions . concat ( [ 0 , 0 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 1 , 0 , - 3 , 1 , 1 , - 3 , 1 , 0 , 0 , 1 , 2 , - 3 , 1 , 0 , - 3 , ] ) ; pixelOffsets = pixelOffsets . concat ( [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , ] ) ; return new Model ( gl , { id : this . props . id , ... this . getShaders ( ) , geometry : new Geometry ( { drawType : GL . TRIANGLES , attributes : { positions : new Float32Array ( positions ) , normals : new Float32Array ( pixelOffsets ) , } , } ) , isInstanced : true , shaderCache : this . context . shaderCache , } ) ; } } export default FlowLinesLayer ;