@@ -16,6 +16,7 @@ var d3 = require('d3');
1616var Color = require ( '../../components/color' ) ;
1717var Drawing = require ( '../../components/drawing' ) ;
1818var Axes = require ( '../../plots/cartesian/axes' ) ;
19+ var Fx = require ( '../../plots/cartesian/graph_interact' ) ;
1920
2021var addProjectionsToD3 = require ( './projections' ) ;
2122var createGeoScale = require ( './set_scale' ) ;
@@ -32,7 +33,6 @@ addProjectionsToD3(d3);
3233
3334
3435function Geo ( options , fullLayout ) {
35-
3636 this . id = options . id ;
3737 this . graphDiv = options . graphDiv ;
3838 this . container = options . container ;
@@ -53,6 +53,9 @@ function Geo(options, fullLayout) {
5353 this . zoom = null ;
5454 this . zoomReset = null ;
5555
56+ this . xaxis = null ;
57+ this . yaxis = null ;
58+
5659 this . makeFramework ( ) ;
5760 this . updateFx ( fullLayout . hovermode ) ;
5861
@@ -88,6 +91,30 @@ proto.plot = function(geoCalcData, fullLayout, promises) {
8891 . call ( _this . zoom )
8992 . on ( 'dblclick.zoom' , _this . zoomReset ) ;
9093
94+ _this . framework . on ( 'mousemove' , function ( ) {
95+ var mouse = d3 . mouse ( this ) ,
96+ lonlat = _this . projection . invert ( mouse ) ;
97+
98+ if ( isNaN ( lonlat [ 0 ] ) || isNaN ( lonlat [ 1 ] ) ) return ;
99+
100+ var evt = {
101+ target : true ,
102+ xpx : mouse [ 0 ] ,
103+ ypx : mouse [ 1 ]
104+ } ;
105+
106+ _this . xaxis . c2p = function ( ) { return mouse [ 0 ] ; } ;
107+ _this . xaxis . p2c = function ( ) { return lonlat [ 0 ] ; } ;
108+ _this . yaxis . c2p = function ( ) { return mouse [ 1 ] ; } ;
109+ _this . yaxis . p2c = function ( ) { return lonlat [ 1 ] ; } ;
110+
111+ Fx . hover ( _this . graphDiv , evt , _this . id ) ;
112+ } ) ;
113+
114+ _this . framework . on ( 'click' , function ( ) {
115+ Fx . click ( _this . graphDiv , { target : true } ) ;
116+ } ) ;
117+
91118 topojsonNameNew = topojsonUtils . getTopojsonName ( geoLayout ) ;
92119
93120 if ( _this . topojson === null || topojsonNameNew !== _this . topojsonName ) {
@@ -265,6 +292,8 @@ proto.makeFramework = function() {
265292 . attr ( 'id' , this . id )
266293 . style ( 'position' , 'absolute' ) ;
267294
295+ // only choropleth traces use this,
296+ // scattergeo traces use Fx.hover and fullLayout._hoverlayer
268297 var hoverContainer = this . hoverContainer = geoDiv . append ( 'svg' ) ;
269298 hoverContainer
270299 . attr ( xmlnsNamespaces . svgAttrs )
@@ -294,14 +323,20 @@ proto.makeFramework = function() {
294323 framework . on ( 'dblclick.zoom' , null ) ;
295324
296325 // TODO use clip paths instead of nested SVG
326+
327+ this . xaxis = { _id : 'x' } ;
328+ this . yaxis = { _id : 'y' } ;
297329} ;
298330
299331proto . adjustLayout = function ( geoLayout , graphSize ) {
300332 var domain = geoLayout . domain ;
301333
334+ var left = graphSize . l + graphSize . w * domain . x [ 0 ] + geoLayout . _marginX ,
335+ top = graphSize . t + graphSize . h * ( 1 - domain . y [ 1 ] ) + geoLayout . _marginY ;
336+
302337 this . geoDiv . style ( {
303- left : graphSize . l + graphSize . w * domain . x [ 0 ] + geoLayout . _marginX + 'px' ,
304- top : graphSize . t + graphSize . h * ( 1 - domain . y [ 1 ] ) + geoLayout . _marginY + 'px' ,
338+ left : left + 'px' ,
339+ top : top + 'px' ,
305340 width : geoLayout . _width + 'px' ,
306341 height : geoLayout . _height + 'px'
307342 } ) ;
@@ -322,6 +357,12 @@ proto.adjustLayout = function(geoLayout, graphSize) {
322357 height : geoLayout . _height
323358 } )
324359 . call ( Color . fill , geoLayout . bgcolor ) ;
360+
361+ this . xaxis . _offset = left ;
362+ this . xaxis . _length = geoLayout . _width ;
363+
364+ this . yaxis . _offset = top ;
365+ this . yaxis . _length = geoLayout . _height ;
325366} ;
326367
327368proto . drawTopo = function ( selection , layerName , geoLayout ) {
@@ -445,27 +486,36 @@ proto.styleLayout = function(geoLayout) {
445486 }
446487} ;
447488
489+ proto . isLonLatOverEdges = function ( lonlat ) {
490+ var clipAngle = this . clipAngle ;
491+
492+ if ( clipAngle === null ) return false ;
493+
494+ var p = this . projection . rotate ( ) ,
495+ angle = d3 . geo . distance ( lonlat , [ - p [ 0 ] , - p [ 1 ] ] ) ,
496+ maxAngle = clipAngle * Math . PI / 180 ;
497+
498+ return angle > maxAngle ;
499+ } ;
500+
448501// [hot code path] (re)draw all paths which depend on the projection
449502proto . render = function ( ) {
450- var framework = this . framework ,
503+ var _this = this ,
504+ framework = _this . framework ,
451505 gChoropleth = framework . select ( 'g.choroplethlayer' ) ,
452506 gScatterGeo = framework . select ( 'g.scattergeolayer' ) ,
453- projection = this . projection ,
454- path = this . path ,
455- clipAngle = this . clipAngle ;
507+ path = _this . path ;
456508
457509 function translatePoints ( d ) {
458- var lonlat = projection ( [ d . lon , d . lat ] ) ;
459- if ( ! lonlat ) return null ;
460- return 'translate(' + lonlat [ 0 ] + ',' + lonlat [ 1 ] + ')' ;
510+ var lonlatPx = _this . projection ( d . lonlat ) ;
511+ if ( ! lonlatPx ) return null ;
512+
513+ return 'translate(' + lonlatPx [ 0 ] + ',' + lonlatPx [ 1 ] + ')' ;
461514 }
462515
463516 // hide paths over edges of clipped projections
464517 function hideShowPoints ( d ) {
465- var p = projection . rotate ( ) ,
466- angle = d3 . geo . distance ( [ d . lon , d . lat ] , [ - p [ 0 ] , - p [ 1 ] ] ) ,
467- maxAngle = clipAngle * Math . PI / 180 ;
468- return ( angle > maxAngle ) ? '0' : '1.0' ;
518+ return _this . isLonLatOverEdges ( d . lonlat ) ? '0' : '1.0' ;
469519 }
470520
471521 framework . selectAll ( 'path.basepath' ) . attr ( 'd' , path ) ;
@@ -476,7 +526,7 @@ proto.render = function() {
476526
477527 gScatterGeo . selectAll ( 'path.js-line' ) . attr ( 'd' , path ) ;
478528
479- if ( clipAngle !== null ) {
529+ if ( _this . clipAngle !== null ) {
480530 gScatterGeo . selectAll ( 'path.point' )
481531 . style ( 'opacity' , hideShowPoints )
482532 . attr ( 'transform' , translatePoints ) ;
0 commit comments