@@ -4517,102 +4517,175 @@ function d3_behavior_dragClick() {
45174517 d3_behavior_dragMoved = 0 ;
45184518 }
45194519}
4520- // TODO unbind zoom behavior?
45214520d3 . behavior . zoom = function ( ) {
4522- var xyz = [ 0 , 0 , 0 ] ,
4521+ var translate = [ 0 , 0 ] ,
4522+ translate0 , // translate when we started zooming (to avoid drift)
4523+ scale = 1 ,
4524+ scale0 , // scale when we started touching
4525+ scaleExtent = d3_behavior_zoomInfinity ,
45234526 event = d3 . dispatch ( "zoom" ) ,
4524- extent = d3_behavior_zoomInfiniteExtent ;
4527+ x0 ,
4528+ x1 ,
4529+ y0 ,
4530+ y1 ,
4531+ touchtime ; // time of last touchstart (to detect double-tap)
45254532
45264533 function zoom ( ) {
45274534 this
45284535 . on ( "mousedown.zoom" , mousedown )
45294536 . on ( "mousewheel.zoom" , mousewheel )
4537+ . on ( "mousemove.zoom" , mousemove )
45304538 . on ( "DOMMouseScroll.zoom" , mousewheel )
45314539 . on ( "dblclick.zoom" , dblclick )
4532- . on ( "touchstart.zoom" , touchstart ) ;
4540+ . on ( "touchstart.zoom" , touchstart )
4541+ . on ( "touchmove.zoom" , touchmove )
4542+ . on ( "touchend.zoom" , touchstart ) ;
4543+ }
45334544
4534- d3 . select ( window )
4535- . on ( "mousemove.zoom" , d3_behavior_zoomMousemove )
4536- . on ( "mouseup.zoom" , d3_behavior_zoomMouseup )
4537- . on ( "touchmove.zoom" , d3_behavior_zoomTouchmove )
4538- . on ( "touchend.zoom" , d3_behavior_zoomTouchup )
4539- . on ( "click.zoom" , d3_behavior_zoomClick , true ) ;
4545+ zoom . translate = function ( x ) {
4546+ if ( ! arguments . length ) return translate ;
4547+ translate = x . map ( Number ) ;
4548+ return zoom ;
4549+ } ;
4550+
4551+ zoom . scale = function ( x ) {
4552+ if ( ! arguments . length ) return scale ;
4553+ scale = + x ;
4554+ return zoom ;
4555+ } ;
4556+
4557+ zoom . scaleExtent = function ( x ) {
4558+ if ( ! arguments . length ) return scaleExtent ;
4559+ scaleExtent = x == null ? d3_behavior_zoomInfinity : x . map ( Number ) ;
4560+ return zoom ;
4561+ } ;
4562+
4563+ zoom . x = function ( z ) {
4564+ if ( ! arguments . length ) return x1 ;
4565+ x1 = z ;
4566+ x0 = z . copy ( ) ;
4567+ return zoom ;
4568+ } ;
4569+
4570+ zoom . y = function ( z ) {
4571+ if ( ! arguments . length ) return y1 ;
4572+ y1 = z ;
4573+ y0 = z . copy ( ) ;
4574+ return zoom ;
4575+ } ;
4576+
4577+ function location ( p ) {
4578+ return [ ( p [ 0 ] - translate [ 0 ] ) / scale , ( p [ 1 ] - translate [ 1 ] ) / scale ] ;
45404579 }
45414580
4542- // snapshot the local context for subsequent dispatch
4543- function start ( ) {
4544- d3_behavior_zoomXyz = xyz ;
4545- d3_behavior_zoomExtent = extent ;
4546- d3_behavior_zoomDispatch = event . zoom ;
4547- d3_behavior_zoomEventTarget = d3 . event . target ;
4548- d3_behavior_zoomTarget = this ;
4549- d3_behavior_zoomArguments = arguments ;
4581+ function point ( l ) {
4582+ return [ l [ 0 ] * scale + translate [ 0 ] , l [ 1 ] * scale + translate [ 1 ] ] ;
4583+ }
4584+
4585+ function scaleTo ( s ) {
4586+ scale = Math . max ( scaleExtent [ 0 ] , Math . min ( scaleExtent [ 1 ] , s ) ) ;
4587+ }
4588+
4589+ function translateTo ( p , l ) {
4590+ l = point ( l ) ;
4591+ translate [ 0 ] += p [ 0 ] - l [ 0 ] ;
4592+ translate [ 1 ] += p [ 1 ] - l [ 1 ] ;
4593+ }
4594+
4595+ function dispatch ( argumentz ) {
4596+ var o = d3 . event ; // events can by reentrant (e.g., focus);
4597+ d3 . event = { scale : scale , translate : translate , target : zoom } ;
4598+ if ( x1 ) x1 . domain ( x0 . range ( ) . map ( function ( x ) { return ( x - translate [ 0 ] ) / scale ; } ) . map ( x0 . invert ) ) ;
4599+ if ( y1 ) y1 . domain ( y0 . range ( ) . map ( function ( y ) { return ( y - translate [ 1 ] ) / scale ; } ) . map ( y0 . invert ) ) ;
4600+ try { event . zoom . apply ( zoom , argumentz ) ; }
4601+ finally { d3 . event = o ; }
4602+ o . preventDefault ( ) ;
45504603 }
45514604
45524605 function mousedown ( ) {
4553- start . apply ( this , arguments ) ;
4554- d3_behavior_zoomPanning = d3_behavior_zoomLocation ( d3 . svg . mouse ( d3_behavior_zoomTarget ) ) ;
4555- d3_behavior_zoomMoved = 0 ;
4556- d3 . event . preventDefault ( ) ;
4606+ var moved = 0 ,
4607+ that = this ,
4608+ argumentz = arguments ,
4609+ target = d3 . event . target ,
4610+ w = d3 . select ( window ) . on ( "mousemove.zoom" , mousemove ) . on ( "mouseup.zoom" , mouseup ) ,
4611+ l = location ( d3 . svg . mouse ( that ) ) ;
4612+
45574613 window . focus ( ) ;
4614+ d3_eventCancel ( ) ;
4615+
4616+ function mousemove ( ) {
4617+ moved = 1 ;
4618+ translateTo ( d3 . svg . mouse ( that ) , l ) ;
4619+ dispatch ( argumentz ) ;
4620+ }
4621+
4622+ function mouseup ( ) {
4623+ if ( moved ) d3_eventCancel ( ) ;
4624+ w . on ( "mousemove.zoom" , null ) . on ( "mouseup.zoom" , null ) . on ( "click.zoom" , moved && d3 . event . target === target ? click : null ) ;
4625+ }
4626+
4627+ function click ( ) {
4628+ d3_eventCancel ( ) ;
4629+ w . on ( "click.zoom" , null ) ;
4630+ }
45584631 }
45594632
4560- // store starting mouse location
45614633 function mousewheel ( ) {
4562- start . apply ( this , arguments ) ;
4563- if ( ! d3_behavior_zoomZooming ) d3_behavior_zoomZooming = d3_behavior_zoomLocation ( d3 . svg . mouse ( d3_behavior_zoomTarget ) ) ;
4564- d3_behavior_zoomTo ( d3_behavior_zoomDelta ( ) + xyz [ 2 ] , d3 . svg . mouse ( d3_behavior_zoomTarget ) , d3_behavior_zoomZooming ) ;
4634+ if ( ! translate0 ) translate0 = location ( d3 . svg . mouse ( this ) ) ;
4635+ scaleTo ( Math . pow ( 2 , d3_behavior_zoomDelta ( ) * .002 ) * scale ) ;
4636+ translateTo ( d3 . svg . mouse ( this ) , translate0 ) ;
4637+ dispatch ( arguments ) ;
4638+ }
4639+
4640+ function mousemove ( ) {
4641+ translate0 = null ;
45654642 }
45664643
45674644 function dblclick ( ) {
4568- start . apply ( this , arguments ) ;
4569- var mouse = d3 . svg . mouse ( d3_behavior_zoomTarget ) ;
4570- d3_behavior_zoomTo ( d3 . event . shiftKey ? Math . ceil ( xyz [ 2 ] - 1 ) : Math . floor ( xyz [ 2 ] + 1 ) , mouse , d3_behavior_zoomLocation ( mouse ) ) ;
4645+ var p = d3 . svg . mouse ( this ) , l = location ( p ) ;
4646+ scaleTo ( d3 . event . shiftKey ? scale / 2 : scale * 2 ) ;
4647+ translateTo ( p , l ) ;
4648+ dispatch ( arguments ) ;
45714649 }
45724650
4573- // doubletap detection
45744651 function touchstart ( ) {
4575- start . apply ( this , arguments ) ;
4576- var touches = d3_behavior_zoomTouchup ( ) ,
4577- touch ,
4652+ var touches = d3 . svg . touches ( this ) ,
45784653 now = Date . now ( ) ;
4579- if ( ( touches . length === 1 ) && ( now - d3_behavior_zoomLast < 300 ) ) {
4580- d3_behavior_zoomTo ( 1 + Math . floor ( xyz [ 2 ] ) , touch = touches [ 0 ] , d3_behavior_zoomLocations [ touch . identifier ] ) ;
4654+
4655+ scale0 = scale ;
4656+ translate0 = { } ;
4657+ touches . forEach ( function ( t ) { translate0 [ t . identifier ] = location ( t ) ; } ) ;
4658+ d3_eventCancel ( ) ;
4659+
4660+ if ( ( touches . length === 1 ) && ( now - touchtime < 500 ) ) { // dbltap
4661+ var p = touches [ 0 ] , l = location ( touches [ 0 ] ) ;
4662+ scaleTo ( scale * 2 ) ;
4663+ translateTo ( p , l ) ;
4664+ dispatch ( arguments ) ;
45814665 }
4582- d3_behavior_zoomLast = now ;
4666+ touchtime = now ;
4667+ }
4668+
4669+ function touchmove ( ) {
4670+ var touches = d3 . svg . touches ( this ) ,
4671+ p0 = touches [ 0 ] ,
4672+ l0 = translate0 [ p0 . identifier ] ;
4673+ if ( p1 = touches [ 1 ] ) {
4674+ var p1 , l1 = translate0 [ p1 . identifier ] ;
4675+ p0 = [ ( p0 [ 0 ] + p1 [ 0 ] ) / 2 , ( p0 [ 1 ] + p1 [ 1 ] ) / 2 ] ;
4676+ l0 = [ ( l0 [ 0 ] + l1 [ 0 ] ) / 2 , ( l0 [ 1 ] + l1 [ 1 ] ) / 2 ] ;
4677+ scaleTo ( d3 . event . scale * scale0 ) ;
4678+ }
4679+ translateTo ( p0 , l0 ) ;
4680+ dispatch ( arguments ) ;
45834681 }
45844682
4585- zoom . extent = function ( x ) {
4586- if ( ! arguments . length ) return extent ;
4587- extent = x == null ? d3_behavior_zoomInfiniteExtent : x ;
4588- return zoom ;
4589- } ;
4590-
45914683 return d3 . rebind ( zoom , event , "on" ) ;
45924684} ;
45934685
4594- var d3_behavior_zoomDiv ,
4595- d3_behavior_zoomPanning ,
4596- d3_behavior_zoomZooming ,
4597- d3_behavior_zoomLocations = { } , // identifier -> location
4598- d3_behavior_zoomLast = 0 ,
4599- d3_behavior_zoomXyz ,
4600- d3_behavior_zoomExtent ,
4601- d3_behavior_zoomDispatch ,
4602- d3_behavior_zoomEventTarget ,
4603- d3_behavior_zoomTarget ,
4604- d3_behavior_zoomArguments ,
4605- d3_behavior_zoomMoved ;
4606-
4607- function d3_behavior_zoomLocation ( point ) {
4608- return [
4609- point [ 0 ] - d3_behavior_zoomXyz [ 0 ] ,
4610- point [ 1 ] - d3_behavior_zoomXyz [ 1 ] ,
4611- d3_behavior_zoomXyz [ 2 ]
4612- ] ;
4613- }
4686+ var d3_behavior_zoomDiv , // for interpreting mousewheel events
4687+ d3_behavior_zoomInfinity = [ 0 , Infinity ] ; // default scale extent
46144688
4615- // detect the pixels that would be scrolled by this wheel event
46164689function d3_behavior_zoomDelta ( ) {
46174690
46184691 // mousewheel events are totally broken!
@@ -4639,124 +4712,6 @@ function d3_behavior_zoomDelta() {
46394712 delta = e . wheelDelta || ( - e . detail * 5 ) ;
46404713 }
46414714
4642- return delta * .005 ;
4643- }
4644-
4645- // Note: Since we don't rotate, it's possible for the touches to become
4646- // slightly detached from their original positions. Thus, we recompute the
4647- // touch points on touchend as well as touchstart!
4648- function d3_behavior_zoomTouchup ( ) {
4649- var touches = d3 . svg . touches ( d3_behavior_zoomTarget ) ,
4650- i = - 1 ,
4651- n = touches . length ,
4652- touch ;
4653- while ( ++ i < n ) d3_behavior_zoomLocations [ ( touch = touches [ i ] ) . identifier ] = d3_behavior_zoomLocation ( touch ) ;
4654- return touches ;
4655- }
4656-
4657- function d3_behavior_zoomTouchmove ( ) {
4658- var touches = d3 . svg . touches ( d3_behavior_zoomTarget ) ;
4659- switch ( touches . length ) {
4660-
4661- // single-touch pan
4662- case 1 : {
4663- var touch = touches [ 0 ] ;
4664- d3_behavior_zoomTo ( d3_behavior_zoomXyz [ 2 ] , touch , d3_behavior_zoomLocations [ touch . identifier ] ) ;
4665- break ;
4666- }
4667-
4668- // double-touch pan + zoom
4669- case 2 : {
4670- var p0 = touches [ 0 ] ,
4671- p1 = touches [ 1 ] ,
4672- p2 = [ ( p0 [ 0 ] + p1 [ 0 ] ) / 2 , ( p0 [ 1 ] + p1 [ 1 ] ) / 2 ] ,
4673- l0 = d3_behavior_zoomLocations [ p0 . identifier ] ,
4674- l1 = d3_behavior_zoomLocations [ p1 . identifier ] ,
4675- l2 = [ ( l0 [ 0 ] + l1 [ 0 ] ) / 2 , ( l0 [ 1 ] + l1 [ 1 ] ) / 2 , l0 [ 2 ] ] ;
4676- d3_behavior_zoomTo ( Math . log ( d3 . event . scale ) / Math . LN2 + l0 [ 2 ] , p2 , l2 ) ;
4677- break ;
4678- }
4679- }
4680- }
4681-
4682- function d3_behavior_zoomMousemove ( ) {
4683- d3_behavior_zoomZooming = null ;
4684- if ( d3_behavior_zoomPanning ) {
4685- d3_behavior_zoomMoved = 1 ;
4686- d3_behavior_zoomTo ( d3_behavior_zoomXyz [ 2 ] , d3 . svg . mouse ( d3_behavior_zoomTarget ) , d3_behavior_zoomPanning ) ;
4687- }
4688- }
4689-
4690- function d3_behavior_zoomMouseup ( ) {
4691- if ( d3_behavior_zoomPanning ) {
4692- if ( d3_behavior_zoomMoved ) {
4693- d3_eventCancel ( ) ;
4694- d3_behavior_zoomMoved = d3_behavior_zoomEventTarget === d3 . event . target ;
4695- }
4696-
4697- d3_behavior_zoomXyz =
4698- d3_behavior_zoomExtent =
4699- d3_behavior_zoomDispatch =
4700- d3_behavior_zoomEventTarget =
4701- d3_behavior_zoomTarget =
4702- d3_behavior_zoomArguments =
4703- d3_behavior_zoomPanning = null ;
4704- }
4705- }
4706-
4707- function d3_behavior_zoomClick ( ) {
4708- if ( d3_behavior_zoomMoved ) {
4709- d3_eventCancel ( ) ;
4710- d3_behavior_zoomMoved = 0 ;
4711- }
4712- }
4713-
4714- function d3_behavior_zoomTo ( z , x0 , x1 ) {
4715- z = d3_behavior_zoomExtentClamp ( z , 2 ) ;
4716- var j = Math . pow ( 2 , d3_behavior_zoomXyz [ 2 ] ) ,
4717- k = Math . pow ( 2 , z ) ,
4718- K = Math . pow ( 2 , ( d3_behavior_zoomXyz [ 2 ] = z ) - x1 [ 2 ] ) ,
4719- x_ = d3_behavior_zoomXyz [ 0 ] ,
4720- y_ = d3_behavior_zoomXyz [ 1 ] ,
4721- x = d3_behavior_zoomXyz [ 0 ] = d3_behavior_zoomExtentClamp ( ( x0 [ 0 ] - x1 [ 0 ] * K ) , 0 , k ) ,
4722- y = d3_behavior_zoomXyz [ 1 ] = d3_behavior_zoomExtentClamp ( ( x0 [ 1 ] - x1 [ 1 ] * K ) , 1 , k ) ,
4723- o = d3 . event ; // Events can be reentrant (e.g., focus).
4724-
4725- d3 . event = {
4726- scale : k ,
4727- translate : [ x , y ] ,
4728- transform : function ( sx , sy ) {
4729- if ( sx ) transform ( sx , x_ , x ) ;
4730- if ( sy ) transform ( sy , y_ , y ) ;
4731- }
4732- } ;
4733-
4734- function transform ( scale , a , b ) {
4735- scale . domain ( scale . range ( ) . map ( function ( v ) { return scale . invert ( ( ( v - b ) * j ) / k + a ) ; } ) ) ;
4736- }
4737-
4738- try {
4739- d3_behavior_zoomDispatch . apply ( d3_behavior_zoomTarget , d3_behavior_zoomArguments ) ;
4740- } finally {
4741- d3 . event = o ;
4742- }
4743-
4744- o . preventDefault ( ) ;
4745- }
4746-
4747- var d3_behavior_zoomInfiniteExtent = [
4748- [ - Infinity , Infinity ] ,
4749- [ - Infinity , Infinity ] ,
4750- [ - Infinity , Infinity ]
4751- ] ;
4752-
4753- function d3_behavior_zoomExtentClamp ( x , i , k ) {
4754- var range = d3_behavior_zoomExtent [ i ] ,
4755- r0 = range [ 0 ] ,
4756- r1 = range [ 1 ] ;
4757- return arguments . length === 3
4758- ? Math . max ( r1 * ( r1 === Infinity ? - Infinity : 1 / k - 1 ) ,
4759- Math . min ( r0 === - Infinity ? Infinity : r0 , x / k ) ) * k
4760- : Math . max ( r0 , Math . min ( r1 , x ) ) ;
4715+ return delta ;
47614716}
47624717} ) ( ) ;
0 commit comments