Drag & Drop Image Position Issue On Canvas - javascript

I am placing an image on the canvas using drap & drop but the problem is, after dropping the image on canvas, image is loosing it's original position where it is dropped.
Sometimes it comes down from the original position and sometimes moves to right. Here is the code:
$("#draggable1").draggable({
stop: function(event, ui)
{
var canv = document.getElementById("tools_sketch");
var rect = canv.getBoundingClientRect();
x = event.clientX - rect.left;
y = event.clientY - rect.top;
ans = confirm("Is it correct position?");
if (ans)
{
dropimg_over_ground("img1", x, y);
$('#draggable1').remove();
}
}
});
dropimg_over_ground = function(imgid, lefti, topi)
{
var c = document.getElementById("tools_sketch");
var ctx = c.getContext("2d");
var img = document.getElementById(imgid);
ctx.drawImage(img, lefti, topi);
}
I have searched forum alot and tried many solutions but it's not worked.

Just subtract the offset of the container:
$('#drag').draggable({
stop: function(e, ui){
console.log('drag');
console.log($(this).offset().top - $('#canvas').offset().top)
console.log($(this).offset().left - $('#canvas').offset().left)
}
});
$("#canvas").droppable({
accept: "#drag",
drop: function (event, ui) {
},
out: function (event, ui) {
console.log('dragged out');
}
});
Working example,
http://jsfiddle.net/kBM6u/6/
check the console for the results
Regards

Related

How to clear Canvas before drop new image on HTML5?

Dear I have small html5 canvas project that getting example from codepen to drag&drop image using html5 canvas. Example work fine, but I have problem once new image placed, then all of them are overlap in image area. Below is javascript code
<script>
var imgW;
function drawImg() {
var x = document.getElementById('myCanvas');
var canvax = x.getContext('2d');
var imgElement = document.getElementById('imgCanvas');
var imgObj = new Image();
imgObj.src = imgElement.src;
var imgW = imgObj.width;
var imgH = imgObj.height;
var imgX = canvax.canvas.width * .5 - imgW * .5;
var imgY = canvax.canvas.height * .5 - imgH * .5;
imgObj.onload = function () {
canvax.clearRect(imgX, imgY, imgW, imgH);
canvax.drawImage(imgObj, imgX, imgY, imgW, imgH);
};
}
$(document).ready(function () {
$('.listImg li').draggable({ containment: 'document', opacity: 0.60, revert: false, helper: 'clone',
start: function () {
$('.infoDrag').text('Start Drag');
},
drag: function () {
$('.infoDrag').text('on Dragging');
},
stop: function () {
$('.infoDrag').text('Stop Dragging');
} });
$('#myCanvas').droppable({ hoverClass: 'dashborder', tolerance: 'pointer',
drop: function (ev, ui) {
var droppedItem = $(ui.draggable).clone();
var canvasImg = $(this).find('img');
var newSrc = droppedItem.find('img').attr('src');
canvasImg.attr("src", newSrc);
drawImg();
} });
$('#myCanvas').dblclick(function () {
$('#myCanvas').draggable();
});
});
</script>
My need is to clear image before place new image. I may need to use clearRect method. But since tried several but not work. Any advise or guidance would be greatly appreciated, Thanks.
Instead of using the size and position of a (newly) loaded image as the bounding rectangle you feed to clearRect() use the size of the canvas itself.
Simply change
canvax.clearRect(imgX, imgY, imgW, imgH);
to
canvax.clearRect(0, 0, x.width, x.height);

How to show value of Jquery slider into multiple dropped divs

