Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><strong>Drag/Drop multiple items between 2 canvases</strong></p> <p>Here’s what the code does:</p> <ul> <li>Click to select one or more images from the top source canvas</li> <li>Click an image again to toggle its selection on/off</li> <li>Once you have made all your selections, drag from the top canvas to the bottom canvas</li> <li>Your selections will be moved to the bottom canvas</li> </ul> <p><img src="https://i.stack.imgur.com/4kk7S.png" alt="enter image description here"></p> <p>Some explanation about the code:</p> <ul> <li>Each image is stored in an array called Images</li> <li>An item-object for each image is stored in an array called items</li> <li>The item-object contains an item’s description, image-url, an isSelected flag and an isDropped flag.</li> <li>The mouseup event handler of the top source canvas checks for hits on images and toggles their isSelected flags.</li> <li>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.</li> <li>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)</li> </ul> <p>Here is code and a Fiddle: <a href="http://jsfiddle.net/m1erickson/3KqgX/" rel="nofollow noreferrer">http://jsfiddle.net/m1erickson/3KqgX/</a></p> <pre><code>&lt;!doctype html&gt; &lt;html&gt; &lt;head&gt; &lt;link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /&gt; &lt;!-- reset css --&gt; &lt;script type="text/javascript" src="http://code.jquery.com/jquery.min.js"&gt;&lt;/script&gt; &lt;style&gt; body{ background-color: ivory; padding:10px; } canvas{border:1px solid red;} #canvas { } #canvas:active { cursor: move; } &lt;/style&gt; &lt;script&gt; $(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&lt;items.length;i++){ images[i]=document.createElement("img"); images[i].onload=function(){ if(++imgLoadCount&gt;=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&lt;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&gt;=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&lt;items.length;i++){ var item=items[i]; // have we clicked on something? if(!item.isDropped &amp;&amp; mouseX&gt;=item.x &amp;&amp; mouseX&lt;=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&lt;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(){}); &lt;/script&gt; &lt;/head&gt; &lt;body&gt; &lt;p&gt;Click an item to toggle it's selection&lt;/p&gt; &lt;p&gt;Drag from top to bottom canvas to drop selected items&lt;/p&gt; &lt;canvas id="canvas" width=500 height=200&gt;&lt;/canvas&gt;&lt;br&gt; &lt;canvas id="dropzone" width=500 height=200&gt;&lt;/canvas&gt; &lt;/body&gt; &lt;/html&gt; </code></pre> <p><strong>[Addition: Alternate code to sort bottom canvas by order dropped]</strong></p> <pre><code> function handleDrop(e){ for(var i=items.length-1;i&gt;=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(); } </code></pre> <p><strong>[ Edited to present a solution in KineticJS ]</strong></p> <p>Here is code and a Fiddle: <a href="http://jsfiddle.net/m1erickson/bSpBF/" rel="nofollow noreferrer">http://jsfiddle.net/m1erickson/bSpBF/</a></p> <pre><code>&lt;!DOCTYPE html&gt; &lt;html&gt; &lt;head&gt; &lt;script type="text/javascript" src="http://code.jquery.com/jquery.min.js"&gt;&lt;/script&gt; &lt;script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.1.min.js"&gt;&lt;/script&gt; &lt;style&gt; body{ background-color: ivory; padding:10px;} #container1,#container2{ border:solid 1px #ccc; margin-top: 10px; width:300px; height:100px; } #container2{ height:300px; } &lt;/style&gt; &lt;script&gt; $(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 &amp; layers addBackground(stage,layer,dropLayer); layer.draw(); addBackground(dropzone,dropLayer,layer); dropLayer.draw(); // get images &amp; 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&lt;elements.length;i++){ if(elements[i].isSelected){ totalWidth+=elements[i].getWidth(); maxHeight=Math.max(elements[i].getHeight(),maxHeight); } } if(startX+totalWidth&gt;layerWidth){ startX=layerWidth-totalWidth-15; } if(startY+maxHeight&gt;layerHeight){ startY=layerHeight-maxHeight-15; } // move all selected images // to the clicked x/y of the destination layer for(var i=0;i&lt;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 &gt;= needed) { callback(images); } }; images[url].src = URLs[url]; } } ///////////// Toggle Highlighting function highlight(element,setStrokeWidth){ if(setStrokeWidth){ element.setStrokeWidth(setStrokeWidth); }else{ if(element.getStrokeWidth()&gt;5){ element.setStrokeWidth(0.1); element.isSelected=false; }else{ element.setStrokeWidth(highlightWidth); element.isSelected=true; } } } }); // end $(function(){}); &lt;/script&gt; &lt;/head&gt; &lt;body&gt; &lt;p&gt;Click on image(s) to toggle selection&lt;/p&gt; &lt;p&gt;Then click in the other canvas to drop&lt;/p&gt; &lt;div id="container1"&gt;&lt;/div&gt; &lt;div id="container2"&gt;&lt;/div&gt; &lt;button id="clear"&gt;Clear Hightlights&lt;/button&gt; &lt;button id="swap"&gt;Swap Selected&lt;/button&gt; &lt;/body&gt; &lt;/html&gt; </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload