@@ -306,28 +306,40 @@ describe('Test shapes', function() {
306306 var testCases = [
307307 // xref: 'paper', yref: 'paper'
308308 {
309- title : 'linked to paper should be draggable '
309+ title : 'linked to paper'
310310 } ,
311311
312312 // xaxis.type: 'linear', yaxis.type: 'log'
313313 {
314- title : 'linked to linear and log axes should be draggable ' ,
314+ title : 'linked to linear and log axes' ,
315315 xaxis : { type : 'linear' , range : [ 0 , 10 ] } ,
316316 yaxis : { type : 'log' , range : [ Math . log10 ( 1 ) , Math . log10 ( 1000 ) ] }
317317 } ,
318318
319319 // xaxis.type: 'date', yaxis.type: 'category'
320320 {
321- title : 'linked to date and category axes should be draggable ' ,
321+ title : 'linked to date and category axes' ,
322322 xaxis : { type : 'date' , range : [ '2000-01-01' , '2000-01-02' ] } ,
323323 yaxis : { type : 'category' , range : [ 'a' , 'b' ] }
324324 }
325325 ] ;
326326
327327 testCases . forEach ( function ( testCase ) {
328- it ( testCase . title , function ( done ) {
328+ it ( testCase . title + 'should be draggable' , function ( done ) {
329329 setupLayout ( testCase ) ;
330- testAllShapes ( done ) ;
330+ testDragEachShape ( done ) ;
331+ } ) ;
332+ } ) ;
333+
334+ testCases . forEach ( function ( testCase ) {
335+ [ 'n' , 's' , 'w' , 'e' , 'nw' , 'se' , 'ne' , 'sw' ] . forEach ( function ( direction ) {
336+ var testTitle = testCase . title +
337+ 'should be resizeable over direction ' +
338+ direction ;
339+ it ( testTitle , function ( done ) {
340+ setupLayout ( testCase ) ;
341+ testResizeEachShape ( direction , done ) ;
342+ } ) ;
331343 } ) ;
332344 } ) ;
333345
@@ -392,21 +404,60 @@ describe('Test shapes', function() {
392404 layout . shapes = layoutShapes ;
393405 }
394406
395- function testAllShapes ( done ) {
407+ function testDragEachShape ( done ) {
396408 var promise = Plotly . plot ( gd , data , layout , config ) ;
397409
398410 var layoutShapes = gd . layout . shapes ;
399411
400412 expect ( layoutShapes . length ) . toBe ( 4 ) ; // line, rect, circle and path
401413
402414 layoutShapes . forEach ( function ( layoutShape , index ) {
415+ var dx = 100 ,
416+ dy = 100 ;
403417 promise = promise . then ( function ( ) {
404418 var node = getShapeNode ( index ) ;
405419 expect ( node ) . not . toBe ( null ) ;
406420
407421 return ( layoutShape . path ) ?
408- testPath ( layoutShape , node ) :
409- testShape ( layoutShape , node ) ;
422+ testPathDrag ( dx , dy , layoutShape , node ) :
423+ testShapeDrag ( dx , dy , layoutShape , node ) ;
424+ } ) ;
425+ } ) ;
426+
427+ return promise . then ( done ) ;
428+ }
429+
430+ function testResizeEachShape ( direction , done ) {
431+ var promise = Plotly . plot ( gd , data , layout , config ) ;
432+
433+ var layoutShapes = gd . layout . shapes ;
434+
435+ expect ( layoutShapes . length ) . toBe ( 4 ) ; // line, rect, circle and path
436+
437+ var dxToShrinkWidth = {
438+ n : 0 , s : 0 , w : 10 , e : - 10 , nw : 10 , se : - 10 , ne : - 10 , sw : 10
439+ } ,
440+ dyToShrinkHeight = {
441+ n : 10 , s : - 10 , w : 0 , e : 0 , nw : 10 , se : - 10 , ne : 10 , sw : - 10
442+ } ;
443+ layoutShapes . forEach ( function ( layoutShape , index ) {
444+ if ( layoutShape . path ) return ;
445+
446+ var dx = dxToShrinkWidth [ direction ] ,
447+ dy = dyToShrinkHeight [ direction ] ;
448+
449+ promise = promise . then ( function ( ) {
450+ var node = getShapeNode ( index ) ;
451+ expect ( node ) . not . toBe ( null ) ;
452+
453+ return testShapeResize ( direction , dx , dy , layoutShape , node ) ;
454+ } ) ;
455+
456+ promise = promise . then ( function ( ) {
457+ var node = getShapeNode ( index ) ;
458+ expect ( node ) . not . toBe ( null ) ;
459+
460+ return testShapeResize ( direction , - dx , - dy , layoutShape , node ) ;
410461 } ) ;
411462 } ) ;
412463
@@ -419,15 +470,13 @@ describe('Test shapes', function() {
419470 } ) . node ( ) ;
420471 }
421472
422- function testShape ( layoutShape , node ) {
473+ function testShapeDrag ( dx , dy , layoutShape , node ) {
423474 var xa = Axes . getFromId ( gd , layoutShape . xref ) ,
424475 ya = Axes . getFromId ( gd , layoutShape . yref ) ,
425476 x2p = getDataToPixel ( gd , xa ) ,
426477 y2p = getDataToPixel ( gd , ya , true ) ;
427478
428- var initialCoordinates = getShapeCoordinates ( layoutShape , x2p , y2p ) ,
429- dx = 100 ,
430- dy = 100 ;
479+ var initialCoordinates = getShapeCoordinates ( layoutShape , x2p , y2p ) ;
431480
432481 return drag ( node , dx , dy ) . then ( function ( ) {
433482 var finalCoordinates = getShapeCoordinates ( layoutShape , x2p , y2p ) ;
@@ -448,16 +497,14 @@ describe('Test shapes', function() {
448497 } ;
449498 }
450499
451- function testPath ( layoutShape , node ) {
500+ function testPathDrag ( dx , dy , layoutShape , node ) {
452501 var xa = Axes . getFromId ( gd , layoutShape . xref ) ,
453502 ya = Axes . getFromId ( gd , layoutShape . yref ) ,
454503 x2p = getDataToPixel ( gd , xa ) ,
455504 y2p = getDataToPixel ( gd , ya , true ) ;
456505
457506 var initialPath = layoutShape . path ,
458- initialCoordinates = getPathCoordinates ( initialPath , x2p , y2p ) ,
459- dx = 100 ,
460- dy = 100 ;
507+ initialCoordinates = getPathCoordinates ( initialPath , x2p , y2p ) ;
461508
462509 expect ( initialCoordinates . length ) . toBe ( 6 ) ;
463510
@@ -483,6 +530,51 @@ describe('Test shapes', function() {
483530 } ) ;
484531 }
485532
533+ function testShapeResize ( direction , dx , dy , layoutShape , node ) {
534+ var xa = Axes . getFromId ( gd , layoutShape . xref ) ,
535+ ya = Axes . getFromId ( gd , layoutShape . yref ) ,
536+ x2p = getDataToPixel ( gd , xa ) ,
537+ y2p = getDataToPixel ( gd , ya , true ) ;
538+
539+ var initialCoordinates = getShapeCoordinates ( layoutShape , x2p , y2p ) ;
540+
541+ return resize ( direction , node , dx , dy ) . then ( function ( ) {
542+ var finalCoordinates = getShapeCoordinates ( layoutShape , x2p , y2p ) ;
543+
544+ var keyN , keyS , keyW , keyE ;
545+ if ( initialCoordinates . y0 < initialCoordinates . y1 ) {
546+ keyN = 'y0' ; keyS = 'y1' ;
547+ }
548+ else {
549+ keyN = 'y1' ; keyS = 'y0' ;
550+ }
551+ if ( initialCoordinates . x0 < initialCoordinates . x1 ) {
552+ keyW = 'x0' ; keyE = 'x1' ;
553+ }
554+ else {
555+ keyW = 'x1' ; keyE = 'x0' ;
556+ }
557+
558+ if ( ~ direction . indexOf ( 'n' ) ) {
559+ expect ( finalCoordinates [ keyN ] - initialCoordinates [ keyN ] )
560+ . toBeCloseTo ( dy ) ;
561+ }
562+ else if ( ~ direction . indexOf ( 's' ) ) {
563+ expect ( finalCoordinates [ keyS ] - initialCoordinates [ keyS ] )
564+ . toBeCloseTo ( dy ) ;
565+ }
566+
567+ if ( ~ direction . indexOf ( 'w' ) ) {
568+ expect ( finalCoordinates [ keyW ] - initialCoordinates [ keyW ] )
569+ . toBeCloseTo ( dx ) ;
570+ }
571+ else if ( ~ direction . indexOf ( 'e' ) ) {
572+ expect ( finalCoordinates [ keyE ] - initialCoordinates [ keyE ] )
573+ . toBeCloseTo ( dx ) ;
574+ }
575+ } ) ;
576+ }
577+
486578 // Adapted from src/components/shapes/index.js
487579 var segmentRE = / [ M L H V Q C T S Z ] [ ^ M L H V Q C T S Z ] * / g,
488580 paramRE = / [ ^ \s , ] + / g,
@@ -639,6 +731,34 @@ function drag(node, dx, dy) {
639731 return promise ;
640732}
641733
734+ function resize ( direction , node , dx , dy ) {
735+ var bbox = node . getBoundingClientRect ( ) ;
736+
737+ var fromX , fromY , toX , toY ;
738+
739+ if ( ~ direction . indexOf ( 'n' ) ) fromY = bbox . top ;
740+ else if ( ~ direction . indexOf ( 's' ) ) fromY = bbox . bottom ;
741+ else fromY = ( bbox . bottom + bbox . top ) / 2 ;
742+
743+ if ( ~ direction . indexOf ( 'w' ) ) fromX = bbox . left ;
744+ else if ( ~ direction . indexOf ( 'e' ) ) fromX = bbox . right ;
745+ else fromX = ( bbox . left + bbox . right ) / 2 ;
746+
747+ toX = fromX + dx ;
748+ toY = fromY + dy ;
749+
750+ mouseMove ( node , fromX , fromY ) ;
751+ mouseDown ( node , fromX , fromY ) ;
752+
753+ var promise = waitForDragCover ( ) . then ( function ( dragCoverNode ) {
754+ mouseMove ( dragCoverNode , toX , toY ) ;
755+ mouseUp ( dragCoverNode , toX , toY ) ;
756+ return waitForDragCoverRemoval ( ) ;
757+ } ) ;
758+
759+ return promise ;
760+ }
761+
642762function waitForDragCover ( ) {
643763 return new Promise ( function ( resolve ) {
644764 var interval = DBLCLICKDELAY / 4 ,
0 commit comments