Connect canvas with lines - html

I need to connect two canvas with a line to create a dynamic workflow.
I'll generate the canvas rectangle dynamic (amount of steps I have at DB) but I need to connect the steps with lines.
Anybody have some ideas?

Here’s how to automatically connect 2 draggable canvas rectangles with a line
First, define some boxes and connectors:
// define any boxes that will be drawn
var boxes=[];
boxes.push({x:50,y:25,w:75,h:50}); // x,y,width,height
boxes.push({x:200,y:100,w:50,h:50});
// define any connectors between any boxes
var connectors=[];
connectors.push({box1:0,box2:1});
Draw the boxes and automatically draw their connectors:
function draw(){
// clear the canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<boxes.length;i++){
var box=boxes[i];
ctx.fillRect(box.x,box.y,box.w,box.h);
}
for(var i=0;i<connectors.length;i++){
var connector=connectors[i];
var box1=boxes[connector.box1];
var box2=boxes[connector.box2];
ctx.beginPath();
ctx.moveTo(box1.x+box1.w/2,box1.y+box1.h/2);
ctx.lineTo(box2.x+box2.w/2,box2.y+box2.h/2);
ctx.stroke();
}
}
The code below allows any box to be dragged and remain connected.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/GX6HS/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; padding:20px;}
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var startX;
var startY;
var isDown=false;
var dragTarget;
var boxes=[];
boxes.push({x:50,y:25,w:75,h:50}); // x,y,width,height
boxes.push({x:200,y:100,w:50,h:50});
var connectors=[];
connectors.push({box1:0,box2:1});
draw();
function draw(){
// clear the canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<boxes.length;i++){
var box=boxes[i];
ctx.fillRect(box.x,box.y,box.w,box.h);
}
for(var i=0;i<connectors.length;i++){
var connector=connectors[i];
var box1=boxes[connector.box1];
var box2=boxes[connector.box2];
ctx.beginPath();
ctx.moveTo(box1.x+box1.w/2,box1.y+box1.h/2);
ctx.lineTo(box2.x+box2.w/2,box2.y+box2.h/2);
ctx.stroke();
}
}
function hit(x,y){
for(var i=0;i<boxes.length;i++){
var box=boxes[i];
if(x>=box.x && x<=box.x+box.w && y>=box.y && y<=box.y+box.h){
dragTarget=box;
return(true);
}
}
return(false);
}
function handleMouseDown(e){
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
isDown=hit(startX,startY);
}
function handleMouseUp(e){
// Put your mouseup stuff here
dragTarget=null;
isDown=false;
}
function handleMouseOut(e){
handleMouseUp(e);
}
function handleMouseMove(e){
if(!isDown){return;}
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
var dx=mouseX-startX;
var dy=mouseY-startY;
startX=mouseX;
startY=mouseY;
dragTarget.x+=dx;
dragTarget.y+=dy;
draw();
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
}); // end $(function(){});
</script>
</head>
<body>
<p>Drag boxes--they remain connected</p>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Related

Add Href to canvas element

