I have created a program that populates the canvas with randomly positioned boxes with random colors. That part was easy, problem im having is that I would like to move any of these colored boxes around with my mouse. As well, the pointer must stay a costant distance from the top-left corner. My code is below, any help would be greatly appreciated!
window.onload = init;
function init() {
var x= Math.floor(Math.random()*400);
var y= Math.floor(Math.random()*400);
var body = document.getElementsByTagName("body")[0];
var canvas = document.createElement("canvas");
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
var context = canvas.getContext("2d");
// Repeat to draw a rectangle 100 times
for(var i=0;i<100;i++){
var color = '#'+ Math.round(0xffffff * Math.random()).toString(16);
context.fillStyle = color;
//Each rectangle is at (0 ~ width of window, 0 ~ height of window)
//Each rectangle's size is 50x50)
context.fillRect(Math.random()*window.innerWidth,
Math.random()*window.innerHeight, 50, 50);
}
document.body.appendChild(canvas);
}
var mousePiece = null;
function init2() {
//we are grabbing the div elm by uts id
// var divEl = document.getElementById("ace");
var cx = document.querySelector("canvas").getContext("2d");
//divEl.style.top = getStyle(divEl,"top");
//divEl.style.left = getStyle(divEl,"left");
addEvent(cx, "mousedown", mouseGrab, false);
}
function mouseGrab(e) {
var evt = e || window.event;
mousePiece = evt.target || evt.srcElement;
addEvent(document, "mousemove", mouseMove, false);
addEvent(document, "mouseup", mouseDrop, false);
}
function mouseMove(e) {
var evt = e || window.event;
var mouseX = evt.clientX;
var mouseY = evt.clientY;
mousePiece.style.left = mouseX + "px";
mousePiece.style.top = mouseY + "px";
}
function mouseDrop(e) {
mousePiece = null;
removeEvent(document, "mousemove", mouseMove, false);
removeEvent(document, "mouseup", mouseDrop, false);
}
function addEvent(object, evName, fnName, cap) {
if (object.attachEvent)
object.attachEvent("on" + evName, fnName);
else if (object.addEventListener)
object.addEventListener(evName, fnName, cap);
}
function removeEvent(object, evName, fnName, cap) {
if (object.detachEvent)
object.detachEvent("on" + evName, fnName);
else if (object.removeEventListener)
object.removeEventListener(evName, fnName, cap);
}
function getStyle(object, styleName) {
if (window.getComputedStyle) {
return document.defaultView.getComputedStyle(object,
null).getPropertyValue(styleName);
} else if (object.currentStyle) {
return object.currentStyle[styleName]
}
}
I would consider JQuery UI draggable. I made you a JS Fiddle with random colors and all. There are many things you can do with JQuery UI so check the docs to find exactly what you need.
$( document ).ready( function () {
for ( var i = 0; i < 50; i++ ) {
var randomColor = Math.floor(Math.random()*16777215).toString(16);
var ranNum = Math.round( Math.random() * 65 )
$( ".boxHolder" ).append( '<div class="pos' + i + ' draggable ui-widget-content"></div>' )
$( ".pos" + i ).css({
"background" : "#" + randomColor,
"top" : 10 * i + "px",
"left" : ranNum * 6 + "px"
})
}
})
$( function() {
$( ".draggable" ).draggable()
})
The bad news is that the canvas element is a pixel map: when you draw something on it, you modify pixel values as if you were updating an image. Drawing on the canvas does not create HTML elements that can be assigned an id, grabbed, or moved around using event.target (the target in your case will be the canvas element).
The good news is that there are canvas libraries that create an object model on top of the canvas for items separately placed and then allow you to move them around. For example have a look at fabric.js for demonstrations of the operations it supports. Feel free to do more research on your options!
Also note two issues with the random color string:
Use Math.floor instead of Math.round to avoid ending up with a value of 2^24 (also corrected in ALFmachine's reply)
Defining CSS colors usig a hex digit string requires either 3 or 6 hex digits preceeded by '#'. To avoid color values being discarded by the CSS parser in your case, lead fill the hex digits with '0' to make up the 6 digits as required.
You could construct a CSS rbg() color string using three random integers in range 0 to 255 as the alternative.
Related
the code below is a standard resizable() jQuery-ui Widget.
how is it possible to know what is the object it being dragged on to ?
i have tried to catch it using the clientX and more... but it did not "deliver" the actual element. i have tried without ghost which was inter-fearing in middle of the way to discover what is layed under. though this is not the issue i guess.
$([selector]).resizable({
//some featurs/options and then
resize:
function (event, obj) {
var x = event.clientX, y = event.clientY,
var elementMouseIsOver = document.elementFromPoint(x, y);
}
});
any help would be appreciated .
take a look on the z-index i have applied to resizable div
i have lowered it conditionally.
so if it is over some other ide'd object, i will then be able to access its properties rather the blocking resizable .
$('document').ready(function () {
$('#resz').resizable({
handles: 'n, s',
resize:
function (event, obj) {
var H = obj.size.height;
var curobj = $(this);
var target = curobj;
var x = event.clientX, y = event.clientY;
var elementMouseIsOver = document.elementFromPoint(x, y);
if (elementMouseIsOver.id != "") //&& elementMouseIsOver.id != this.id)
{
curobj.css("z-index", "-1");
target = $("#" + elementMouseIsOver.id); //.css('display', 'none');
$("#deb").html("found " + target.attr("id") + " at " + target.css("z-index"));
}
}
});
});
so I have a canvas that takes up 100% of the page size and ontop of this canvas are other html elements. I want to make it so any element that has the class game-gui can be dragged round the screen (so users can position them where they want).
the js fiddle for this looks like this:
http://jsfiddle.net/VYJCj/2/
the code for this can be seen below:
$('.game-gui').each(function(i, obj) {
$(obj).on('dragstart', function(event){
var left = parseInt($(obj).css("left"), 10);
var top = parseInt($(obj).css("top"), 10);
event.originalEvent.dataTransfer.effectAllowed = 'move';
var str = (left - event.originalEvent.clientX) + ',' + (top - event.originalEvent.clientY)+ ',' + event.target.id;
event.originalEvent.dataTransfer.setData("text/plain", str);
});
});
this.canvas = $('#game_canvas');
this.canvas.bind('drop', function(event){
event.stopPropagation();
event.preventDefault();
var offset = event.originalEvent.dataTransfer.getData("text/plain").split(',');
console.log(offset);
var obj = $('#' + offset[2]);
var clientX = event.originalEvent.clientX || 0;
var clientY = event.originalEvent.clientY || 0 ;
obj.css('left', ( clientX+ parseInt(offset[0],10)) + 'px');
obj.css('top', ( clientY + parseInt(offset[1],10)) + 'px');
return false;
});
this.canvas.bind('dragover', function(event){
event.preventDefault();
event.originalEvent.dataTransfer.dropEffect = 'move';
return false;
});
as you will be able to see from the demo you can move the elements around the page however they move into different positions then they should! would anyone be able to help me on the matter?
I want to achieve 'Panning' in svg while 'dragging' an element in particular direction.
Let say i select an element and start 'dragging' it upward untill it reached top of screen, now my svg should pan upwards automatically, without causing any problem with dragging. how i can achieve this.?
i have made a small mockup of this, where user can select and drag elements. it also contain two button, which cause svg to pan upward and downward. I am achiveing 'Panning' by changing 'ViewBox' of svg. ( i have to use this logic, i cannot use any other solution);
here is the fiddle link : http://jsfiddle.net/9J25r/
Complete Code:-
addEventListener('mousedown', mousedown, false);
var mx, my;
var dx, dy;
var mainsvg = document.getElementById('svg');
var selectedElement;
var eleTx, eleTy;
function getSvgCordinates(event) {
var m = mainsvg.getScreenCTM();
var p = mainsvg.createSVGPoint();
var x, y;
x = event.pageX;
y = event.pageY;
p.x = x;
p.y = y;
p = p.matrixTransform(m.inverse());
x = p.x;
y = p.y;
x = parseFloat(x.toFixed(3));
y = parseFloat(y.toFixed(3));
return {x: x, y: y};
}
function mousedown(event) {
if (event.target.id === 'arrow_t') {
panning('up');
}
else if (event.target.id === 'arrow_b') {
panning('down');
}
else if (event.target.id.split('_')[0] === 'rect') {
selectedElement = event.target;
var translatexy = selectedElement.getAttribute('transform');
translatexy = translatexy.split('(');
translatexy = translatexy[1].split(',');
eleTx = translatexy[0];
translatexy = translatexy[1].split(')');
eleTy = translatexy[0];
eleTx = parseFloat(eleTx);
eleTy = parseFloat(eleTy);
var xy = getSvgCordinates(event);
mx = xy.x;
my = xy.y;
mx = parseFloat(mx);
my = parseFloat(my);
addEventListener('mousemove', drag, false);
addEventListener('mouseup', mouseup, false);
}
}
function drag(event) {
var xy = getSvgCordinates(event);
dx = xy.x - mx;
dy = xy.y - my;
selectedElement.setAttribute('transform', 'translate(' + (eleTx + dx) + ',' + (eleTy + dy) + ')');
}
function mouseup(event) {
removeEventListener('mousemove', drag, false);
removeEventListener('mouseup', mouseup, false);
}
function panning(direction) {
var viewBox = svg.getAttribute('viewBox');
viewBox = viewBox.split(' ');
var y = parseFloat(viewBox[1]);
if (direction === 'up')
{
y+=5;
}
else if (direction === 'down')
{
y-=5;
}
viewBox=viewBox[0]+' '+y+' '+viewBox[2]+' '+viewBox[3];
svg.setAttribute('viewBox',viewBox);
}
here is the fiddle link : http://jsfiddle.net/9J25r/
EDIT:- (UPDATE)
I use the solution of Ian , it works well on the sample, but when i applied it to my original application, it did not work. check the below gif. You can see the 'gap' between mouse pointer and element. how i can remove that? .
This is one way, I've just done it with the Y/vertical for the moment...
You may want to adjust it, so that if the cursor is off the screen it adjusts the viewBox automatically as well, depends how you want it to drag (otherwise you will need to keep wiggling it to kick the drag func in).
var viewBox = svg.getAttribute('viewBox');
viewBoxSplit = viewBox.split(' ');
if( ely < viewBoxSplit[1] ) {
panning('down');
} else if( ely + +event.target.getAttribute('height')> +viewBoxSplit[1] + 300 ) {
panning('up');
}
jsfiddle here
This question already has answers here:
Moveable/draggable <div>
(9 answers)
Closed 5 years ago.
I want to create a movable/draggable div in native javascript without using jquery and libraries. Is there a tutorial or anythign?
OK, here's my personal code that I use for lightweight deployments (projects where using a library is either not allowed or overkill for some reason). First thing first, I always use this convenience function so that I can pass either an id or the actual dom element:
function get (el) {
if (typeof el == 'string') return document.getElementById(el);
return el;
}
As a bonus, get() is shorter to type than document.getElementById() and my code ends up shorter.
Second realize that what most libraries are doing is cross-browser compatibility. If all browsers behave the same the code is fairly trivial. So lets write some cross-browser functions to get mouse position:
function mouseX (e) {
if (e.pageX) {
return e.pageX;
}
if (e.clientX) {
return e.clientX + (document.documentElement.scrollLeft ?
document.documentElement.scrollLeft :
document.body.scrollLeft);
}
return null;
}
function mouseY (e) {
if (e.pageY) {
return e.pageY;
}
if (e.clientY) {
return e.clientY + (document.documentElement.scrollTop ?
document.documentElement.scrollTop :
document.body.scrollTop);
}
return null;
}
OK, the two functions above are identical. There're certainly better ways to write them but I'm keeping it (relatively) simple for now.
Now we can write the drag and drop code. The thing I like about this code is that everything's captured in a single closure so there are no global variables or helper functions littering the browser. Also, the code separates the drag handle from the object being dragged. This is useful for creating dialog boxes etc. But if not needed, you can always assign them the same object. Anyway, here's the code:
function dragable (clickEl,dragEl) {
var p = get(clickEl);
var t = get(dragEl);
var drag = false;
offsetX = 0;
offsetY = 0;
var mousemoveTemp = null;
if (t) {
var move = function (x,y) {
t.style.left = (parseInt(t.style.left)+x) + "px";
t.style.top = (parseInt(t.style.top) +y) + "px";
}
var mouseMoveHandler = function (e) {
e = e || window.event;
if(!drag){return true};
var x = mouseX(e);
var y = mouseY(e);
if (x != offsetX || y != offsetY) {
move(x-offsetX,y-offsetY);
offsetX = x;
offsetY = y;
}
return false;
}
var start_drag = function (e) {
e = e || window.event;
offsetX=mouseX(e);
offsetY=mouseY(e);
drag=true; // basically we're using this to detect dragging
// save any previous mousemove event handler:
if (document.body.onmousemove) {
mousemoveTemp = document.body.onmousemove;
}
document.body.onmousemove = mouseMoveHandler;
return false;
}
var stop_drag = function () {
drag=false;
// restore previous mousemove event handler if necessary:
if (mousemoveTemp) {
document.body.onmousemove = mousemoveTemp;
mousemoveTemp = null;
}
return false;
}
p.onmousedown = start_drag;
p.onmouseup = stop_drag;
}
}
There is a reason for the slightly convoluted offsetX/offsetY calculations. If you notice, it's just taking the difference between mouse positions and adding them back to the position of the div being dragged. Why not just use the mouse positions? Well, if you do that the div will jump to the mouse pointer when you click on it. Which is a behavior I did not want.
You can try this
HTML
<div id="one" style="height:50px; width:50px; border:1px solid #ccc; background:red;">
</div>
Js Script for draggable div
window.onload = function(){
draggable('one');
};
var dragObj = null;
function draggable(id)
{
var obj = document.getElementById(id);
obj.style.position = "absolute";
obj.onmousedown = function(){
dragObj = obj;
}
}
document.onmouseup = function(e){
dragObj = null;
};
document.onmousemove = function(e){
var x = e.pageX;
var y = e.pageY;
if(dragObj == null)
return;
dragObj.style.left = x +"px";
dragObj.style.top= y +"px";
};
Check this Demo
This code corrects the position of the mouse (so the dragged object doesn't jump when you start dragging) and works with touch screens/phones as well
var dragObj = null; //object to be moved
var xOffset = 0; //used to prevent dragged object jumping to mouse location
var yOffset = 0;
window.onload = function()
{
document.getElementById("menuBar").addEventListener("mousedown", startDrag, true);
document.getElementById("menuBar").addEventListener("touchstart", startDrag, true);
document.onmouseup = stopDrag;
document.ontouchend = stopDrag;
}
function startDrag(e)
/*sets offset parameters and starts listening for mouse-move*/
{
e.preventDefault();
e.stopPropagation();
dragObj = e.target;
dragObj.style.position = "absolute";
var rect = dragObj.getBoundingClientRect();
if(e.type=="mousedown")
{
xOffset = e.clientX - rect.left; //clientX and getBoundingClientRect() both use viewable area adjusted when scrolling aka 'viewport'
yOffset = e.clientY - rect.top;
window.addEventListener('mousemove', dragObject, true);
}
else if(e.type=="touchstart")
{
xOffset = e.targetTouches[0].clientX - rect.left; //clientX and getBoundingClientRect() both use viewable area adjusted when scrolling aka 'viewport'
yOffset = e.targetTouches[0].clientY - rect.top;
window.addEventListener('touchmove', dragObject, true);
}
}
function dragObject(e)
/*Drag object*/
{
e.preventDefault();
e.stopPropagation();
if(dragObj == null) return; // if there is no object being dragged then do nothing
else if(e.type=="mousemove")
{
dragObj.style.left = e.clientX-xOffset +"px"; // adjust location of dragged object so doesn't jump to mouse position
dragObj.style.top = e.clientY-yOffset +"px";
}
else if(e.type=="touchmove")
{
dragObj.style.left = e.targetTouches[0].clientX-xOffset +"px"; // adjust location of dragged object so doesn't jump to mouse position
dragObj.style.top = e.targetTouches[0].clientY-yOffset +"px";
}
}
function stopDrag(e)
/*End dragging*/
{
if(dragObj)
{
dragObj = null;
window.removeEventListener('mousemove', dragObject, true);
window.removeEventListener('touchmove', dragObject, true);
}
}
div{height:400px; width:400px; border:1px solid #ccc; background:blue; cursor: pointer;}
<div id="menuBar" >A</div>
<div draggable=true ondragstart="event.dataTransfer.setData('text/plain', '12345')">
drag me
</div>
<div ondragover="return false;" ondrop="this.innerHTML=event.dataTransfer.getData('text/plain')">
drop on me
</div>
How to make a element draggable without using jQuery UI?
I have this code:
<script type="text/javascript">
function show_coords(event)
{
var x=event.clientX;
var y=event.clientY;
var drag=document.getElementById('drag');
drag.style.left=x;
drag.style.top=y
}
</script>
<body style="height:100%;width:100%" onmousemove="show_coords(event)">
<p id="drag" style="position:absolute">drag me</p>
</body>
The problem is that I want to drag while the user the pressing the mouse button. I tried onmousedown but results were negative.
It will be quite easy as you get the concept.
function enableDragging(ele) {
var dragging = dragging || false, //Setup a bunch of variables
x, y, Ox, Oy,
enableDragging.z = enableDragging.z || 1,
current;
ele.onmousedown = function(ev) { //When mouse is down
current = ev.target;
dragging = true; //It is dragging time
x = ev.clientX; //Get mouse X and Y and store it
y = ev.clientY; // for later use.
Ox = current.offsetLeft; //Get element's position
Oy = current.offsetTop;
current.style.zIndex = ++enableDragging.z; //z-index thing
window.onmousemove = function(ev) {
if (dragging == true) { //when it is dragging
var Sx = ev.clientX - x + Ox, //Add the difference between
Sy = ev.clientY - y + Oy; // 2 mouse position to the
current.style.top = Sy + "px"; // element.
current.style.left = Sx + "px";
return false; //Don't care about this.
}
};
window.onmouseup = function(ev) {
dragging && (dragging = false); //Mouse up, dragging done!
}
};
}
enableDragging(document.getElementById("drag")); //draggable now!
var ele = document.getElementsByTagName("div");
for(var i = 0; i < ele.length; i++){ //Every div's is draggable
enableDragging(ele[i]); // (only when its "position"
} // is set to "absolute" or
// "relative")
http://jsfiddle.net/DerekL/NWU9G/
The reason why your code is not working is because the <div> will always follow where your cursor goes, and you are not actually dragging it. The top left corner will always follow your cursor, and this is not we wanted.
UPDATE
Now if you only want a grabber or something similar, just change this part of the script:
ele.onmousedown = function(ev) {
current = ev.target;
to
var grabber = document.createElement("div");
grabber.setAttribute("class", "grabber");
ele.appendChild(grabber);
grabber.onmousedown = function(ev) {
current = ev.target.parentNode;
Now you can only click on the grabber to start the dragging process.
http://jsfiddle.net/DerekL/NWU9G/7/