patternjavascriptModerate
Draggable Resizeable Box
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:
-
-
-
```
(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);
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:
-
You have a few place where you can apply DRY
-
You set the
-
You set css values a number of times by comparing values
It is better to first deduce the value of
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 ){
- It makes more sense from a UX experience to create the box on
clickthen onmousedown
- 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
25and50all 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.