@@ -351,11 +351,18 @@ function updateShape(gd, index, opt, value) {
351351}
352352
353353function setupDragElement ( gd , shapePath , shapeOptions , index ) {
354+ var MINWIDTH = 10 ,
355+ MINHEIGHT = 10 ;
356+
354357 var update ;
355358 var x0 , y0 , x1 , y1 , astrX0 , astrY0 , astrX1 , astrY1 ;
359+ var n0 , s0 , w0 , e0 , astrN , astrS , astrW , astrE , optN , optS , optW , optE ;
356360 var pathIn , astrPath ;
361+
357362 var xa , ya , x2p , y2p , p2x , p2y ;
358363
364+ var dragBBox , dragMode ;
365+
359366 var dragOptions = {
360367 element : shapePath . node ( ) ,
361368 prepFn : startDrag ,
@@ -364,9 +371,8 @@ function setupDragElement(gd, shapePath, shapeOptions, index) {
364371
365372 dragElement . init ( dragOptions ) ;
366373
367- function startDrag ( ) {
368- setCursor ( shapePath , 'move' ) ;
369-
374+ function startDrag ( evt , startX , startY ) {
375+ // setup conversion functions
370376 xa = Axes . getFromId ( gd , shapeOptions . xref ) ;
371377 ya = Axes . getFromId ( gd , shapeOptions . yref ) ;
372378
@@ -375,6 +381,7 @@ function setupDragElement(gd, shapePath, shapeOptions, index) {
375381 p2x = getPixelToData ( gd , xa ) ;
376382 p2y = getPixelToData ( gd , ya , true ) ;
377383
384+ // setup update strings and initial values
378385 var astr = 'shapes[' + index + ']' ;
379386 if ( shapeOptions . type === 'path' ) {
380387 pathIn = shapeOptions . path ;
@@ -392,9 +399,43 @@ function setupDragElement(gd, shapePath, shapeOptions, index) {
392399 astrY1 = astr + '.y1' ;
393400 }
394401
402+ if ( x0 < x1 ) {
403+ w0 = x0 ; astrW = astr + '.x0' ; optW = 'x0' ;
404+ e0 = x1 ; astrE = astr + '.x1' ; optE = 'x1' ;
405+ }
406+ else {
407+ w0 = x1 ; astrW = astr + '.x1' ; optW = 'x1' ;
408+ e0 = x0 ; astrE = astr + '.x0' ; optE = 'x0' ;
409+ }
410+ if ( y0 < y1 ) {
411+ n0 = y0 ; astrN = astr + '.y0' ; optN = 'y0' ;
412+ s0 = y1 ; astrS = astr + '.y1' ; optS = 'y1' ;
413+ }
414+ else {
415+ n0 = y1 ; astrN = astr + '.y1' ; optN = 'y1' ;
416+ s0 = y0 ; astrS = astr + '.y0' ; optS = 'y0' ;
417+ }
418+
395419 update = { } ;
396420
397- dragOptions . moveFn = moveShape ;
421+ // choose 'move' or 'resize'
422+ // based on initial position of cursor within the drag element
423+ dragBBox = dragOptions . element . getBoundingClientRect ( ) ;
424+
425+ var w = dragBBox . right - dragBBox . left ,
426+ h = dragBBox . bottom - dragBBox . top ,
427+ x = startX - dragBBox . left ,
428+ y = startY - dragBBox . top ,
429+ cursor = ( w > MINWIDTH && h > MINHEIGHT ) ?
430+ dragElement . getCursor ( x / w , 1 - y / h ) :
431+ 'move' ;
432+
433+ setCursor ( shapePath , cursor ) ;
434+
435+ // possible values 'move', 'sw', 'w', 'se', 'e', 'ne', 'n', 'nw' and 'w'
436+ dragMode = cursor . split ( '-' ) [ 0 ] ;
437+
438+ dragOptions . moveFn = ( dragMode === 'move' ) ? moveShape : resizeShape ;
398439 }
399440
400441 function endDrag ( dragged ) {
@@ -424,6 +465,38 @@ function setupDragElement(gd, shapePath, shapeOptions, index) {
424465
425466 shapePath . attr ( 'd' , getPathString ( gd , shapeOptions ) ) ;
426467 }
468+
469+ function resizeShape ( dx , dy ) {
470+ if ( shapeOptions . type === 'path' ) {
471+ // TODO: implement path resize
472+ var moveX = function moveX ( x ) { return p2x ( x2p ( x ) + dx ) ; } ;
473+ if ( xa && xa . type === 'date' ) moveX = encodeDate ( moveX ) ;
474+
475+ var moveY = function moveY ( y ) { return p2y ( y2p ( y ) + dy ) ; } ;
476+ if ( ya && ya . type === 'date' ) moveY = encodeDate ( moveY ) ;
477+
478+ shapeOptions . path = movePath ( pathIn , moveX , moveY ) ;
479+ update [ astrPath ] = shapeOptions . path ;
480+ }
481+ else {
482+ var newN = ( ~ dragMode . indexOf ( 'n' ) ) ? n0 + dy : n0 ,
483+ newS = ( ~ dragMode . indexOf ( 's' ) ) ? s0 + dy : s0 ,
484+ newW = ( ~ dragMode . indexOf ( 'w' ) ) ? w0 + dx : w0 ,
485+ newE = ( ~ dragMode . indexOf ( 'e' ) ) ? e0 + dx : e0 ;
486+
487+ if ( newS - newN > MINHEIGHT ) {
488+ update [ astrN ] = shapeOptions [ optN ] = p2y ( newN ) ;
489+ update [ astrS ] = shapeOptions [ optS ] = p2y ( newS ) ;
490+ }
491+
492+ if ( newE - newW > MINWIDTH ) {
493+ update [ astrW ] = shapeOptions [ optW ] = p2x ( newW ) ;
494+ update [ astrE ] = shapeOptions [ optE ] = p2x ( newE ) ;
495+ }
496+ }
497+
498+ shapePath . attr ( 'd' , getPathString ( gd , shapeOptions ) ) ;
499+ }
427500}
428501
429502function getShapeLayer ( gd , index ) {
0 commit comments