I'm using jQuery UI slider and drag and drop to create a way of specifying a rating out of 100 for each div.
The problem is when I drag my divs onto the slider, I do not know how to get the value for the position of each div on the slider. Here is a plnk + some code;
http://plnkr.co/edit/wSS2gZnSeJrvoBNDK6L3?p=preview
$(init);
function init() {
var range = 100;
var sliderDiv = $('#ratingBar');
sliderDiv.slider({
min: 0,
max: range,
slide: function(event, ui) {
$(".slider-value").html(ui.value);
}
});
var divs = '.itemContainer'
$(divs).draggable({
containment: '#content',
cursor: 'move',
snap: '#ratingBar',
revert: function(event, ui) {
$(this).data("uiDraggable").originalPosition = {
top: 0,
left: 0
};
return !event;
}
});
var position = sliderDiv.position(),
sliderWidth = sliderDiv.width(),
minX = position.left,
maxX = minX + sliderWidth,
tickSize = sliderWidth / range;
$('#ratingBar').droppable({
tolerance: 'touch',
drop: function(e, ui) {
var finalMidPosition = $(ui.draggable).position().left + Math.round($(divs).width() / 2);
if (finalMidPosition >= minX && finalMidPosition <= maxX) {
var val = Math.round((finalMidPosition - minX) / tickSize);
sliderDiv.slider("value", val);
$(".slider-value").html(ui.value);
}
}
});
$(".slider-value").html(sliderDiv.slider('value'));
}
Hope someone can offer some advice,
Cheers
(Also, if someone knows why I can drop the divs outside of the rating bar on either side, please let me know!)
Jquery UI has a function called stop and there is where you want to handle all the calculations as such:
stop: function(event, ui) {
// Object dragged
var e = ui.helper;
// Offset of that object
var eOffset = e.offset().left;
// Sliders offset
var sliderOffset = sliderDiv.offset().left;
// Subtract their offsets
var totalOffset = eOffset - sliderOffset;
// Width of box dragged
var boxWidth = ui.helper.width();
// Subtract their widths to account for overflow on end
var sliderW = sliderDiv.width() - boxWidth;
// Get percent moved
var percent = totalOffset / sliderW * 100;
// Find .slider-value and replace HTML
e.find(".slider-value").html(Math.round(percent));
}
This will be located here:
$(divs).draggable({
containment: '#content',
cursor: 'move',
snap: '#ratingBar',
revert: function(event, ui) {
$(this).data("uiDraggable").originalPosition = {
top: 0,
left: 0
};
return !event;
},
.... <-- HERE
});
I have provided commenting for every line so you understand what I did.
Above your draggable function you need to define a tighter containment area as such:
var left = sliderDiv.offset().left;
var right = left + sliderDiv.width();
var top = sliderDiv.offset().top;
var bottom = top + sliderDiv.height();
var height = $(".itemContainer").height();
var width = $(".itemContainer").width();
$(divs).draggable({
containment: [left, 0, right - width, bottom - height],
.....
});
This will prevent the draggable from being moved left, right, or below the slider.
Basically you grab the position of the object grabbed, adjust for some offset, adjust for some width, calculate the percentage, and replace the html (Could use text() as well).
Here is your plunker redone: http://plnkr.co/edit/3WSCo77c1cC5uFiYO8bV?p=preview
Documentation:
Jquery UI
Jquery .find

Trigger an event to call a function that's inside of a closure

