HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptModerate

Draggable Resizeable Box

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
draggableboxresizeable

Problem

This is my first angular code. I've been working with jQuery for a while, so I don't have the same approach. I'm looking for advice and code improvement.

The following code has 3 directives:

-
ceBoxCreator: Will create a div that will be draggable and resizable on a click.

-
ceDrag: The element binded to this directive will be draggable.

-
ceResize: The element binded to this directive will be resizable.

```
(function() {
var contentEditor = angular.module("contentEditor", []);

// To create a empty resizable and draggable box
contentEditor.directive("ceBoxCreator", function($document, $compile) {
return {
restrict: 'A',
link: function($scope, $element, $attrs) {
$element.on("mousedown", function($event) {
var newNode = $compile('')($scope);

newNode.css({
position: "absolute",
top: $event.pageY - 25 + "px",
left: $event.pageX - 25 + "px",
});

angular.element($document[0].body).append(newNode);
});
}
}
});

// To manage the drag
contentEditor.directive("ceDrag", function($document) {
return function($scope, $element, $attr) {
var startX = 0, startY = 0;
var newElement = angular.element('');

$element.append(newElement);
newElement.on("mousedown", function($event) {
$event.preventDefault();

// To keep the last selected box in front
angular.element(document.querySelectorAll(".contentEditorBox")).css("z-index", "0");
$element.css("z-index", "1");

startX = $event.pageX - $element[0].offsetLeft;
startY = $event.pageY - $element[0].offsetTop;
$document.on("mousemove", mousemove);
$document.on("mouseup", mouseup);

Solution

From a once over:

  • It makes more sense from a UX experience to create the box on click then on mousedown



  • There are a number of indenting inconsistencies, use TidyUp in jsFiddle to fix that



  • Naming is good



  • Flow of the code is good



  • Commenting is good



  • I don't like the constants 25 and 50 all over the place, name them and manage them



-
You have a few place where you can apply DRY

-
You set the top and left a number of times, simply create a helper function

function placeNode(node, top, left) {
  node.css({
    position: "absolute",
    top: top + "px",
    left: left + "px",
  });
}


-
You set css values a number of times by comparing values

var width = $event.pageX - $element[0].offsetLeft;

if ($event.pageX > $element[0].offsetLeft + 50) {
    $element.css({
       width: width + "px"
    });
} else {
    $element.css({
        width: "50px",
     });
}


It is better to first deduce the value of width and then set it in 1 go:

var margin = 50,
    leftest = $element[0].offsetLeft + margin,
    width = $event.pageX > leftest ? $event.pageX - $element[0].offsetLeft : margin;
$element.css({
  width: width + "px"
});


  • There is a ton of copy pastage when the resize divs are generated, use 1 common function that can generate a div with a class name and event handler(s).



All in all I thought your code looked okay, if repetitive, so I took a stab at both fixing your code ( for upper and left resize ) and making it less repetitive ( you can find this in action here ):

```
(function() {
var contentEditor = angular.module("contentEditor", []);

function placeNode(node, top, left) {
node.css({
position: "absolute",
top: top + "px",
left: left + "px",
});
}

// To create a empty resizable and draggable box
contentEditor.directive("ceBoxCreator", function($document, $compile) {
return {
restrict: 'A',
link: function($scope, $element, $attrs) {
$element.on("click", function($event) {

var newNode = $compile('')($scope);
placeNode(newNode, $event.pageY - 25, $event.pageX - 25);
angular.element($document[0].body).append(newNode);
});
}
}
});

// To manage the drag
contentEditor.directive("ceDrag", function($document) {
return function($scope, $element, $attr) {
var startX = 0,
startY = 0;

var newElement = angular.element('');

$element.append(newElement);
newElement.on("mousedown", function($event) {
event.preventDefault();

// To keep the last selected box in front
angular.element(document.querySelectorAll(".contentEditorBox")).css("z-index", "0");
$element.css("z-index", "1");

startX = $event.pageX - $element[0].offsetLeft;
startY = $event.pageY - $element[0].offsetTop;
$document.on("mousemove", mousemove);
$document.on("mouseup", mouseup);
});

function mousemove($event) {
placeNode( $element , $event.pageY - startY , $event.pageX - startX );
}

function mouseup() {
$document.off("mousemove", mousemove);
$document.off("mouseup", mouseup);
}
};
});

// To manage the resizers
contentEditor.directive("ceResize", function($document) {
return function($scope, $element, $attr) {
//Reference to the original
var $mouseDown;

// Function to manage resize up event
var resizeUp = function($event) {
var margin = 50,
lowest = $mouseDown.top + $mouseDown.height - margin,
top = $event.pageY > lowest ? lowest : $event.pageY,
height = $mouseDown.top - top + $mouseDown.height;

$element.css({
top: top + "px",
height: height + "px"
});
};

// Function to manage resize right event
var resizeRight = function($event) {
var margin = 50,
leftest = $element[0].offsetLeft + margin,
width = $event.pageX > leftest ? $event.pageX - $element[0].offsetLeft : margin;

$element.css({
width: width + "px"
});
};

// Function to manage resize down event
var resizeDown = function($event) {
var margin = 50,
uppest = $element[0].offsetTop + margin,
height = $event.pageY > uppest ? $event.pageY - $element[0].offsetTop : margin;

$element.css({
height: height + "px"
});
};

// Function to manage resize left event
function resizeLeft ($event) {
var margin = 50,
rightest = $mouseDown.left + $mouseDown.width - margin,
left = $event.pageX > rightest ? rightest : $event.pageX,
width = $mouseDown.left - left + $mouseDown.width;

$element.css({
left: left + "px",
width: width + "px"
});
};

var createResizer = function createResizer( className , handlers ){

Code Snippets

function placeNode(node, top, left) {
  node.css({
    position: "absolute",
    top: top + "px",
    left: left + "px",
  });
}
var width = $event.pageX - $element[0].offsetLeft;

if ($event.pageX > $element[0].offsetLeft + 50) {
    $element.css({
       width: width + "px"
    });
} else {
    $element.css({
        width: "50px",
     });
}
var margin = 50,
    leftest = $element[0].offsetLeft + margin,
    width = $event.pageX > leftest ? $event.pageX - $element[0].offsetLeft : margin;
$element.css({
  width: width + "px"
});
(function() {
  var contentEditor = angular.module("contentEditor", []);

  function placeNode(node, top, left) {
    node.css({
      position: "absolute",
      top: top + "px",
      left: left + "px",
    });
  }

  // To create a empty resizable and draggable box
  contentEditor.directive("ceBoxCreator", function($document, $compile) {
    return {
      restrict: 'A',
      link: function($scope, $element, $attrs) {
        $element.on("click", function($event) {

          var newNode = $compile('<div class="contentEditorBox" ce-drag ce-resize></div>')($scope);
          placeNode(newNode, $event.pageY - 25, $event.pageX - 25);
          angular.element($document[0].body).append(newNode);
        });
      }
    }
  });

  // To manage the drag
  contentEditor.directive("ceDrag", function($document) {
    return function($scope, $element, $attr) {
      var startX = 0,
          startY = 0;

      var newElement = angular.element('<div class="draggable"></div>');

      $element.append(newElement);
      newElement.on("mousedown", function($event) {
        event.preventDefault();

        // To keep the last selected box in front
        angular.element(document.querySelectorAll(".contentEditorBox")).css("z-index", "0");
        $element.css("z-index", "1");

        startX = $event.pageX - $element[0].offsetLeft;
        startY = $event.pageY - $element[0].offsetTop;
        $document.on("mousemove", mousemove);
        $document.on("mouseup", mouseup);
      });

      function mousemove($event) {
        placeNode( $element , $event.pageY - startY , $event.pageX - startX );
      }

      function mouseup() {
        $document.off("mousemove", mousemove);
        $document.off("mouseup", mouseup);
      }
    };
  });

  // To manage the resizers
  contentEditor.directive("ceResize", function($document) {
    return function($scope, $element, $attr) {
      //Reference to the original 
      var $mouseDown; 

      // Function to manage resize up event
      var resizeUp = function($event) {
        var margin = 50,
            lowest = $mouseDown.top + $mouseDown.height - margin,
            top = $event.pageY > lowest ? lowest : $event.pageY,
            height = $mouseDown.top - top + $mouseDown.height;

        $element.css({
          top: top + "px",
          height: height + "px"
        });
      };

      // Function to manage resize right event
      var resizeRight = function($event) {
        var margin = 50,
            leftest = $element[0].offsetLeft + margin,
            width = $event.pageX > leftest ? $event.pageX - $element[0].offsetLeft : margin;

        $element.css({
          width: width + "px"
        });
      };

      // Function to manage resize down event
      var resizeDown = function($event) {
        var margin = 50,
            uppest = $element[0].offsetTop + margin,
            height = $event.pageY > uppest ? $event.pageY - $element[0].offsetTop : margin;

        $element.css({
          height:

Context

StackExchange Code Review Q#61847, answer score: 10

Revisions (0)

No revisions yet.