1111
1212var mouseChange = require ( 'mouse-change' ) ;
1313var mouseWheel = require ( 'mouse-wheel' ) ;
14+ var cartesianConstants = require ( '../cartesian/constants' ) ;
1415
1516module . exports = createCamera ;
1617
@@ -22,8 +23,10 @@ function Camera2D(element, plot) {
2223 this . lastInputTime = Date . now ( ) ;
2324 this . lastPos = [ 0 , 0 ] ;
2425 this . boxEnabled = false ;
26+ this . boxInited = false ;
2527 this . boxStart = [ 0 , 0 ] ;
2628 this . boxEnd = [ 0 , 0 ] ;
29+ this . dragStart = [ 0 , 0 ] ;
2730}
2831
2932
@@ -37,13 +40,33 @@ function createCamera(scene) {
3740 scene . yaxis . autorange = false ;
3841 }
3942
43+ function getSubplotConstraint ( ) {
44+ // note: this assumes we only have one x and one y axis on this subplot
45+ // when this constraint is lifted this block won't make sense
46+ var constraints = scene . graphDiv . _fullLayout . _axisConstraintGroups ;
47+ var xaId = scene . xaxis . _id ;
48+ var yaId = scene . yaxis . _id ;
49+ for ( var i = 0 ; i < constraints . length ; i ++ ) {
50+ if ( constraints [ i ] [ xaId ] !== - 1 ) {
51+ if ( constraints [ i ] [ yaId ] !== - 1 ) return true ;
52+ break ;
53+ }
54+ }
55+ return false ;
56+ }
57+
4058 result . mouseListener = mouseChange ( element , function ( buttons , x , y ) {
4159 var dataBox = scene . calcDataBox ( ) ,
4260 viewBox = plot . viewBox ;
4361
4462 var lastX = result . lastPos [ 0 ] ,
4563 lastY = result . lastPos [ 1 ] ;
4664
65+ var MINDRAG = cartesianConstants . MINDRAG * plot . pixelRatio ;
66+ var MINZOOM = cartesianConstants . MINZOOM * plot . pixelRatio ;
67+
68+ var dx , dy ;
69+
4770 x *= plot . pixelRatio ;
4871 y *= plot . pixelRatio ;
4972
@@ -76,32 +99,114 @@ function createCamera(scene) {
7699 ( viewBox [ 3 ] - viewBox [ 1 ] ) * ( dataBox [ 3 ] - dataBox [ 1 ] ) +
77100 dataBox [ 1 ] ;
78101
79- if ( ! result . boxEnabled ) {
102+ if ( ! result . boxInited ) {
80103 result . boxStart [ 0 ] = dataX ;
81104 result . boxStart [ 1 ] = dataY ;
105+ result . dragStart [ 0 ] = x ;
106+ result . dragStart [ 1 ] = y ;
82107 }
83108
84109 result . boxEnd [ 0 ] = dataX ;
85110 result . boxEnd [ 1 ] = dataY ;
86111
87- result . boxEnabled = true ;
112+ // we need to mark the box as initialized right away
113+ // so that we can tell the start and end pionts apart
114+ result . boxInited = true ;
115+
116+ // but don't actually enable the box until the cursor moves
117+ if ( ! result . boxEnabled && (
118+ result . boxStart [ 0 ] !== result . boxEnd [ 0 ] ||
119+ result . boxStart [ 1 ] !== result . boxEnd [ 1 ] )
120+ ) {
121+ result . boxEnabled = true ;
122+ }
123+
124+ // constrain aspect ratio if the axes require it
125+ var smallDx = Math . abs ( result . dragStart [ 0 ] - x ) < MINZOOM ;
126+ var smallDy = Math . abs ( result . dragStart [ 1 ] - y ) < MINZOOM ;
127+ if ( getSubplotConstraint ( ) && ! ( smallDx && smallDy ) ) {
128+ dx = result . boxEnd [ 0 ] - result . boxStart [ 0 ] ;
129+ dy = result . boxEnd [ 1 ] - result . boxStart [ 1 ] ;
130+ var dydx = ( dataBox [ 3 ] - dataBox [ 1 ] ) / ( dataBox [ 2 ] - dataBox [ 0 ] ) ;
131+
132+ if ( Math . abs ( dx * dydx ) > Math . abs ( dy ) ) {
133+ result . boxEnd [ 1 ] = result . boxStart [ 1 ] +
134+ Math . abs ( dx ) * dydx * ( Math . sign ( dy ) || 1 ) ;
135+
136+ // gl-select-box clips to the plot area bounds,
137+ // which breaks the axis constraint, so don't allow
138+ // this box to go out of bounds
139+ if ( result . boxEnd [ 1 ] < dataBox [ 1 ] ) {
140+ result . boxEnd [ 1 ] = dataBox [ 1 ] ;
141+ result . boxEnd [ 0 ] = result . boxStart [ 0 ] +
142+ ( dataBox [ 1 ] - result . boxStart [ 1 ] ) / Math . abs ( dydx ) ;
143+ }
144+ else if ( result . boxEnd [ 1 ] > dataBox [ 3 ] ) {
145+ result . boxEnd [ 1 ] = dataBox [ 3 ] ;
146+ result . boxEnd [ 0 ] = result . boxStart [ 0 ] +
147+ ( dataBox [ 3 ] - result . boxStart [ 1 ] ) / Math . abs ( dydx ) ;
148+ }
149+ }
150+ else {
151+ result . boxEnd [ 0 ] = result . boxStart [ 0 ] +
152+ Math . abs ( dy ) / dydx * ( Math . sign ( dx ) || 1 ) ;
153+
154+ if ( result . boxEnd [ 0 ] < dataBox [ 0 ] ) {
155+ result . boxEnd [ 0 ] = dataBox [ 0 ] ;
156+ result . boxEnd [ 1 ] = result . boxStart [ 1 ] +
157+ ( dataBox [ 0 ] - result . boxStart [ 0 ] ) * Math . abs ( dydx ) ;
158+ }
159+ else if ( result . boxEnd [ 0 ] > dataBox [ 2 ] ) {
160+ result . boxEnd [ 0 ] = dataBox [ 2 ] ;
161+ result . boxEnd [ 1 ] = result . boxStart [ 1 ] +
162+ ( dataBox [ 2 ] - result . boxStart [ 0 ] ) * Math . abs ( dydx ) ;
163+ }
164+ }
165+ }
166+ // otherwise clamp small changes to the origin so we get 1D zoom
167+ else {
168+ if ( smallDx ) result . boxEnd [ 0 ] = result . boxStart [ 0 ] ;
169+ if ( smallDy ) result . boxEnd [ 1 ] = result . boxStart [ 1 ] ;
170+ }
88171 }
89172 else if ( result . boxEnabled ) {
90- updateRange ( 0 , result . boxStart [ 0 ] , result . boxEnd [ 0 ] ) ;
91- updateRange ( 1 , result . boxStart [ 1 ] , result . boxEnd [ 1 ] ) ;
92- unSetAutoRange ( ) ;
173+ dx = result . boxStart [ 0 ] !== result . boxEnd [ 0 ] ;
174+ dy = result . boxStart [ 1 ] !== result . boxEnd [ 1 ] ;
175+ if ( dx || dy ) {
176+ if ( dx ) {
177+ updateRange ( 0 , result . boxStart [ 0 ] , result . boxEnd [ 0 ] ) ;
178+ scene . xaxis . autorange = false ;
179+ }
180+ if ( dy ) {
181+ updateRange ( 1 , result . boxStart [ 1 ] , result . boxEnd [ 1 ] ) ;
182+ scene . yaxis . autorange = false ;
183+ }
184+ scene . relayoutCallback ( ) ;
185+ }
186+ else {
187+ scene . glplot . setDirty ( ) ;
188+ }
93189 result . boxEnabled = false ;
94- scene . relayoutCallback ( ) ;
190+ result . boxInited = false ;
95191 }
96192 break ;
97193
98194 case 'pan' :
99195 result . boxEnabled = false ;
196+ result . boxInited = false ;
100197
101198 if ( buttons ) {
102- var dx = ( lastX - x ) * ( dataBox [ 2 ] - dataBox [ 0 ] ) /
199+ if ( ! result . panning ) {
200+ result . dragStart [ 0 ] = x ;
201+ result . dragStart [ 1 ] = y ;
202+ }
203+
204+ if ( Math . abs ( result . dragStart [ 0 ] - x ) < MINDRAG ) x = result . dragStart [ 0 ] ;
205+ if ( Math . abs ( result . dragStart [ 1 ] - y ) < MINDRAG ) y = result . dragStart [ 1 ] ;
206+
207+ dx = ( lastX - x ) * ( dataBox [ 2 ] - dataBox [ 0 ] ) /
103208 ( plot . viewBox [ 2 ] - plot . viewBox [ 0 ] ) ;
104- var dy = ( lastY - y ) * ( dataBox [ 3 ] - dataBox [ 1 ] ) /
209+ dy = ( lastY - y ) * ( dataBox [ 3 ] - dataBox [ 1 ] ) /
105210 ( plot . viewBox [ 3 ] - plot . viewBox [ 1 ] ) ;
106211
107212 dataBox [ 0 ] += dx ;
0 commit comments