I've been working with HTML5 drag and drop, and canvas. I'm trying to put the two together: I drag an element to a drop-area; in the drop-area I want to be able to move the dropped items around to position them as needed.
I know how to drop elements into a div, for ex, but:
does the drop-area have to be a canvas for (re)positioning?
is there a specific term for the moving/repositioning of elements in the drop-area/canvas. I've done a lot of searching and can't find a term for this specifically. simply 'dragging'??
sample drop-area.
No the canvas element is not required anyhow.
You can achieve the exact same result as the linked example you gave without using any canvas.
Here is an example code, among many others possible, certainly far from being perfect, but which does the same as your example, using only <div> elements, css and javascript, but it could also be made with svg.
// we will increment it to get the dragged element atop of everything
var zIndex = 0;
// our constructor
var newElement = function() {
var that = {};
// first get its dimension and position randomly
that.rad = Math.random() * 20 + 10;
// x and y are the center of our element
that.x = Math.random() * (500 - that.rad * 2) + that.rad;
that.y = Math.random() * (300 - that.rad * 2) + that.rad;
// define the element that will be appended to the doc
that.el = document.createElement('div');
// a shortcut to the style property of the element
// since we'll play with this to update our object's position
var s = that.el.style;
// don't forget we're talking in css
s.width = that.rad * 2 + 'px';
s.height = that.rad * 2 + 'px';
s.left = that.x - that.rad + 'px';
s.top = that.y - that.rad + 'px';
s.backgroundColor = get_random_color();
// needed to make be sure we're not in a corner of the circle shaped elements
that.isCircle = Math.random() > .5;
if (that.isCircle) {
that.el.className = 'circle';
}
// happens on mousedown
that.startDrag = function(x, y) {
that.lastX = x;
that.lastY = y;
s.zIndex = ++zIndex;
}
// happens on mousemove if we're the one being dragged
that.move = function(x, y) {
that.x += x - that.lastX;
that.y += y - that.lastY;
that.lastX = x;
that.lastY = y;
s.left = that.x - that.rad + 'px';
s.top = that.y - that.rad + 'px';
};
container.appendChild(that.el);
return that;
};
var elements = [];
for (var i = 0; i < (~~(Math.random() * 50)) + 15; i++) {
elements.push(newElement());
}
var dragged;
var mousedown = function(e) {
var rect = container.getBoundingClientRect();
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
dragged = null;
// sort our elements, higher zIndex firsts
elements.sort(function(a, b) {
return (+b.el.style.zIndex) - (+a.el.style.zIndex);
});
elements.forEach(function(el) {
// we already found the One, no need to go further
// (no "break;" in forEach method...)
if (dragged) return;
// is our mouse over the rectangular bounds of this element
if (x >= el.x - el.rad && x <= el.x + el.rad &&
y >= el.y - el.rad && y <= el.y + el.rad) {
if (el.isCircle) {
// a little bit of Pythagorian
var a = el.x - x;
var b = el.y - y;
var dist = Math.sqrt(a * a + b * b);
// too far from the center, we were in the corner
if (dist > el.rad) {
return;
}
}
// we got through here,
// tell the whole app we've got the One
dragged = el;
el.startDrag(x, y);
}
});
};
var mousemove = function(e) {
// nobody is being dragged, so don't do anything
if (!dragged) return;
// otherwise, tell the browser we handle the event
e.preventDefault();
e.stopPropagation();
// get the coordinates of our container
var rect = container.getBoundingClientRect();
// get the relative coordinates of our event
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
// move the dragged element accordingly
dragged.move(x, y);
};
var mouseup = function() {
// we dropped it..
dragged = null;
};
container.onmousedown = mousedown;
container.onmousemove = mousemove;
container.onmouseup = mouseup;
function get_random_color() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.round(Math.random() * 15)];
}
return color;
};
body {
text-align: center;
}
#container {
width: 500px;
height: 300px;
background-color: black;
margin: 0 auto;
position: relative;
overflow: hidden;
}
#container>div {
position: absolute;
opacity: .7;
}
.circle {
border-radius: 50%;
}
<div id="container"></div>
As you can see, I myself used the word dragged to refer to the object that we do move while we move the mouse with the button down. Yes, dragging is how this action is called...
But, this has very little to do with the HTML drag and drop API where what is important is not the positioning of your elements, but their content.
You can drag and drop elements into others, but it was mainly developed to drag data (external files or text content) to the document.
For this particular example, that would make things a lot harder and while the name "dragging" still applies to the action of the end-user, this shall not be confused with the API and every events related.
A canvas element is required by your linked canvas demo, but you can alternatively use the drag/drop API built into html+JS. And you can "manually" move DOM objects using mouse events as described in Kaiido's answer.
The canvas is required for your linked demo to work.
That exact demo was coded using a canvas element's drawing capabilities and that exact demo will not work if you try to substitute a DIV.
Think of html5 canvas as a re-writable bitmap. You can't "move" or "drag" anything on the canvas. Instead, you completely erase the canvas surface and redraw your circles in their new positions.
In the case of dragging, you listen for mousemove events on the canvas and reposition the circle under the mouse by the distance the mouse has moved since the last mousemove event.
How would I clip everything in the following drawing except for the S stroke? In other words get rid of all transparent space and only keep black S shape... thanks in advance!
=== PNG RENDERED IMAGE OF CANVAS ===
image located at --> http://buildasearch.com/ant/s.png
=== ACTUAL COORDINATES OF CANVAS DRAWING ===
var x = '68,67,66,65,64,63,62,61,60,59,57,56,55,54,53,52,51,51,51,51,51,51,51,52,55,56,52,58,60,59,61,62,64,65,66,68,70,71,72,74,75,76,77,78,78,79,79,79,79,79,79,79,79,79,79,79,79,78,76,74,71,67,59,56,54,52,49,47,46,45,43,42,41,40,39';
var y = '11,11,11,11,11,12,12,12,12,12,13,14,14,15,17,18,20,21,23,24,27,30,32,32,34,34,33,34,34,34,34,35,35,35,35,35,35,36,36,37,38,38,39,40,41,42,43,44,45,47,48,49,50,51,52,53,54,55,56,57,58,59,59,59,60,60,60,60,60,60,60,60,60,60,60';
It would be easier if your x and y were of the form [6, 3, 19] instead of '6,3,19'. For the purposes of this answer, I will assume that you have it done this way as it makes the code a bit easier.
It's quite possible to calculate afterwards, but it would get messy with getting the bit that you want and then resizing the canvas. It will end up easier and faster to calculate it before-hand if you can. Something like this should work:
// Data specification
var x = [68,67,66,65,64,63,62,61,60,59,57,56,55,54,53,52,51,51,51,51,51,51,51,52,55,56,52,58,60,59,61,62,64,65,66,68,70,71,72,74,75,76,77,78,78,79,79,79,79,79,79,79,79,79,79,79,79,78,76,74,71,67,59,56,54,52,49,47,46,45,43,42,41,40,39],
y = [11,11,11,11,11,12,12,12,12,12,13,14,14,15,17,18,20,21,23,24,27,30,32,32,34,34,33,34,34,34,34,35,35,35,35,35,35,36,36,37,38,38,39,40,41,42,43,44,45,47,48,49,50,51,52,53,54,55,56,57,58,59,59,59,60,60,60,60,60,60,60,60,60,60,60];
// Work out the extreme points in both dimensions
var xs = x.slice().sort(),
ys = y.slice().sort(),
minX = xs[0],
maxX = xs[xs.length-1],
minY = ys[0],
maxY = ys[ys.length-1];
// Resize the canvas
canvas.width = maxX - minX + 1;
canvas.height = maxY - minY + 1;
// Shift the points to fit on the shrunk canvas
x.forEach(function(v, i) {
x[i] = v - minX;
});
y.forEach(function(v, i) {
y[i] = v - minY;
});