Add Href to canvas element - html

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>

Related

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>

Straighten image in HTML5 canvas by rotating from the center of the image and zoom

Instagram has a great straighten feature
https://help.instagram.com/135826209959819
Where if you straighten an image it will rotate from the center of the image and zoom.
Rotating in a canvas rotates from not the center(i think it is from 0,0)
And zoom zooms towards 0,0
context.rotate(.01)
context.scale(2.2, 2.2)
Do you know a way to force the canvas to rotate from the center, zoom towards the center?
Cheers
To answer your question...You can set the desired rotation point by using:
context.translate(desiredRotationX,desiredRotationY)
This causes context.rotate to rotate around your desired rotation point.
But Note: The proper rotation point of an unstraightened image might/might not be the center of the image. It depends on the original rotation point of the original image.
Perhaps a better way of straightening an image would be to:
Find the top-left and top-right corner points of the image.
Determine the angle of the line connecting those 2 points.
Rotate the image by the negative of the angle.
Example code and Demo:
var canvas1=document.getElementById("canvas1");
var ctx1=canvas1.getContext("2d");
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();
var cw,ch,topLeft,topRight,bottomRight,bottomLeft;
var pT,pR,pB,pL;
var img=new Image();
img.crossOrigin='anonymous';
img.onload=start;
// img.src="https://dl.dropboxusercontent.com/u/139992952/multple/tiltedCW.png";
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/tiltedCCW.png";
function start(){
cw=canvas.width=img.width;
ch=canvas.height=img.height;
ctx.drawImage(img,0,0);
calcCorners();
$("#canvas").mousedown(function(e){handleMouseDown(e);});
}
function handleMouseDown(e){
e.preventDefault();
e.stopPropagation();
mx=parseInt(e.clientX-offsetX);
my=parseInt(e.clientY-offsetY);
var dT=calcDistance(mx,my,pT);
var dR=calcDistance(mx,my,pR);
var dB=calcDistance(mx,my,pB);
var dL=calcDistance(mx,my,pL);
if(dT<dR && dT<dB && dT<dL){
topLeft=pT;
topRight=pR;
bottomRight=pB
}else if(dR<dT && dR<dB && dR<dL){
topLeft=pR;
topRight=pB;
bottomRight=pL;
}else if(dB<dT && dB<dR && dB<dL){
topLeft=pB;
topRight=pL;
bottomRight=pT;
}else{
topLeft=pL;
topRight=pT;
bottomRight=pR;
}
// straighten
var dx=topRight.x-topLeft.x;
var dy=topRight.y-topLeft.y;
var angle=Math.atan2(dy,dx);
var width=Math.sqrt(dx*dx+dy*dy);
dx=bottomRight.x-topRight.x;
dy=bottomRight.y-topRight.y;
var height=Math.sqrt(dx*dx+dy*dy);
canvas1.width=width;
canvas1.height=height;
ctx1.rotate(-angle);
ctx1.drawImage(img,-topLeft.x,-topLeft.y);
}
function calcDistance(mx,my,p){
var dx=mx-p.x;
var dy=my-p.y;
return(Math.sqrt(dx*dx+dy*dy));
}
function calcCorners(){
var data=ctx.getImageData(0,0,cw,ch).data;
// pT (topmost)
for(var y=0;y<ch;y++){
for(var x=0;x<cw;x++){
var n=(y*cw+x)*4+3;
if(!pT &&data[n]>40){ pT={x:x,y:y}; break; }
}}
// pR (rightmost)
for(var x=cw-1;x>=0;x--){
for(var y=ch-1;y>=0;y--){
var n=(y*cw+x)*4+3;
if(!pR &&data[n]>40){ pR={x:x,y:y}; break; }
}}
// pB (bottommost)
for(var y=ch-1;y>=0;y--){
for(var x=cw-1;x>=0;x--){
var n=(y*cw+x)*4+3;
if(!pB &&data[n]>40){ pB={x:x,y:y}; break; }
}}
// pL (leftmost)
for(var x=0;x<cw;x++){
for(var y=0;y<ch;y++){
var n=(y*cw+x)*4+3;
if(!pL && data[n]>40){ pL={x:x,y:y}; break; }
}}
}
body{ background-color: white; }
canvas{border:1px solid purple;}
#red{color:red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Original: tilted with transparency</h4>
<h4 id=red>Click near the top-left corner of the image</h4>
<canvas id="canvas" width=300 height=300></canvas><br>
<h4>Straightened</h4>
<canvas id="canvas1" width=300 height=300></canvas>

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>

Connect canvas with lines

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>

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>