1- import { Layer } from '@deck.gl/core' ;
2- import GL from '@luma.gl/constants' ;
3- import { Model , Geometry } from '@luma.gl/core' ;
1+ import { Color , DefaultProps , Layer , LayerDataSource , LayerProps } from '@deck.gl/core' ;
2+ import { Model , Geometry } from '@luma.gl/engine' ;
3+ import { Texture } from '@luma.gl/core' ;
4+ import { ScaleLinear } from 'd3-scale' ;
45
56import { textMatrixToTexture } from './utils' ;
67
78import fragmentShader from './axes-fragment.glsl' ;
89import gridVertex from './grid-vertex.glsl' ;
910import labelVertex from './label-vertex.glsl' ;
1011import labelFragment from './label-fragment.glsl' ;
12+ import { Axis , Tick , TickFormat , Vec2 , Vec3 } from './types' ;
1113
1214/* Constants */
1315const DEFAULT_FONT_SIZE = 48 ;
1416const DEFAULT_TICK_COUNT = 6 ;
15- const DEFAULT_TICK_FORMAT = x => x . toFixed ( 2 ) ;
17+ const DEFAULT_TICK_FORMAT = ( x : number ) => x . toFixed ( 2 ) ;
18+ const DEFAULT_COLOR : Color = [ 0 , 0 , 0 , 255 ] ;
19+
20+ interface LabelTexture {
21+ labelHeight : number ;
22+ labelWidths : number [ ] ;
23+ labelTextureDim : Vec2 ;
24+ labelTexture : Texture ;
25+ }
1626
17- const defaultProps = {
27+ const defaultProps : DefaultProps < AxesLayerProps > = {
1828 data : [ ] ,
1929 fontSize : 12 ,
20- xScale : null ,
21- yScale : null ,
22- zScale : null ,
30+ xScale : undefined ,
31+ yScale : undefined ,
32+ zScale : undefined ,
2333 xTicks : DEFAULT_TICK_COUNT ,
2434 yTicks : DEFAULT_TICK_COUNT ,
2535 zTicks : DEFAULT_TICK_COUNT ,
26- xTickFormat : DEFAULT_TICK_FORMAT ,
27- yTickFormat : DEFAULT_TICK_FORMAT ,
28- zTickFormat : DEFAULT_TICK_FORMAT ,
36+ xTickFormat : DEFAULT_TICK_FORMAT as TickFormat ,
37+ yTickFormat : DEFAULT_TICK_FORMAT as TickFormat ,
38+ zTickFormat : DEFAULT_TICK_FORMAT as TickFormat ,
2939 padding : 0 ,
30- color : [ 0 , 0 , 0 , 255 ] ,
40+ color : DEFAULT_COLOR ,
3141 xTitle : 'x' ,
3242 yTitle : 'y' ,
3343 zTitle : 'z'
3444} ;
3545
36- /* Utils */
37- function flatten ( arrayOfArrays ) {
38- const flatArray = arrayOfArrays . reduce ( ( acc , arr ) => acc . concat ( arr ) , [ ] ) ;
39- if ( Array . isArray ( flatArray [ 0 ] ) ) {
40- return flatten ( flatArray ) ;
41- }
42- return flatArray ;
43- }
44-
45- function getTicks ( props ) {
46- const { axis} = props ;
47- let ticks = props [ `${ axis } Ticks` ] ;
48- const scale = props [ `${ axis } Scale` ] ;
49- const tickFormat = props [ `${ axis } TickFormat` ] ;
50-
51- if ( ! Array . isArray ( ticks ) ) {
52- ticks = scale . ticks ( ticks ) ;
53- }
54-
55- const titleTick = {
56- value : props [ `${ axis } Title` ] ,
57- position : ( scale . range ( ) [ 0 ] + scale . range ( ) [ 1 ] ) / 2 ,
58- text : props [ `${ axis } Title` ]
59- } ;
60-
61- return [
62- ...ticks . map ( t => ( {
63- value : t ,
64- position : scale ( t ) ,
65- text : tickFormat ( t , axis )
66- } ) ) ,
67- titleTick
68- ] ;
69- }
46+ /** All props supported by AxesLayer. */
47+ export type AxesLayerProps < DataT = unknown > = _AxesLayerProps < DataT > & LayerProps ;
48+
49+ type _AxesLayerProps < DataT > = {
50+ data : LayerDataSource < DataT > ;
51+ fontSize : number ;
52+ xScale : ScaleLinear < number , number > ;
53+ yScale : ScaleLinear < number , number > ;
54+ zScale : ScaleLinear < number , number > ;
55+ xTicks : number ;
56+ yTicks : number ;
57+ zTicks : number ;
58+ xTickFormat : TickFormat < DataT > ;
59+ yTickFormat : TickFormat < DataT > ;
60+ zTickFormat : TickFormat < DataT > ;
61+ padding : 0 ;
62+ color : Color ;
63+ xTitle : string ;
64+ yTitle : string ;
65+ zTitle : string ;
66+ } ;
7067
7168/*
7269 * @classdesc
@@ -93,30 +90,38 @@ function getTicks(props) {
9390 * @param {Number } [props.fontSize] - size of the labels
9491 * @param {Array } [props.color] - color of the gridlines, in [r,g,b,a]
9592 */
96- export default class AxesLayer extends Layer {
93+ export default class AxesLayer < DataT = any , ExtraPropsT extends { } = { } > extends Layer <
94+ ExtraPropsT & Required < _AxesLayerProps < DataT > >
95+ > {
96+ static layerName = 'AxesLayer' ;
97+ static defaultProps = defaultProps ;
98+
99+ // @ts -ignore
100+ state ! : Layer [ 'state' ] & {
101+ models : [ Model , Model ] ;
102+ modelsByName : { grids : Model ; labels : Model } ;
103+ numInstances : number ;
104+ ticks : [ Tick [ ] , Tick [ ] , Tick [ ] ] ;
105+ gridDims : Vec3 ;
106+ gridCenter : Vec3 ;
107+ labelTexture : LabelTexture | null ;
108+ } ;
109+
97110 initializeState ( ) {
98111 const { gl} = this . context ;
99- const attributeManager = this . getAttributeManager ( ) ;
112+ const attributeManager = this . getAttributeManager ( ) ! ;
100113
101114 attributeManager . addInstanced ( {
102115 instancePositions : { size : 2 , update : this . calculateInstancePositions , noAlloc : true } ,
103116 instanceNormals : { size : 3 , update : this . calculateInstanceNormals , noAlloc : true } ,
104117 instanceIsTitle : { size : 1 , update : this . calculateInstanceIsTitle , noAlloc : true }
105118 } ) ;
106119
107- this . setState (
108- Object . assign (
109- {
110- numInstances : 0 ,
111- labels : null
112- } ,
113- this . _getModels ( gl )
114- )
115- ) ;
120+ this . setState ( Object . assign ( { numInstances : 0 } , this . _getModels ( gl ) ) ) ;
116121 }
117122
118123 updateState ( { oldProps, props, changeFlags} ) {
119- const attributeManager = this . getAttributeManager ( ) ;
124+ const attributeManager = this . getAttributeManager ( ) ! ;
120125
121126 if (
122127 oldProps . xScale !== props . xScale ||
@@ -157,7 +162,8 @@ export default class AxesLayer extends Layer {
157162 }
158163
159164 draw ( { uniforms} ) {
160- const { gridDims, gridCenter, modelsByName, labelTexture, numInstances} = this . state ;
165+ const { gridDims, gridCenter, modelsByName, numInstances} = this . state ;
166+ const { labelTexture, ...labelTextureUniforms } = this . state . labelTexture ! ;
161167 const { fontSize, color, padding} = this . props ;
162168
163169 if ( labelTexture ) {
@@ -172,10 +178,14 @@ export default class AxesLayer extends Layer {
172178 modelsByName . grids . setInstanceCount ( numInstances ) ;
173179 modelsByName . labels . setInstanceCount ( numInstances ) ;
174180
175- modelsByName . grids . setUniforms ( Object . assign ( { } , uniforms , baseUniforms ) ) . draw ( ) ;
176- modelsByName . labels
177- . setUniforms ( Object . assign ( { } , uniforms , baseUniforms , labelTexture ) )
178- . draw ( ) ;
181+ modelsByName . grids . setUniforms ( Object . assign ( { } , uniforms , baseUniforms ) ) ;
182+ modelsByName . labels . setBindings ( { labelTexture} ) ;
183+ modelsByName . labels . setUniforms (
184+ Object . assign ( { } , uniforms , baseUniforms , labelTextureUniforms )
185+ ) ;
186+
187+ modelsByName . grids . draw ( this . context . renderPass ) ;
188+ modelsByName . labels . draw ( this . context . renderPass ) ;
179189 }
180190 }
181191
@@ -222,29 +232,29 @@ export default class AxesLayer extends Layer {
222232 0 , - 1 , 0 , 0 , - 1 , 0
223233 ] ;
224234
225- const grids = new Model ( gl , {
235+ const grids = new Model ( gl . device , {
226236 id : `${ this . props . id } -grids` ,
227237 vs : gridVertex ,
228238 fs : fragmentShader ,
239+ bufferLayout : this . getAttributeManager ( ) ! . getBufferLayouts ( ) ,
229240 geometry : new Geometry ( {
230241 topology : 'line-list' ,
231242 attributes : {
232- positions : new Float32Array ( gridPositions ) ,
233- normals : new Float32Array ( gridNormals )
243+ positions : { value : new Float32Array ( gridPositions ) , size : 3 } ,
244+ normals : { value : new Float32Array ( gridNormals ) , size : 3 }
234245 } ,
235246 vertexCount : gridPositions . length / 3
236- } ) ,
237- isInstanced : true
247+ } )
238248 } ) ;
239249
240250 /* labels
241251 * one label is placed at each end of every grid line
242252 * show/hide is toggled by the vertex shader
243253 */
244- let labelTexCoords = [ ] ;
245- let labelPositions = [ ] ;
246- let labelNormals = [ ] ;
247- let labelIndices = [ ] ;
254+ let labelTexCoords : number [ ] = [ ] ;
255+ let labelPositions : number [ ] = [ ] ;
256+ let labelNormals : number [ ] = [ ] ;
257+ let labelIndices : number [ ] = [ ] ;
248258 for ( let i = 0 ; i < 8 ; i ++ ) {
249259 /*
250260 * each label is rendered as a rectangle
@@ -271,20 +281,20 @@ export default class AxesLayer extends Layer {
271281 }
272282 }
273283
274- const labels = new Model ( gl , {
284+ const labels = new Model ( gl . device , {
275285 id : `${ this . props . id } -labels` ,
276286 vs : labelVertex ,
277287 fs : labelFragment ,
288+ bufferLayout : this . getAttributeManager ( ) ! . getBufferLayouts ( ) ,
278289 geometry : new Geometry ( {
279290 topology : 'triangle-list' ,
280291 attributes : {
281292 indices : new Uint16Array ( labelIndices ) ,
282- positions : new Float32Array ( labelPositions ) ,
283- texCoords : { size : 2 , value : new Float32Array ( labelTexCoords ) } ,
284- normals : new Float32Array ( labelNormals )
293+ positions : { value : new Float32Array ( labelPositions ) , size : 3 } ,
294+ texCoords : { value : new Float32Array ( labelTexCoords ) , size : 2 } ,
295+ normals : { value : new Float32Array ( labelNormals ) , size : 3 }
285296 }
286- } ) ,
287- isInstanced : true
297+ } )
288298 } ) ;
289299
290300 return {
@@ -329,9 +339,9 @@ export default class AxesLayer extends Layer {
329339 attribute . value = new Float32Array ( flatten ( isTitle ) ) ;
330340 }
331341
332- renderLabelTexture ( ticks ) {
333- if ( this . state . labels ) {
334- this . state . labels . labelTexture . delete ( ) ;
342+ renderLabelTexture ( ticks ) : LabelTexture | null {
343+ if ( this . state . labelTexture ) {
344+ this . state . labelTexture . labelTexture . destroy ( ) ;
335345 }
336346
337347 // attach a 2d texture of all the label texts
@@ -351,5 +361,37 @@ export default class AxesLayer extends Layer {
351361 }
352362}
353363
354- AxesLayer . layerName = 'AxesLayer' ;
355- AxesLayer . defaultProps = defaultProps ;
364+ /* Utils */
365+ function flatten ( arrayOfArrays ) {
366+ const flatArray = arrayOfArrays . reduce ( ( acc , arr ) => acc . concat ( arr ) , [ ] ) ;
367+ if ( Array . isArray ( flatArray [ 0 ] ) ) {
368+ return flatten ( flatArray ) ;
369+ }
370+ return flatArray ;
371+ }
372+
373+ function getTicks ( props : AxesLayerProps < number > & { axis : Axis } ) : Tick [ ] {
374+ const { axis} = props ;
375+ let ticks = props [ `${ axis } Ticks` ] as number | number [ ] ;
376+ const scale = props [ `${ axis } Scale` ] ;
377+ const tickFormat = props [ `${ axis } TickFormat` ] ;
378+
379+ if ( ! Array . isArray ( ticks ) ) {
380+ ticks = scale . ticks ( ticks ) as number [ ] ;
381+ }
382+
383+ const titleTick = {
384+ value : props [ `${ axis } Title` ] ,
385+ position : ( scale . range ( ) [ 0 ] + scale . range ( ) [ 1 ] ) / 2 ,
386+ text : props [ `${ axis } Title` ]
387+ } ;
388+
389+ return [
390+ ...ticks . map ( t => ( {
391+ value : String ( t ) ,
392+ position : scale ( t ) ,
393+ text : tickFormat ( t , axis )
394+ } ) ) ,
395+ titleTick
396+ ] ;
397+ }
0 commit comments