I'm working on a project based on a nice little sample canvas drawing app someone else on the project downloaded and modified. We need to allow the user to click a button elsewhere on the page (not part of the canvas), and have it run a function that came with the sample app. However, the function is inside of a closure. Since I can't call the function directly (right? the closure prevents this? I don't often work with closures), I thought I'd be able to accomplish this by triggering a mouse event at the location the user would click to accomplish the same thing. It's not working, and I don't know why not.
I posted a greatly simplified version at this fiddle. Simple HTML code:
<div id="canvasDiv"></div>
<div id="buttonDiv">
<button>why can't I send a click to the canvas?</button>
</div>
And the simplified version of the downloaded sample app, plus my attempt to use jQuery's .trigger method to trigger the event:
var WM = {};
WM.drawingApp = function(options) {
"use strict";
var canvas, context,
// Add mouse and touch event listeners to the canvas
createUserEvents = function() {
var getElementPos = function(element) {
// straight-forward stuff removed for brevity's sake
return pos;
};
var press = function(e) {
// Mouse down location
var sizeHotspotStartX, toolIndex,
mouseX = (e.changedTouches ? e.changedTouches[0].pageX : e.pageX),
mouseY = (e.changedTouches ? e.changedTouches[0].pageY : e.pageY);
var elementPos = getElementPos(document.getElementById(options.canvasElementId || 'canvasDiv'));
mouseX -= elementPos.x;
mouseY -= elementPos.y;
announce(mouseX, mouseY);
};
var announce = function(x,y) { alert('press at: ' + x + ', ' + y); }
// Add mouse event listeners to canvas element
canvas.addEventListener("mousedown", press, false);
},
// Creates a canvas element, etc
init = function() {
// Create the canvas
canvas = document.createElement('canvas');
canvas.setAttribute('width', 100);
canvas.setAttribute('height', 100);
canvas.setAttribute('id', 'canvas');
document.getElementById(options.canvasElementId || 'canvasDiv').appendChild(canvas);
context = canvas.getContext("2d"); // Grab the 2d canvas context
createUserEvents();
};
init();
return {};
};
jQuery(document).ready(function() {
jQuery('#buttonDiv').on('click', 'button', function() {
var down = jQuery.Event("mousedown", {
pageX: 50,
pageY: 50
});
jQuery('#canvasDiv canvas').trigger(down);
});
});
As you can see by running the fiddle, if you click inside the box, you get an alert announcing where you clicked. But if you click the button, you don't get an alert. While writing this question, it occurred to me that maybe jQuery's .trigger method isn't a sufficient way to send the click. Its documentation page specifically says that .trigger "does not perfectly replicate a naturally-occurring event". We're open to solutions that don't involve jQuery.
You can define a variable var press; outside of WM, inside of WM, remove var before press and set press = function() {}. You should then be able to call press(down) at click of button
var press;
press = function(e) {
console.log(e);
// Mouse down location
var sizeHotspotStartX, toolIndex,
mouseX = (e.changedTouches ? e.changedTouches[0].pageX : e.pageX),
mouseY = (e.changedTouches ? e.changedTouches[0].pageY : e.pageY);
var elementPos = getElementPos(
document.getElementById(options.canvasElementId
|| 'canvasDiv')
);
mouseX -= elementPos.x;
mouseY -= elementPos.y;
announce(mouseX, mouseY);
};
jQuery(document).ready(function() {
jQuery('#buttonDiv').on('click', 'button', function() {
var down = jQuery.Event("mousedown", {
pageX: 50,
pageY: 50
});
press(down); // call `press` at `button` click
//jQuery('#canvasDiv canvas').trigger(down);
});
});
// based on http://www.williammalone.com/projects/html5-canvas-javascript-drawing-app-with-bucket-tool/
var press;
var WM = {};
WM.drawingApp = function(options) {
"use strict";
var canvas, context,
// Add mouse and touch event listeners to the canvas
createUserEvents = function() {
var getElementPos = function(element) {
var parentOffset, pos;
if (!element) {
pos = {
x: 0,
y: 0
};
} else {
pos = {
x: element.offsetLeft,
y: element.offsetTop
};
if (element.offsetParent) {
parentOffset = getElementPos(element.offsetParent);
pos.x += parentOffset.x;
pos.y += parentOffset.y;
}
}
return pos;
};
press = function(e) {
console.log(e)
// Mouse down location
var sizeHotspotStartX, toolIndex,
mouseX = (e.changedTouches ? e.changedTouches[0].pageX : e.pageX),
mouseY = (e.changedTouches ? e.changedTouches[0].pageY : e.pageY);
var elementPos = getElementPos(document.getElementById(options.canvasElementId || 'canvasDiv'));
mouseX -= elementPos.x;
mouseY -= elementPos.y;
announce(mouseX, mouseY);
};
var announce = function(x,y) { alert('press at: ' + x + ', ' + y); }
// Add mouse event listeners to canvas element
canvas.addEventListener("mousedown", press, false);
},
// Creates a canvas element, loads images, adds events, and draws the canvas for the first time.
init = function() {
// Create the canvas (Neccessary for IE because it doesn't know what a canvas element is)
canvas = document.createElement('canvas');
canvas.setAttribute('width', 100);
canvas.setAttribute('height', 100);
canvas.setAttribute('id', 'canvas');
document.getElementById(options.canvasElementId || 'canvasDiv').appendChild(canvas);
context = canvas.getContext("2d"); // Grab the 2d canvas context
createUserEvents();
};
init();
return {};
};
jQuery(document).ready(function() {
jQuery('#buttonDiv').on('click', 'button', function() {
var down = jQuery.Event("mousedown", {
pageX: 50,
pageY: 50
});
press(down)
//jQuery('#canvasDiv canvas').trigger(down);
});
});
var drawingApp = WM.drawingApp({
canvasElementId: "canvasDiv"
});
#canvasDiv canvas {
border: solid black 1px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<div id="canvasDiv"></div>
<div id="buttonDiv">
<button>why can't I send a click to the canvas?</button>
</div>
jsfiddle https://jsfiddle.net/gkvdha3h/5/

Intricate drag and drop jquery UI

Update:
Here is the final fiddle. Thanks Twisty.
https://jsfiddle.net/natjkern/55n1Lg61/14/
Here is a mock up of my site
http://jsfiddle.net/natjkern/pjq9wqLy/
On the right I have a fixed list of elements called #userList. This element must be set to overflow: auto, as the number of user elements is variable. I then need to drag a copy into dropzone, which again can vary in size, so it's container must be also set to overflow auto. I need the container to auto scroll when dragged element is dragged to edge to allow user to place element anywhere in dropzone. So far my best idea is to append to body first to escape the original auto overflow container then append to #dropzone on droppable({over:}). But this isn't really working out. Any UI experts out there that can give me a hand?
Here is my code so far:
$(document).ready(function () {
$('.moveMe').draggable({
helper: "clone",
appendTo: 'body',
revert: 'invalid',
scroll: true,
});
$('#dropZone').droppable({
accept: '.moveMe',
//here is where my problem arrises
// I need #dropZoneCon to scroll to place
over: function (event, ui) {
ui.helper.draggable.detach().appendTo($(this));
$('#DropZone div').css('position','absolute');
ui.helper.draggable.draggable('option', 'containment', 'parent');
},
/* */
drop: function (event, ui) {
ui.helper.draggable.detach().appendTo($(this));
$('#DropZone div').css('position','absolute');
ui.helper.draggable.draggable('option', 'containment', 'parent');
},
});
});
Note: commenting out over: allow me to place element where I would like, but I really need the scrolling to work.
This is a little clunky, but it does what you're looking to do.
http://jsfiddle.net/Twisty/55n1Lg61/5/
JQuery
$(document).ready(function() {
var tEntered = false;
$('.moveMe').draggable({
helper: "clone",
appendTo: 'body',
revert: 'invalid',
drag: function(e, u) {
var curPos = u.offset;
var $target = $("#dropZoneCon");
var tVP = $target.offset();
var tW = Math.floor($target.width());
var tH = Math.floor($target.height());
var pad = 20;
var scrInc = 10;
var x0 = tVP.top;
var x1 = tVP.top + tH;
var y0 = tVP.left;
var y1 = tVP.left + tW;
$("#dragInfo").html("Over #dropZone: " + tEntered + ", top: " +
tVP.top + "/" + curPos.top + "/" + x1 + " left: " + tVP.left + "/" + curPos.left + "/" + y1);
if (tEntered) {
// Increase Scroll
if (curPos.left >= (y1 - pad) && curPos.left <= y1) {
$target.scrollLeft($target.scrollLeft() + scrInc);
}
if (curPos.top >= (x1 - pad) && curPos.top <= x1) {
$target.scrollTop($target.scrollTop() + scrInc);
}
// Decrease Scroll
if (curPos.left >= y0 && curPos.left <= (y0 + pad)) {
$target.scrollLeft($target.scrollLeft() - scrInc);
}
if (curPos.top >= x0 && curPos.top <= (x0 + pad)) {
$target.scrollTop($target.scrollTop() - scrInc);
}
}
}
});
$('#dropZone').droppable({
accept: '.moveMe',
over: function(e, u) {
tEntered = true;
},
out: function(e, u) {
tEntered = false;
},
drop: function(event, ui) {
ui.draggable.detach().appendTo($(this));
$('#DropZone div').css('position', 'absolute');
ui.draggable.draggable('option', 'containment', 'parent');
},
});
});
So we do a lot of the heavy lifting in the drag event since we can determine the position of the drag object from this event. In the drag event we define a number of variables:
curPos the current position of our draggable object in { top, left }
$target the dropZone container
tVP the Target View Port offset in { top, left }
tW & tH the Target's Width and Height
scrInc a value we will use to increase or decrease the scroll position
pad the amount of pixels to use as the edge detection of tVP
x0 & x1 are the tVP top edge and bottom edge
y0 & y1 are the tVP left edge and right edge
I defined tEntered outside of these functions, so I can access it from either draggable or droppable. Since droppable has over and out, we can use those to change this value.
Now, when tEntered is true, meaning we are dragging an object over the target, we look to see if the x and y might be within our padding. If they are we increase or decrease the scroll position.
I found this helpful: http://www.jqwidgets.com/community/topic/how-detect-area-dropped-inside-a-div-into-another-div/
This should allow you to do what you want unless I misunderstood. Comment if you have questions.

how to know event.pageX and event.pageY is increasing or decreasing in jQuery-Ui?

I am using this following jQuery-UI code in my programming, can anybody know how to know, whether event.pageX and event.pageY is increasing or decreasing while resizing a particular div.
CODE:
fontSize = parseInt($(' span',this).css('fontSize'));
$(this).resizable({
disabled:false,
handles: 'nw, ne, se, sw',
resize: function(event, ui) {
xvalue = event.pageX;
yvalue = event.pageY;
fontSize = fontSize+.1;
$(" span",this).css("fontSize",fontSize);
}
});
can anybody how to get to know is that xvalue and yvalue is increasing or decreasing ??
var fontSize = parseInt($('span', this).css('fontSize'));
var xValue, yValue;
var f = function(event, ui) {
var isXIncreasing = xXalue < event.pageX;
var isYIncreasing = yValue < event.pageY;
// ^ you can do something with these now
xValue = event.pageX;
yValue = event.pageY;
fontSize = fontSize+.1;
$('span', this).css("fontSize",fontSize);
};
$(this).resizable({
disabled: false,
handles: 'nw, ne, se, sw',
resize: f
});
You can compare ui.originalSize and ui.size to see whether the current resizing operation is decreasing or increasing the size.
For instance:
resize: function(event, ui) {
if (ui.size.height > ui.originalSize.height) {
// element is taller than before
} else {
// element is the same size or smaller than before
}
}
By analogy, you can use ui.size.width and ui.originalSize.width to see if the element is wider than before.
See the API.

Categories

Resources