I am using HexagonTools to draw hexagon using canvas.
I need to add an href link to elements of canvas.
I have tried this code:
function drawHexGrid()
{
var linkText="http://stackoverflow.com";
var linkX=5;
var linkY=15;
var linkHeight=10;
var linkWidth;
var inLink = false;
var grid = new HT.Grid(800, 600);
var canvas = document.getElementById("hexCanvas");
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, 800, 600);
for(var h in grid.Hexes)
{
grid.Hexes[h].draw(ctx);
linkWidth=ctx.measureText(linkText).width;
canvas.addEventListener("mousemove", on_mousemove, false);
canvas.addEventListener("click", on_click, false);
}
}
But this is not working, I need a simple example on how to develop this, I have already looked at this SOF Question
But I couldn't develop it
You can test which hexagon you mouse clicked using context.isPointInPath.
Listen for mousedown events
In mousedown, fetch the mouseX, mouseY
Recreate each of your hex paths (no need to actually stroke/fill them).
For each hex, use .isPointInPath(mouseX,mouseY) to see if the mouse clicked in this hex.
If you find a clicked hex, use window.open(theUrl, '_blank') to navigate to its associated url.
In Hexagon Tools, each hex has a points property which you can use to receate each of your hex paths.
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }
var isDown=false;
var startX,startY;
var hexes=[];
hexes.push({
points:[{x:57.5,y:63},{x:42.5,y:63},{x:35,y:50},{x:42.5,y:37},{x:57.5,y:37},{x:65,y:50}],
url:'http://stackoverflow.com',
});
draw();
$("#canvas").mousedown(function(e){handleMouseDown(e);});
function draw(){
for(var i=0;i<hexes.length;i++){
var h=hexes[i];
ctx.beginPath();
ctx.moveTo(h.points[0].x,h.points[0].y);
for(var j=1;j<h.points.length;j++){
ctx.lineTo(h.points[j].x,h.points[j].y);
}
ctx.closePath();
ctx.stroke();
}
}
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
for(var i=0;i<hexes.length;i++){
var h=hexes[i];
ctx.beginPath();
ctx.moveTo(h.points[0].x,h.points[0].y);
for(var j=1;j<h.points.length;j++){
ctx.lineTo(h.points[j].x,h.points[j].y);
}
ctx.closePath();
//if(ctx.isPointInPath(mouseX,mouseY)){ window.open(h.url, '_blank'); }
if(ctx.isPointInPath(mouseX,mouseY)){ alert('Navigate to: '+h.url); }
}
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Click in the hexagon to navigate to Stackoverflow.com</h4>
<canvas id="canvas" width=300 height=300></canvas>

HTML5 Canvas Ghosting Issue

When a user drags their cursor across the screen a square canvas is drawn. My issue is that the canvas is "ghosting". I think it is possible to fix this problem using redraw() or clearrect() but I'm not sure how to implement those functions in this case. Thanks.
drawSquare = true;
//DRAG TO CREATE RECTANGLE
if(drawSquare == true){
$(document).mousedown(function(e) {
dragShape = true;
posYdown = e.pageY;
posXdown = e.pageX;
});
$(document).mousemove(function(e) {
if(dragShape == true) {
var c=document.getElementById("canvas1");
var ctx=c.getContext("2d");
ctx.fillStyle = "black";
ctx.fillRect(posXdown ,posYdown ,e.pageX - posXdown ,e.pageY - posYdown);
}
});
$(document).mouseup(function() {
dragShape = false;
});
}
Yes, you need context.clearRect to remove previously drawn pixels or you will have ghost remnants.
Here's a refactored version of your code:
Hints:
Clear the canvas before drawing a new rectangle.
Just get references to your canvas and context once at the beginning of your app.
Adjust your mouse position by the offset X,Y of the canvas (in case you later reposition your canvas on the page).
Good luck with your learning!
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var dragShape=false;
var posXdown,posYdown;
function handleMouseDown(e){
e.preventDefault();
e.stopPropagation();
posXdown=parseInt(e.clientX-offsetX);
posYdown=parseInt(e.clientY-offsetY);
dragShape = true;
}
function handleMouseUp(e){
e.preventDefault();
e.stopPropagation();
dragShape = false;
}
function handleMouseMove(e){
if(!dragShape){return;}
e.preventDefault();
e.stopPropagation();
var mouseX=parseInt(e.clientX-offsetX);
var mouseY=parseInt(e.clientY-offsetY);
var width=mouseX-posXdown;
var height=mouseY-posYdown;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillRect(posXdown,posYdown,width,height);
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseUp(e);});
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<canvas id="canvas" width=300 height=300></canvas>

inclined calendar with html5 and css3 and / or any other idea

