@@ -25,14 +25,14 @@ module.exports = function(gd, plotinfo, cdheatmaps) {
25
25
}
26
26
} ;
27
27
28
- // From http://www.xarg.org/2010/03/generate-client-side-png-files-using-javascript/
29
28
function plotOne ( gd , plotinfo , cd ) {
30
- var trace = cd [ 0 ] . trace ,
31
- uid = trace . uid ,
32
- xa = plotinfo . xaxis ,
33
- ya = plotinfo . yaxis ,
34
- fullLayout = gd . _fullLayout ,
35
- id = 'hm' + uid ;
29
+ var cd0 = cd [ 0 ] ;
30
+ var trace = cd0 . trace ;
31
+ var uid = trace . uid ;
32
+ var xa = plotinfo . xaxis ;
33
+ var ya = plotinfo . yaxis ;
34
+ var fullLayout = gd . _fullLayout ;
35
+ var id = 'hm' + uid ;
36
36
37
37
// in case this used to be a contour map
38
38
fullLayout . _paper . selectAll ( '.contour' + uid ) . remove ( ) ;
@@ -45,23 +45,21 @@ function plotOne(gd, plotinfo, cd) {
45
45
return ;
46
46
}
47
47
48
- var z = cd [ 0 ] . z ,
49
- x = cd [ 0 ] . x ,
50
- y = cd [ 0 ] . y ,
51
- isContour = Registry . traceIs ( trace , 'contour' ) ,
52
- zsmooth = isContour ? 'best' : trace . zsmooth ,
53
-
54
- // get z dims
55
- m = z . length ,
56
- n = maxRowLength ( z ) ,
57
- xrev = false ,
58
- left ,
59
- right ,
60
- temp ,
61
- yrev = false ,
62
- top ,
63
- bottom ,
64
- i ;
48
+ var z = cd0 . z ;
49
+ var x = cd0 . x ;
50
+ var y = cd0 . y ;
51
+ var xc = cd0 . xCenter ;
52
+ var yc = cd0 . yCenter ;
53
+ var isContour = Registry . traceIs ( trace , 'contour' ) ;
54
+ var zsmooth = isContour ? 'best' : trace . zsmooth ;
55
+
56
+ // get z dims
57
+ var m = z . length ;
58
+ var n = maxRowLength ( z ) ;
59
+ var xrev = false ;
60
+ var yrev = false ;
61
+
62
+ var left , right , temp , top , bottom , i ;
65
63
66
64
// TODO: if there are multiple overlapping categorical heatmaps,
67
65
// or if we allow category sorting, then the categories may not be
@@ -113,11 +111,10 @@ function plotOne(gd, plotinfo, cd) {
113
111
// for contours with heatmap fill, we generate the boundaries based on
114
112
// brick centers but then use the brick edges for drawing the bricks
115
113
if ( isContour ) {
116
- // TODO: for 'best' smoothing, we really should use the given brick
117
- // centers as well as brick bounds in calculating values, in case of
118
- // nonuniform brick sizes
119
- x = cd [ 0 ] . xfill ;
120
- y = cd [ 0 ] . yfill ;
114
+ xc = x ;
115
+ yc = y ;
116
+ x = cd0 . xfill ;
117
+ y = cd0 . yfill ;
121
118
}
122
119
123
120
// make an image that goes at most half a screen off either side, to keep
@@ -199,30 +196,6 @@ function plotOne(gd, plotinfo, cd) {
199
196
} ;
200
197
}
201
198
202
- // get interpolated bin value. Returns {bin0:closest bin, frac:fractional dist to next, bin1:next bin}
203
- function findInterp ( pixel , pixArray ) {
204
- var maxbin = pixArray . length - 2 ,
205
- bin = Lib . constrain ( Lib . findBin ( pixel , pixArray ) , 0 , maxbin ) ,
206
- pix0 = pixArray [ bin ] ,
207
- pix1 = pixArray [ bin + 1 ] ,
208
- interp = Lib . constrain ( bin + ( pixel - pix0 ) / ( pix1 - pix0 ) - 0.5 , 0 , maxbin ) ,
209
- bin0 = Math . round ( interp ) ,
210
- frac = Math . abs ( interp - bin0 ) ;
211
-
212
- if ( ! interp || interp === maxbin || ! frac ) {
213
- return {
214
- bin0 : bin0 ,
215
- bin1 : bin0 ,
216
- frac : 0
217
- } ;
218
- }
219
- return {
220
- bin0 : bin0 ,
221
- frac : frac ,
222
- bin1 : Math . round ( bin0 + frac / ( interp - bin0 ) )
223
- } ;
224
- }
225
-
226
199
// build the pixel map brick-by-brick
227
200
// cruise through z-matrix row-by-row
228
201
// build a brick at each z-matrix value
@@ -254,13 +227,6 @@ function plotOne(gd, plotinfo, cd) {
254
227
return [ 0 , 0 , 0 , 0 ] ;
255
228
}
256
229
257
- function putColor ( pixels , pxIndex , c ) {
258
- pixels [ pxIndex ] = c [ 0 ] ;
259
- pixels [ pxIndex + 1 ] = c [ 1 ] ;
260
- pixels [ pxIndex + 2 ] = c [ 2 ] ;
261
- pixels [ pxIndex + 3 ] = Math . round ( c [ 3 ] * 255 ) ;
262
- }
263
-
264
230
function interpColor ( r0 , r1 , xinterp , yinterp ) {
265
231
var z00 = r0 [ xinterp . bin0 ] ;
266
232
if ( z00 === undefined ) return setColor ( undefined , 1 ) ;
@@ -303,24 +269,26 @@ function plotOne(gd, plotinfo, cd) {
303
269
}
304
270
305
271
if ( zsmooth === 'best' ) {
306
- var xPixArray = new Array ( x . length ) ,
307
- yPixArray = new Array ( y . length ) ,
308
- xinterpArray = new Array ( imageWidth ) ,
309
- yinterp ,
310
- r0 ,
311
- r1 ;
272
+ var xForPx = xc || x ;
273
+ var yForPx = yc || y ;
274
+ var xPixArray = new Array ( xForPx . length ) ;
275
+ var yPixArray = new Array ( yForPx . length ) ;
276
+ var xinterpArray = new Array ( imageWidth ) ;
277
+ var findInterpX = xc ? findInterpFromCenters : findInterp ;
278
+ var findInterpY = yc ? findInterpFromCenters : findInterp ;
279
+ var yinterp , r0 , r1 ;
312
280
313
281
// first make arrays of x and y pixel locations of brick boundaries
314
- for ( i = 0 ; i < x . length ; i ++ ) xPixArray [ i ] = Math . round ( xa . c2p ( x [ i ] ) - left ) ;
315
- for ( i = 0 ; i < y . length ; i ++ ) yPixArray [ i ] = Math . round ( ya . c2p ( y [ i ] ) - top ) ;
282
+ for ( i = 0 ; i < xForPx . length ; i ++ ) xPixArray [ i ] = Math . round ( xa . c2p ( xForPx [ i ] ) - left ) ;
283
+ for ( i = 0 ; i < yForPx . length ; i ++ ) yPixArray [ i ] = Math . round ( ya . c2p ( yForPx [ i ] ) - top ) ;
316
284
317
285
// then make arrays of interpolations
318
286
// (bin0=closest, bin1=next, frac=fractional dist.)
319
- for ( i = 0 ; i < imageWidth ; i ++ ) xinterpArray [ i ] = findInterp ( i , xPixArray ) ;
287
+ for ( i = 0 ; i < imageWidth ; i ++ ) xinterpArray [ i ] = findInterpX ( i , xPixArray ) ;
320
288
321
289
// now do the interpolations and fill the png
322
290
for ( j = 0 ; j < imageHeight ; j ++ ) {
323
- yinterp = findInterp ( j , yPixArray ) ;
291
+ yinterp = findInterpY ( j , yPixArray ) ;
324
292
r0 = z [ yinterp . bin0 ] ;
325
293
r1 = z [ yinterp . bin1 ] ;
326
294
for ( i = 0 ; i < imageWidth ; i ++ , pxIndex += 4 ) {
@@ -415,3 +383,61 @@ function plotOne(gd, plotinfo, cd) {
415
383
416
384
image3 . exit ( ) . remove ( ) ;
417
385
}
386
+
387
+ // get interpolated bin value. Returns {bin0:closest bin, frac:fractional dist to next, bin1:next bin}
388
+ function findInterp ( pixel , pixArray ) {
389
+ var maxBin = pixArray . length - 2 ;
390
+ var bin = Lib . constrain ( Lib . findBin ( pixel , pixArray ) , 0 , maxBin ) ;
391
+ var pix0 = pixArray [ bin ] ;
392
+ var pix1 = pixArray [ bin + 1 ] ;
393
+ var interp = Lib . constrain ( bin + ( pixel - pix0 ) / ( pix1 - pix0 ) - 0.5 , 0 , maxBin ) ;
394
+ var bin0 = Math . round ( interp ) ;
395
+ var frac = Math . abs ( interp - bin0 ) ;
396
+
397
+ if ( ! interp || interp === maxBin || ! frac ) {
398
+ return {
399
+ bin0 : bin0 ,
400
+ bin1 : bin0 ,
401
+ frac : 0
402
+ } ;
403
+ }
404
+ return {
405
+ bin0 : bin0 ,
406
+ frac : frac ,
407
+ bin1 : Math . round ( bin0 + frac / ( interp - bin0 ) )
408
+ } ;
409
+ }
410
+
411
+ function findInterpFromCenters ( pixel , centerPixArray ) {
412
+ var maxBin = centerPixArray . length - 1 ;
413
+ var bin = Lib . constrain ( Lib . findBin ( pixel , centerPixArray ) , 0 , maxBin ) ;
414
+ var pix0 = centerPixArray [ bin ] ;
415
+ var pix1 = centerPixArray [ bin + 1 ] ;
416
+ var frac = ( ( pixel - pix0 ) / ( pix1 - pix0 ) ) || 0 ;
417
+ if ( frac <= 0 ) {
418
+ return {
419
+ bin0 : bin ,
420
+ bin1 : bin ,
421
+ frac : 0
422
+ } ;
423
+ }
424
+ if ( frac < 0.5 ) {
425
+ return {
426
+ bin0 : bin ,
427
+ bin1 : bin + 1 ,
428
+ frac : frac
429
+ } ;
430
+ }
431
+ return {
432
+ bin0 : bin + 1 ,
433
+ bin1 : bin ,
434
+ frac : 1 - frac
435
+ } ;
436
+ }
437
+
438
+ function putColor ( pixels , pxIndex , c ) {
439
+ pixels [ pxIndex ] = c [ 0 ] ;
440
+ pixels [ pxIndex + 1 ] = c [ 1 ] ;
441
+ pixels [ pxIndex + 2 ] = c [ 2 ] ;
442
+ pixels [ pxIndex + 3 ] = Math . round ( c [ 3 ] * 255 ) ;
443
+ }
0 commit comments