@@ -25,14 +25,14 @@ module.exports = function(gd, plotinfo, cdheatmaps) {
2525 }
2626} ;
2727
28- // From http://www.xarg.org/2010/03/generate-client-side-png-files-using-javascript/
2928function 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 ;
3636
3737 // in case this used to be a contour map
3838 fullLayout . _paper . selectAll ( '.contour' + uid ) . remove ( ) ;
@@ -45,23 +45,21 @@ function plotOne(gd, plotinfo, cd) {
4545 return ;
4646 }
4747
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 ;
6563
6664 // TODO: if there are multiple overlapping categorical heatmaps,
6765 // or if we allow category sorting, then the categories may not be
@@ -113,11 +111,10 @@ function plotOne(gd, plotinfo, cd) {
113111 // for contours with heatmap fill, we generate the boundaries based on
114112 // brick centers but then use the brick edges for drawing the bricks
115113 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 ;
121118 }
122119
123120 // make an image that goes at most half a screen off either side, to keep
@@ -199,30 +196,6 @@ function plotOne(gd, plotinfo, cd) {
199196 } ;
200197 }
201198
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-
226199 // build the pixel map brick-by-brick
227200 // cruise through z-matrix row-by-row
228201 // build a brick at each z-matrix value
@@ -254,13 +227,6 @@ function plotOne(gd, plotinfo, cd) {
254227 return [ 0 , 0 , 0 , 0 ] ;
255228 }
256229
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-
264230 function interpColor ( r0 , r1 , xinterp , yinterp ) {
265231 var z00 = r0 [ xinterp . bin0 ] ;
266232 if ( z00 === undefined ) return setColor ( undefined , 1 ) ;
@@ -303,24 +269,26 @@ function plotOne(gd, plotinfo, cd) {
303269 }
304270
305271 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 ;
312280
313281 // 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 ) ;
316284
317285 // then make arrays of interpolations
318286 // (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 ) ;
320288
321289 // now do the interpolations and fill the png
322290 for ( j = 0 ; j < imageHeight ; j ++ ) {
323- yinterp = findInterp ( j , yPixArray ) ;
291+ yinterp = findInterpY ( j , yPixArray ) ;
324292 r0 = z [ yinterp . bin0 ] ;
325293 r1 = z [ yinterp . bin1 ] ;
326294 for ( i = 0 ; i < imageWidth ; i ++ , pxIndex += 4 ) {
@@ -415,3 +383,61 @@ function plotOne(gd, plotinfo, cd) {
415383
416384 image3 . exit ( ) . remove ( ) ;
417385}
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