I need something like the picture shown in the link below, I have no idea how to do it, the most important think is that the calendar is generated dynamically.... this calendar 'll display in a web page.
Interesting project!
You can use canvas transforms to radiate your calendar around a centerpoint.
A Demo: http://jsfiddle.net/m1erickson/Q7S9L/
The idea is to draw a line of your calendar vertically into a column:
And then rotate that column using canvas transforms.
Transforms include context.translate (which moves) and context.rotate (which rotates)
// save the context state
ctx.save();
// translate to the centerpoint around which we will rotate the column
ctx.translate(cx,cy);
// rotate the canvas (which will rotate the column)
ctx.rotate( desiredRadianAngle );
// now draw the column and it will be rotated to the desired angle
Here's example code:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var year=2014;
var PI2=Math.PI*2;
var cx=375;
var cy=375;
var radialIncrement=15;
var rotationIncrement=-Math.PI/31;
var months=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
var days=[31,28,31,30,31,30,31,31,30,31,30,31];
var dayNames=['Su','M','Tu','W','Th','F','Sa','Su','M','Tu','W','Th','F','Sa','Su','M','Tu','W','Th','F','Sa','Su','M','Tu','W','Th','F','Sa','Su','M','Tu','W','Th','F','Sa','Su','M','Tu','W','Th','F','Sa'];
var monthsFirstWeekday=[]
for(var m=1;m<=12;m++){
monthsFirstWeekday.push(new Date(m+"/01/"+year).getDay());
}
for(var d=0;d<=38;d++){
ctx.save();
ctx.translate(cx,cy);
ctx.rotate(rotationIncrement*(31-d)+Math.PI/2);
var x=-3;
var y=-13*radialIncrement-150;
ctx.font="12px verdana";
ctx.fillStyle="blue";
ctx.fillText(dayNames[d],x,y);
ctx.restore();
}
for(var m=0;m<months.length;m++){
ctx.save();
ctx.translate(cx,cy+25);
ctx.rotate(Math.PI*3/2);
ctx.fillStyle="blue";
ctx.fillText(months[m],0,-(months.length-m)*radialIncrement-150);
ctx.restore();
}
for(var d=0;d<=38;d++){
ctx.save();
ctx.translate(cx,cy);
ctx.rotate(rotationIncrement*(31-d)+Math.PI/2);
for(var m=0;m<months.length;m++){
var x=0;
var y=-(months.length-m)*radialIncrement-150;
var dd=d-monthsFirstWeekday[m]+1;
if(dd>0 && dd<=days[m]){
ctx.fillStyle="black";
ctx.fillText(dd,x,y);
}else{
ctx.beginPath();
ctx.arc(x+3,y,1,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle="red";
ctx.fill();
}
}
ctx.restore();
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=775 height=650></canvas>
</body>
</html>

How set a identification to Canvas Path?

Good morning everyone.
I'm building a graph for the enterprise system where I work, but I came across a problem where I need to insert some kind of identification, that I may be rescued by JavaScript (name, id, label, ...).
Someone could tell me how I could do to identify each element of the graph separately? To be more exact, what I'm wondering identifies each element arc is created.
If someone wanted to see the code to understand it better, I'll put the link here:
- JS Bin
Nothing you draw on the canvas is automatically remembered or labeled with an id.
All canvas drawings become forgotten and inaccessible pixels. However there are ways of keeping track of your various drawings.
Instead of keeping your posX,posY and color info in separate parallel arrays, how about creating an object for each node.
Then you could add the id property to each node object:
var nodes=[];
nodes.push({id:"sun", x:100, y:100, color:"yellow"});
nodes.push({id:"earth", x:50, y:50, color:"blue"});
nodes.push({id:"moon", x:50, y:60, color:"gray"});
And, of course, pull the graphing info from each node...
You can draw your graph inside a function and apply a scaleFactor when needed.
function drawGraph(){
context.clearRect(0,0,canvas.width,canvas.height);
context.save();
context.scale(scaleFactor,scaleFactor);
for(var i=0; i<nodes.length;i++){
var node=nodes[i];
context.beginPath();
context.moveTo(centerCanvasX,centerCanvasY);
context.lineTo(node.x,node.y);
context.stroke();
context.beginPath();
context.arc(node.x,node.y,node.radius,0,Math.PI*2,false);
context.closePath();
context.stroke();
context.fillStyle=node.color;
context.fill();
}
context.restore();
}
For dragging/clicking/etc, You could hit test each node array element until you found a match.
function hit(x,y){
for(var i=0;i<nodes.length;i++){
var node=nodes[i];
var dx=node.x-x;
var dy=node.y-y;
var rr=node.radius;
if(dx*dx+dy*dy<rr*rr){
return(i);
}
}
return(-1);
}
The matching element would have the id you need.
If your graph is scaled and you're using mouse coordinates to drag, you must adjust the coordinates that the browser gives you by the current scaleFactor of your graph:
mouseX=parseInt(event.clientX-offsetX)/scaleFactor;
mouseY=parseInt(event.clientY-offsetY)/scaleFactor;
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/c4hsW/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; padding:20px; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var context=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var centerCanvasX=canvas.width/2;
var centerCanvasY=canvas.height/2;
var startX;
var startY;
var isDown=false;
var nodes=[];
var dragNode;
var scaleFactor=1.00;
nodes.push({id:"sun", x:centerCanvasX, y:centerCanvasY, radius:20, color:"yellow"});
nodes.push({id:"earth", x:50, y:50, radius:5, color:"blue"});
nodes.push({id:"moon", x:50, y:65, radius:3, color:"gray"});
drawGraph();
function drawGraph(){
context.clearRect(0,0,canvas.width,canvas.height);
context.save();
context.scale(scaleFactor,scaleFactor);
for(var i=0; i<nodes.length;i++){
var node=nodes[i];
context.beginPath();
context.moveTo(centerCanvasX,centerCanvasY);
context.lineTo(node.x,node.y);
context.stroke();
context.beginPath();
context.arc(node.x,node.y,node.radius,0,Math.PI*2,false);
context.closePath();
context.stroke();
context.fillStyle=node.color;
context.fill();
}
context.restore();
}
function hit(x,y){
for(var i=0;i<nodes.length;i++){
var node=nodes[i];
var dx=node.x-x;
var dy=node.y-y;
var rr=node.radius;
if(dx*dx+dy*dy<rr*rr){
return(i);
}
}
return(-1);
}
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX)/scaleFactor;
mouseY=parseInt(e.clientY-offsetY)/scaleFactor;
var i=hit(mouseX,mouseY);
if(i>=0){
startX=mouseX;
startY=mouseY;
isDown=true;
dragNode=nodes[i];
}
}
function handleMouseUp(e){
isDown=false;
}
function handleMouseOut(e){
isDown=false;
}
function handleMouseMove(e){
if(!isDown){return;}
// get the current mouse position
mouseX=parseInt(e.clientX-offsetX)/scaleFactor;
mouseY=parseInt(e.clientY-offsetY)/scaleFactor;
// reposition the dragged node
dragNode.x+=(mouseX-startX);
dragNode.y+=(mouseY-startY);
startX=mouseX;
startY=mouseY;
// redraw the graph
drawGraph();
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
$("#bigger").click(function(){
scaleFactor+=0.20;
drawGraph();
});
$("#smaller").click(function(){
scaleFactor-=0.20;
drawGraph();
});
}); // end $(function(){});
</script>
</head>
<body>
<button id="bigger">Scale Up</button>
<button id="smaller">Scale Down</button><br>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

drag and drop multiple images from one canvas to other

How do I drag and drop multiple images from one canvas to another? My manager has given me this task, it's been 3 days and I am not able to do this as I'm new to HTML5. I've searched Google but only got it working for one image. Please help me in this matter.
This is what I got for one image:
<pre>
<script>
window.onload = function ()
{
var canvas1 = document.getElementById("cvs1");
var canvas2 = document.getElementById("cvs2");
var context1 = canvas1.getContext('2d');
var context2 = canvas2.getContext('2d');
var imageXY = {x: 5, y: 5};
/**
* This draws the image to the canvas
*/
function Draw ()
{
//Clear both canvas first
context1.clearRect(0,0,canvas1.width,canvas1.height);
context2.clearRect(0,0,canvas2.width,canvas2.height);
//Draw a red rectangle around the image
if (state && state.dragging) {
state.canvas.getContext('2d').strokeStyle = 'red';
state.canvas.getContext('2d').strokeRect(imageXY.x - 2.5,
imageXY.y - 2.5,
state.image.width + 5,
state.image.height + 5);
}
// Now draw the image
state.canvas.getContext('2d').drawImage(state.image, imageXY.x, imageXY.y);
}
canvas2.onclick =
canvas1.onclick = function (e)
{
if (state && state.dragging) {
state.dragging = false;
Draw();
return;
}
var mouseXY = RGraph.getMouseXY(e);
state.canvas = e.target;
if ( mouseXY[0] > imageXY.x
&& mouseXY[0] < (imageXY.x + state.image.width)
&& mouseXY[1] > imageXY.y
&& mouseXY[1] < (imageXY.y + state.image.height)) {
state.dragging = true;
state.originalMouseX = mouseXY[0];
state.originalMouseY = mouseXY[1];
state.offsetX = mouseXY[0] - imageXY.x;
state.offsetY = mouseXY[1] - imageXY.y;
}
}
canvas1.onmousemove =
canvas2.onmousemove = function (e)
{
if (state.dragging) {
state.canvas = e.target;
var mouseXY = RGraph.getMouseXY(e);
// Work how far the mouse has moved since the mousedon event was triggered
var diffX = mouseXY[0] - state.originalMouseX;
var diffY = mouseXY[1] - state.originalMouseY;
imageXY.x = state.originalMouseX + diffX - state.offsetX;
imageXY.y = state.originalMouseY + diffY - state.offsetY;
Draw();
e.stopPropagation();
}
}
/**
* Load the image on canvas1 initially and set the state up with some defaults
*/
state = {}
state.dragging = false;
state.canvas = document.getElementById("cvs1");
state.image = new Image();
state.image.src = 'images/logo.png';
state.offsetX = 0;
state.offsetY = 0;
state.image.onload = function ()
{
Draw();
}
}
</script>
<canvas id="cvs1" width="400" height="125" style="float: left">[No canvas support]</canvas>
<canvas id="cvs2" width="400" height="125" style="float: left; margin-left: 100px">[No canvas support]</canvas>
</pre>
Drag/Drop multiple items between 2 canvases
Here’s what the code does:
Click to select one or more images from the top source canvas
Click an image again to toggle its selection on/off
Once you have made all your selections, drag from the top canvas to the bottom canvas
Your selections will be moved to the bottom canvas
Some explanation about the code:
Each image is stored in an array called Images
An item-object for each image is stored in an array called items
The item-object contains an item’s description, image-url, an isSelected flag and an isDropped flag.
The mouseup event handler of the top source canvas checks for hits on images and toggles their isSelected flags.
The mouseup event handler responds to drops onto the bottom drop canvas. It checks for selected items and records them as dropped by setting their isDropped flags.
The drawContainer function distributes items between the source and drop canvas based on their isDropped flags (isDropped==false are drawn in the top source canvas – isDropped==true are drawn in the bottom drop canvas)
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/3KqgX/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; padding:10px; }
canvas{border:1px solid red;}
#canvas {
}
#canvas:active {
cursor: move;
}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var drop=document.getElementById("dropzone");
var dropCtx=drop.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var mouseIsDown=false;
var frameWidth=128;
var frameHeight=128;
// checkmark for selected
var checkmark=document.createElement("img");
checkmark.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/smallCheckmark.png";
var images=[];
var items=[];
items.push({description:"House#1",url:"https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house1.jpg",isSelected:false,isDropped:false,x:0,y:0});
items.push({description:"House#2",url:"https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house2.jpg",isSelected:false,isDropped:false,x:0,y:0});
items.push({description:"House#3",url:"https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house3.jpg",isSelected:false,isDropped:false,x:0,y:0});
var imgLoadCount=0;
for(var i=0;i<items.length;i++){
images[i]=document.createElement("img");
images[i].onload=function(){
if(++imgLoadCount>=items.length){ draw(); }
}
images[i].src=items[i].url;
}
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
dropCtx.clearRect(0,0,drop.width,drop.height);
var canvasX=0;
var dropX=0;
//
for(var i=0;i<items.length;i++){
if(items[i].isDropped){
x=dropX*160+10;
drawContainer(dropCtx,i,x,20);
dropX++;
items[i].x=x;
}else{
x=canvasX*160+10;
drawContainer(ctx,i,x,20);
canvasX++;
items[i].x=x;
}
}
}
// draw image container
function drawContainer(context,index,x,y){
context.beginPath();
context.rect(x,y+frameHeight,frameWidth,30);
context.fillStyle="black";
context.fill();
context.beginPath();
context.fillStyle="white";
context.font="10pt Verdana";
context.fillText(items[index].description,x+10,y+frameHeight+18);
// draw a thumbnail of the image
var img=images[index];
if(img.width>=img.height){
context.drawImage(img,0,0,img.width,img.height,
x,y,128,128*img.height/img.width);
}else{
context.drawImage(img,0,0,img.width,img.height,
x,y,128*img.width/img.height,128); // edited s/b [,128], not [/128]
}
// outer frame (green if selected)
context.beginPath();
context.rect(x-2,y-2,frameWidth+4,frameHeight+30+4);
context.lineWidth=3;
context.strokeStyle="lightgray";
if(items[index].isSelected){
context.strokeStyle="green";
context.drawImage(checkmark,x+frameWidth-30,y+frameHeight+3);
}
context.stroke();
}
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
mouseIsDown=true;
}
function handleMouseUp(e){
mouseIsDown=false;
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mouseup stuff here
for(var i=0;i<items.length;i++){
var item=items[i];
// have we clicked on something?
if(!item.isDropped && mouseX>=item.x && mouseX<=item.x+frameWidth){
// if so, toggle its selection
items[i].isSelected=!(items[i].isSelected);
draw();
}
}
}
function handleMouseOut(e){
if(!mouseIsDown){return;}
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mouseOut stuff here
}
function handleMouseMove(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
}
function handleDrop(e){
for(var i=0;i<items.length;i++){
if(items[i].isSelected){
items[i].isDropped=true;
items[i].isSelected=false;
console.log(i);
}
}
draw();
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
$("#dropzone").mouseup(function(e){handleDrop(e);});
}); // end $(function(){});
</script>
</head>
<body>
<p>Click an item to toggle it's selection</p>
<p>Drag from top to bottom canvas to drop selected items</p>
<canvas id="canvas" width=500 height=200></canvas><br>
<canvas id="dropzone" width=500 height=200></canvas>
</body>
</html>
[Addition: Alternate code to sort bottom canvas by order dropped]
function handleDrop(e){
for(var i=items.length-1;i>=0;i--){
if(items[i].isSelected){
items[i].isDropped=true;
items[i].isSelected=false;
// sort the bottom canvas by order dropped
var move=items[i];
items.splice(i,1);
items.push(move);
}
}
draw();
}
[ Edited to present a solution in KineticJS ]
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/bSpBF/
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.1.min.js"></script>
<style>
body{ background-color: ivory; padding:10px;}
#container1,#container2{
border:solid 1px #ccc;
margin-top: 10px;
width:300px;
height:100px;
}
#container2{
height:300px;
}
</style>
<script>
$(function(){
var highlightWidth=8;
var stage = new Kinetic.Stage({
container: 'container1',
width: 300,
height: 100
});
var layer = new Kinetic.Layer();
stage.add(layer);
var dropzone = new Kinetic.Stage({
container: 'container2',
width: 300,
height: 300
});
var dropLayer = new Kinetic.Layer();
dropzone.add(dropLayer);
// these must go after the creation of stages & layers
addBackground(stage,layer,dropLayer);
layer.draw();
addBackground(dropzone,dropLayer,layer);
dropLayer.draw();
// get images & then trigger start()
var images={};
var URLs = {
house1: 'https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-3.jpg',
house2: 'https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-4.jpg',
house3: 'https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-1.jpg'
};
loadImages(URLs,start);
function start(){
var house1=kImage(images.house1,10,10,50,50,layer);
var house2=kImage(images.house2,75,10,50,50,layer);
var house3=kImage(images.house3,140,10,50,50,layer);
layer.draw();
}
function swapStagesIfSelected(sourceLayer,destinationLayer,startX,startY){
// get all elements on the source layer
var elements=sourceLayer.get("Image");
// don't let dropped elements fall off the stage
var totalWidth=0;
var maxHeight=-999;
var layerWidth=destinationLayer.getStage().getWidth();
var layerHeight=destinationLayer.getStage().getHeight();
for(var i=0;i<elements.length;i++){
if(elements[i].isSelected){
totalWidth+=elements[i].getWidth();
maxHeight=Math.max(elements[i].getHeight(),maxHeight);
}
}
if(startX+totalWidth>layerWidth){
startX=layerWidth-totalWidth-15;
}
if(startY+maxHeight>layerHeight){
startY=layerHeight-maxHeight-15;
}
// move all selected images
// to the clicked x/y of the destination layer
for(var i=0;i<elements.length;i++){
var element=elements[i];
if(element.isSelected){
var img=element.getImage();
kImage(img,startX,startY,element.getWidth(),element.getHeight(),destinationLayer);
startX+=element.getWidth()+10;
element.remove();
}
}
sourceLayer.draw();
destinationLayer.draw();
}
// build the specified KineticJS Image and add it to the specified layer
function kImage(image,x,y,width,height,theLayer){
var image=new Kinetic.Image({
image:image,
x:x,
y:y,
width:width,
height:height,
strokeWidth:0.1,
stroke:"green",
draggable:true
});
image.myLayer=theLayer;
image.isSelected=false;
image.on("click",function(){
highlight(this);
this.myLayer.draw();
});
image.myLayer.add(image);
return(image);
}
// build a background image and add it to the specified stage
function addBackground(theStage,theLayer,otherLayer){
var background = new Kinetic.Rect({
x: 0,
y: 0,
width: theStage.getWidth(),
height: theStage.getHeight(),
fill: "white",
stroke: "green",
strokeWidth: 1
});
background.on("click",function(){
var pos=theStage.getMousePosition();
var mouseX=parseInt(pos.x);
var mouseY=parseInt(pos.y);
swapStagesIfSelected(otherLayer,theLayer,mouseX,mouseY);
});
theLayer.add(background);
}
///////////// Image loader
function loadImages(URLs, callback) {
var loaded = 0;
var needed = 0;
for(var url in URLs) { needed++; console.log(url); }
for(var url in URLs) {
images[url] = new Image();
images[url].onload = function() {
if(++loaded >= needed) {
callback(images);
}
};
images[url].src = URLs[url];
}
}
///////////// Toggle Highlighting
function highlight(element,setStrokeWidth){
if(setStrokeWidth){
element.setStrokeWidth(setStrokeWidth);
}else{
if(element.getStrokeWidth()>5){
element.setStrokeWidth(0.1);
element.isSelected=false;
}else{
element.setStrokeWidth(highlightWidth);
element.isSelected=true;
}
}
}
}); // end $(function(){});
</script>
</head>
<body>
<p>Click on image(s) to toggle selection</p>
<p>Then click in the other canvas to drop</p>
<div id="container1"></div>
<div id="container2"></div>
<button id="clear">Clear Hightlights</button>
<button id="swap">Swap Selected</button>
</body>
</html>