8
8
9
9
'use strict' ;
10
10
11
- var d3 = require ( 'd3' ) ;
12
11
var createREGL = require ( 'regl' ) ;
13
12
var glslify = require ( 'glslify' ) ;
14
13
var vertexShaderSource = glslify ( './shaders/vertex.glsl' ) ;
@@ -17,6 +16,10 @@ var fragmentShaderSource = glslify('./shaders/fragment.glsl');
17
16
var depthLimitEpsilon = 1e-6 ; // don't change; otherwise near/far plane lines are lost
18
17
var filterEpsilon = 1e-3 ; // don't change; otherwise filter may lose lines on domain boundaries
19
18
19
+ var gpuDimensionCount = 64 ;
20
+ var sectionVertexCount = 2 ;
21
+ var vec4NumberCount = 4 ;
22
+
20
23
var dummyPixel = new Uint8Array ( 4 ) ;
21
24
function ensureDraw ( regl ) {
22
25
regl . read ( {
@@ -51,8 +54,8 @@ function renderBlock(regl, glAes, renderState, blockLineCount, sampleCount, item
51
54
52
55
count = Math . min ( blockLineCount , sampleCount - blockNumber * blockLineCount ) ;
53
56
54
- item . offset = 2 * blockNumber * blockLineCount ;
55
- item . count = 2 * count ;
57
+ item . offset = sectionVertexCount * blockNumber * blockLineCount ;
58
+ item . count = sectionVertexCount * count ;
56
59
if ( blockNumber === 0 ) {
57
60
window . cancelAnimationFrame ( renderState . currentRafs [ rafKey ] ) ; // stop drawing possibly stale glyphs before clearing
58
61
clear ( regl , item . scissorX , 0 , item . scissorWidth , item . viewBoxSize [ 1 ] ) ;
@@ -77,77 +80,93 @@ function renderBlock(regl, glAes, renderState, blockLineCount, sampleCount, item
77
80
render ( blockNumber ) ;
78
81
}
79
82
80
- module . exports = function ( canvasGL , lines , canvasWidth , canvasHeight , data , unitToColor , context ) {
81
-
82
- var renderState = {
83
- currentRafs : { } ,
84
- drawCompleted : true ,
85
- clearOnly : false
86
- } ;
87
-
88
- var dimensions = data ;
89
- var dimensionCount = dimensions . length ;
90
- var sampleCount = dimensions [ 0 ] . values . length ;
91
-
92
- var focusAlphaBlending = context ; // controlConfig.focusAlphaBlending;
93
-
94
- var canvasPixelRatio = lines . pixelratio ;
95
- var canvasPanelSizeY = canvasHeight ;
83
+ function adjustDepth ( d ) {
84
+ // WebGL matrix operations use floats with limited precision, potentially causing a number near a border of [0, 1]
85
+ // to end up slightly outside the border. With an epsilon, we reduce the chance that a line gets clipped by the
86
+ // near or the far plane.
87
+ return Math . max ( depthLimitEpsilon , Math . min ( 1 - depthLimitEpsilon , d ) ) ;
88
+ }
96
89
97
- var gpuDimensionCount = 64 ;
98
- var strideableVectorAttributeCount = gpuDimensionCount - 4 ; // stride can't be an exact 256
90
+ function palette ( unitToColor , context , lines_contextcolor , lines_contextopacity ) {
91
+ var result = [ ] ;
92
+ for ( var j = 0 ; j < 256 ; j ++ ) {
93
+ var c = unitToColor ( j / 255 ) ;
94
+ result . push ( ( context ? lines_contextcolor : c ) . concat ( [ context ? lines_contextopacity : 255 ] ) ) ;
95
+ }
99
96
100
- var paddedUnit = function paddedUnit ( d ) {
101
- var unitPad = lines . verticalpadding / canvasPanelSizeY ;
102
- return unitPad + d * ( 1 - 2 * unitPad ) ;
103
- } ;
97
+ return result ;
98
+ }
104
99
105
- var color = lines . color . map ( paddedUnit ) ;
106
- var overdrag = lines . overdrag * canvasPixelRatio ;
100
+ function makePoints ( sampleCount , dimensionCount , dimensions , color ) {
107
101
108
102
var points = [ ] ;
109
- var i , j ;
110
- for ( j = 0 ; j < sampleCount ; j ++ ) {
111
- for ( i = 0 ; i < strideableVectorAttributeCount ; i ++ ) {
112
- points . push ( i < dimensionCount ? paddedUnit ( dimensions [ i ] . domainToUnitScale ( data [ i ] . values [ j ] ) ) : 0.5 ) ;
103
+ for ( var j = 0 ; j < sampleCount ; j ++ ) {
104
+ for ( var i = 0 ; i < gpuDimensionCount ; i ++ ) {
105
+ points . push ( i < dimensionCount ?
106
+ dimensions [ i ] . paddedUnitValues [ j ] :
107
+ i === ( gpuDimensionCount - 1 ) ?
108
+ adjustDepth ( color [ j ] ) :
109
+ 0.5 ) ;
113
110
}
114
111
}
115
112
113
+ return points ;
114
+ }
115
+
116
+ function makeVecAttr ( sampleCount , points , vecIndex ) {
117
+
118
+ var i , j , k ;
116
119
var pointPairs = [ ] ;
117
120
118
121
for ( j = 0 ; j < sampleCount ; j ++ ) {
119
- for ( i = 0 ; i < strideableVectorAttributeCount ; i ++ ) {
120
- pointPairs . push ( points [ j * strideableVectorAttributeCount + i ] ) ;
121
- }
122
- for ( i = 0 ; i < strideableVectorAttributeCount ; i ++ ) {
123
- pointPairs . push ( points [ j * strideableVectorAttributeCount + i ] ) ;
122
+ for ( k = 0 ; k < sectionVertexCount ; k ++ ) {
123
+ for ( i = 0 ; i < vec4NumberCount ; i ++ ) {
124
+ pointPairs . push ( points [ j * gpuDimensionCount + vecIndex * vec4NumberCount + i ] ) ;
125
+ if ( vecIndex * vec4NumberCount + i === gpuDimensionCount - 1 && k % 2 === 0 ) {
126
+ pointPairs [ pointPairs . length - 1 ] *= - 1 ;
127
+ }
128
+ }
124
129
}
125
130
}
126
131
127
- function adjustDepth ( d ) {
128
- return Math . max ( depthLimitEpsilon , Math . min ( 1 - depthLimitEpsilon , d ) ) ;
129
- }
132
+ return pointPairs ;
133
+ }
130
134
131
- var ccolor = [ ] ;
132
- for ( j = 0 ; j < 256 ; j ++ ) {
133
- var c = unitToColor ( j / 255 ) ;
134
- ccolor . push ( ( focusAlphaBlending ? lines . contextcolor : c ) . concat ( [ focusAlphaBlending ? lines . contextopacity : 255 ] ) ) ;
135
- }
135
+ function makeAttributes ( sampleCount , points ) {
136
136
137
- var styling = [ ] ;
138
- for ( j = 0 ; j < sampleCount ; j ++ ) {
139
- for ( var k = 0 ; k < 2 ; k ++ ) {
140
- styling . push ( points [ ( j + 1 ) * strideableVectorAttributeCount ] ) ;
141
- styling . push ( points [ ( j + 1 ) * strideableVectorAttributeCount + 1 ] ) ;
142
- styling . push ( points [ ( j + 1 ) * strideableVectorAttributeCount + 2 ] ) ;
143
- styling . push ( Math . round ( 2 * ( ( k % 2 ) - 0.5 ) ) * adjustDepth ( color [ j ] ) ) ;
144
- }
145
- }
137
+ var vecIndices = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 ] ;
138
+ var vectors = vecIndices . map ( function ( vecIndex ) { return makeVecAttr ( sampleCount , points , vecIndex ) ; } ) ;
139
+
140
+ var attributes = { } ;
141
+ vectors . forEach ( function ( v , vecIndex ) {
142
+ attributes [ 'p' + vecIndex . toString ( 16 ) ] = v ;
143
+ } ) ;
144
+
145
+ return attributes ;
146
+ }
147
+
148
+ module . exports = function ( canvasGL , lines , canvasWidth , canvasHeight , dimensions , unitToColor , context ) {
149
+
150
+ var renderState = {
151
+ currentRafs : { } ,
152
+ drawCompleted : true ,
153
+ clearOnly : false
154
+ } ;
146
155
147
- var positionStride = strideableVectorAttributeCount * 4 ;
156
+ var dimensionCount = dimensions . length ;
157
+ var sampleCount = dimensions [ 0 ] . values . length ;
148
158
149
- var shownDimensionCount = dimensionCount ;
150
- var shownPanelCount = shownDimensionCount - 1 ;
159
+ var focusAlphaBlending = context ; // controlConfig.focusAlphaBlending;
160
+
161
+ var canvasPanelSizeY = canvasHeight ;
162
+
163
+ var color = lines . color ;
164
+ var overdrag = lines . canvasOverdrag ;
165
+
166
+ var panelCount = dimensionCount - 1 ;
167
+
168
+ var points = makePoints ( sampleCount , dimensionCount , dimensions , color ) ;
169
+ var attributes = makeAttributes ( sampleCount , points ) ;
151
170
152
171
var regl = createREGL ( {
153
172
canvas : canvasGL ,
@@ -162,23 +181,9 @@ module.exports = function(canvasGL, lines, canvasWidth, canvasHeight, data, unit
162
181
type : 'uint8' ,
163
182
mag : 'nearest' ,
164
183
min : 'nearest' ,
165
- data : ccolor
184
+ data : palette ( unitToColor , context , lines . contextcolor , lines . contextopacity )
166
185
} ) ;
167
186
168
- var positionBuffer = regl . buffer ( new Float32Array ( pointPairs ) ) ;
169
-
170
- var attributes = {
171
- pf : styling
172
- } ;
173
-
174
- for ( i = 0 ; i < strideableVectorAttributeCount / 4 ; i ++ ) {
175
- attributes [ 'p' + i . toString ( 16 ) ] = {
176
- offset : i * 16 ,
177
- stride : positionStride ,
178
- buffer : positionBuffer
179
- } ;
180
- }
181
-
182
187
var glAes = regl ( {
183
188
184
189
profile : false ,
@@ -265,36 +270,29 @@ module.exports = function(canvasGL, lines, canvasWidth, canvasHeight, data, unit
265
270
colorClamp [ 1 ] = unitDomain [ 1 ] ;
266
271
}
267
272
268
- function approach ( /* dimension */ ) {
269
- // console.log('Approached ', JSON.stringify(dimension.name));
270
- }
271
-
272
273
var previousAxisOrder = [ ] ;
273
274
274
- var dims = d3 . range ( 2 ) . map ( function ( ) { return d3 . range ( 4 ) . map ( function ( ) { return new Float32Array ( 16 ) ; } ) ; } ) ;
275
- var lims = d3 . range ( 2 ) . map ( function ( ) { return d3 . range ( 4 ) . map ( function ( ) { return new Float32Array ( 16 ) ; } ) ; } ) ;
276
-
277
- function renderGLParcoords ( dimensionViews , setChanged , clearOnly ) {
275
+ function renderGLParcoords ( dimensions , setChanged , clearOnly ) {
278
276
279
277
var I ;
280
278
281
279
function valid ( i , offset ) {
282
- return i < shownDimensionCount && i + offset < dimensionViews . length ;
280
+ return i + offset < dimensions . length ;
283
281
}
284
282
285
283
function orig ( i ) {
286
- var index = dimensionViews . map ( function ( v ) { return v . originalXIndex ; } ) . indexOf ( i ) ;
287
- return dimensionViews [ index ] ;
284
+ var index = dimensions . map ( function ( v ) { return v . originalXIndex ; } ) . indexOf ( i ) ;
285
+ return dimensions [ index ] ;
288
286
}
289
287
290
288
var leftmostIndex , rightmostIndex , lowestX = Infinity , highestX = - Infinity ;
291
- for ( I = 0 ; I < shownPanelCount ; I ++ ) {
292
- if ( dimensionViews [ I ] . x > highestX ) {
293
- highestX = dimensionViews [ I ] . x ;
289
+ for ( I = 0 ; I < panelCount ; I ++ ) {
290
+ if ( dimensions [ I ] . canvasX > highestX ) {
291
+ highestX = dimensions [ I ] . canvasX ;
294
292
rightmostIndex = I ;
295
293
}
296
- if ( dimensionViews [ I ] . x < lowestX ) {
297
- lowestX = dimensionViews [ I ] . x ;
294
+ if ( dimensions [ I ] . canvasX < lowestX ) {
295
+ lowestX = dimensions [ I ] . canvasX ;
298
296
leftmostIndex = I ;
299
297
}
300
298
}
@@ -303,12 +301,15 @@ module.exports = function(canvasGL, lines, canvasWidth, canvasHeight, data, unit
303
301
var loHi , abcd , d , index ;
304
302
var leftRight = [ i , ii ] ;
305
303
304
+ var dims = [ 0 , 1 ] . map ( function ( ) { return [ 0 , 1 , 2 , 3 ] . map ( function ( ) { return new Float32Array ( 16 ) ; } ) ; } ) ;
305
+ var lims = [ 0 , 1 ] . map ( function ( ) { return [ 0 , 1 , 2 , 3 ] . map ( function ( ) { return new Float32Array ( 16 ) ; } ) ; } ) ;
306
+
306
307
for ( loHi = 0 ; loHi < 2 ; loHi ++ ) {
307
308
index = leftRight [ loHi ] ;
308
309
for ( abcd = 0 ; abcd < 4 ; abcd ++ ) {
309
310
for ( d = 0 ; d < 16 ; d ++ ) {
310
311
dims [ loHi ] [ abcd ] [ d ] = d + 16 * abcd === index ? 1 : 0 ;
311
- lims [ loHi ] [ abcd ] [ d ] = paddedUnit ( ( ! context && valid ( d , 16 * abcd ) ? orig ( d + 16 * abcd ) . filter [ loHi ] : loHi ) ) + ( 2 * loHi - 1 ) * filterEpsilon ;
312
+ lims [ loHi ] [ abcd ] [ d ] = ( ! context && valid ( d , 16 * abcd ) ? orig ( d + 16 * abcd ) . filter [ loHi ] : loHi ) + ( 2 * loHi - 1 ) * filterEpsilon ;
312
313
}
313
314
}
314
315
}
@@ -344,30 +345,25 @@ module.exports = function(canvasGL, lines, canvasWidth, canvasHeight, data, unit
344
345
} ;
345
346
}
346
347
347
- for ( I = 0 ; I < shownPanelCount ; I ++ ) {
348
- var dimensionView = dimensionViews [ I ] ;
349
- var i = dimensionView . originalXIndex ;
350
- var x = dimensionView . x * canvasPixelRatio ;
351
- var nextDim = dimensionViews [ ( I + 1 ) % shownDimensionCount ] ;
348
+ for ( I = 0 ; I < panelCount ; I ++ ) {
349
+ var dimension = dimensions [ I ] ;
350
+ var i = dimension . originalXIndex ;
351
+ var x = dimension . canvasX ;
352
+ var nextDim = dimensions [ ( I + 1 ) % dimensionCount ] ;
352
353
var ii = nextDim . originalXIndex ;
353
- var panelSizeX = nextDim . x * canvasPixelRatio - x ;
354
- if ( setChanged || ! previousAxisOrder [ i ] || previousAxisOrder [ i ] [ 0 ] !== x || previousAxisOrder [ i ] [ 1 ] !== nextDim . x ) {
355
- previousAxisOrder [ i ] = [ x , nextDim . x ] ;
356
- var item = makeItem ( i , ii , x , panelSizeX , dimensionView . originalXIndex , dimensionView . scatter ) ;
354
+ var panelSizeX = nextDim . canvasX - x ;
355
+ if ( setChanged || ! previousAxisOrder [ i ] || previousAxisOrder [ i ] [ 0 ] !== x || previousAxisOrder [ i ] [ 1 ] !== nextDim . canvasX ) {
356
+ previousAxisOrder [ i ] = [ x , nextDim . canvasX ] ;
357
+ var item = makeItem ( i , ii , x , panelSizeX , dimension . originalXIndex , dimension . scatter ) ;
357
358
renderState . clearOnly = clearOnly ;
358
359
renderBlock ( regl , glAes , renderState , setChanged ? lines . blocklinecount : sampleCount , sampleCount , item ) ;
359
360
}
360
361
}
361
362
}
362
363
363
- function destroy ( ) {
364
- regl . destroy ( ) ;
365
- }
366
-
367
364
return {
368
365
setColorDomain : setColorDomain ,
369
- approach : approach ,
370
366
render : renderGLParcoords ,
371
- destroy : destroy
367
+ destroy : regl . destroy
372
368
} ;
373
369
} ;
0 commit comments