Sahar Ch.
Sahar Ch.

Reputation: 489

Allowing the drag after dropping an image onto canvas

$(function() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

// get the offset position of the container
var $canvas = $("#canvas");
var Offset = $canvas.offset();
var offsetX = Offset.left;
var offsetY = Offset.top;

// select all .tool's
var $tools = $(".tool");

// make all .tool's draggable
$tools.draggable({
helper: 'clone',
revert: 'invalid'
});


    // assign each .tool its index in $tools
$tools.each(function (index, element) {
$(this).data("toolsIndex", index);
});

// make the canvas a dropzone
$canvas.droppable({
drop: dragDrop,
});

// handle a drop into the canvas
function dragDrop(e, ui) {

// get the drop point (be sure to adjust for border)
var x = parseInt(ui.offset.left - offsetX);
var y = parseInt(ui.offset.top - offsetY);

// get the drop payload (here the payload is the $tools index)
var theIndex = ui.draggable.data("toolsIndex");

// drawImage at the drop point using the dropped image 
ctx.drawImage($tools[theIndex], x, y, 32, 32);

}
});

I tried many things but I failed. This code allows me to drag and drop multiple images onto a canvas element. What I need to do is to add the possibility of dragging the image again after it's been dropped. I know that the canvas has to be redrawn each time, but I didn't know how.

Can anyone fix this for me?

Upvotes: 4

Views: 4272

Answers (2)

markE
markE

Reputation: 105035

Since you commented that you're open to canvas libraries, here's an example that lets you:

  • drag an img element from a toolbar-div using jqueryUI.
  • drop the img on the canvas and create a KineticJS.Image object that you can drag around the canvas.

A Demo: http://jsfiddle.net/m1erickson/gkefk/

Results: An img dragged 3X from blue toolbar, dropped on gray canvas, and then dragged on the canvas.

result screenshot

Here's a commented code example:

$(function() {

  // get a reference to the house icon in the toolbar
  // hide the icon until its image has loaded
  var $house = $("#house");
  $house.hide();
  
  

  // get the offset position of the kinetic container
  var $stageContainer = $("#container");
  var stageOffset = $stageContainer.offset();
  var offsetX = stageOffset.left;
  var offsetY = stageOffset.top;

  // create the Kinetic.Stage and layer
  var stage = new Kinetic.Stage({
    container: 'container',
    width: 350,
    height: 350
  });
  var layer = new Kinetic.Layer();
  stage.add(layer);

  // start loading the image used in the draggable toolbar element
  // this image will be used in a new Kinetic.Image
  var image1 = new Image();
  image1.onload = function() {
    $house.show();
  }
  image1.src = "https://i.sstatic.net/GeibZ.png";

  // make the toolbar image draggable
  $house.draggable({
    helper: 'clone',
  });

  // set the data payload
  $house.data("url", "house.png"); // key-value pair
  $house.data("width", "32"); // key-value pair
  $house.data("height", "33"); // key-value pair
  $house.data("image", image1); // key-value pair

  // make the Kinetic Container a dropzone
  $stageContainer.droppable({
    drop: dragDrop,
  });

  // handle a drop into the Kinetic container
  function dragDrop(e, ui) {

    // get the drop point
    var x = parseInt(ui.offset.left - offsetX);
    var y = parseInt(ui.offset.top - offsetY);

    // get the drop payload (here the payload is the image)
    var element = ui.draggable;
    var data = element.data("url");
    var theImage = element.data("image");

    // create a new Kinetic.Image at the drop point
    // be sure to adjust for any border width (here border==1)
    var image = new Kinetic.Image({
      name: data,
      x: x,
      y: y,
      image: theImage,
      draggable: true
    });
    layer.add(image);
    layer.draw();
  }

}); // end $(function(){});
body {
  padding: 20px;
}

#container {
  border: solid 1px #ccc;
  margin-top: 10px;
  width: 350px;
  height: 350px;
}

#toolbar {
  width: 350px;
  height: 35px;
  border: solid 1px blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/kineticjs/4.7.2/kinetic.min.js"></script>
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Prototype</title>
<script
  src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"
  integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU="
  crossorigin="anonymous"></script>
</head>

<body>
  <div id="toolbar">
    <img id="house" width=32 height=32 src="https://i.sstatic.net/GeibZ.png"><br>
  </div>
  <div id="container"></div>
</body>

</html>

Upvotes: 6

Oscar Paz
Oscar Paz

Reputation: 18312

What you want is certainly not easy. Now you just drop the image and draw it in the mouse position. To do what you want, you'll need:

  1. Keep track of the images added, their positions, their sizes, and their z-index. The best way to do this is using a stack structure, an array of objects with this properties: url x, y, width, height. The z-index can be the index of the array.
  2. Once you start a drag operation on the canvas, you need to get the point you're dragging, and find the image with the highest z-index that contains that point (basically, implement hit-testing).
  3. To move it, then you have to remove it from the canvas, which implies redrawing the entire canvas with all the images except the one you're dragging. For this you can use the stack previously defined, and draw the images in order.
  4. Finally, you need to draw your image again once you drop it, take it from its position in the array and append it at the end.

This is not an easy task. I suggest you to use some library for it. I cannot recommend you one, because I have little to no experience with canvas.

Upvotes: 1

Related Questions