0

When an image is dragged on to a canvas element (or another div), this function is called. If the element was a canvas element it uses pattern to create the fill, otherwise it appends the image. When it appends the image, I can call jquery's draggable function. I would like to achieve the same functionality with the canvas element. How would I go about doing that?

Here is the relevant code:

function photos_create_preview_image(element)
{
  console.log(element.id);
  if(element.id.indexOf("canvas") != -1)
  {
    console.log("canvas element");
    var canvas = document.getElementById(element.id); 
    ctx = canvas.getContext("2d");

    new_img = new Image();
    new_img.onload = function() {
      this.width /= 3; //TODO: Figure out what this should be, right now it is just a "magic number"
      this.height /= 3;

      var pattern = ctx.createPattern(new_img, "no-repeat");
      ctx.fillStyle = pattern;
      ctx.fill();
      //TODO: Make image draggable
    };

    new_img.src = SITE_URL + "/system/photo/cf_preview/" + selected_fid;
  }
  else
  {

    new_img = new Image();
    new_img.onload = function() {
      this.width /= 3; //TODO: Figure out what this should be, right now it is just a "magic number"
      this.height /= 3;

      element.appendChild(new_img);
      $(new_img).draggable({ containment: "parent" });
    };

    new_img.src = SITE_URL + "/system/photo/cf_preview/" + selected_fid;
  }
  console.log("new image: " + new_img.src);
}

Here's the new code with MarkE's solution:

function photos_create_preview_image(element)
{
  console.log(element.id);
  if(element.id.indexOf("canvas") != -1)
  {
    console.log("canvas element");
    var canvas = document.getElementById(element.id); 
    var ctx = canvas.getContext("2d");

    var canvasOffset = $("#" + element.id).offset();
    var offsetX = canvasOffset.left;
    var offsetY = canvasOffset.top;
    var isDown = false;
    var startX;
    var startY;
    var imgX = 0;
    var imgY = 0;
    var imgWidth, imgHeight;
    var mouseX, mouseY;


    var new_img = new Image();
    new_img.onload = function() {
      //this.width /= 3; //TODO: Figure out what this should be, right now it is just a "magic number"
    // this.height /= 3;

      /*var pattern = ctx.createPattern(new_img, "no-repeat");
      ctx.fillStyle = pattern;
      ctx.fill();*/
      imgWidth = new_img.width;
      imgHeight = new_img.height;
      ctx.drawImage(new_img, imgX, imgY);
      //TODO: Make image draggable


    };

    new_img.src = SITE_URL + "/system/photo/cf_preview/" + selected_fid;

    function handleMouseDown(e) {
        e.preventDefault();
        //startX = parseInt(e.clientX - offsetX);
        //startY = parseInt(e.clientY - offsetY);
        startX = parseInt(e.pageX - window.scrollX);
        startY = parseInt(e.pageY - window.scrollY);

        // Put your mousedown stuff here
        if (startX >= imgX && startX <= imgX + imgWidth && startY >= imgY && startY <= imgY + imgHeight) {
            isDown = true;
        }
    }

    function handleMouseUp(e) {
        e.preventDefault();
        isDown = false;
    }

    function handleMouseOut(e) {
        e.preventDefault();
        isDown = false;
    }

    function handleMouseMove(e) {
        if (!isDown) {
            return;
        }
        e.preventDefault();
        mouseX = parseInt(e.clientX - offsetX);
        mouseY = parseInt(e.clientY - offsetY);

        // Put your mousemove stuff here
        if (!isDown) {
            return;
        }
        imgX += mouseX - startX;
        imgY += mouseY - startY;
        startX = mouseX;
        startY = mouseY;
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.drawImage(new_img, imgX, imgY);
    }

    $("#" + element.id).mousedown(function (e) {
        handleMouseDown(e);
    });
    $("#" + element.id).mousemove(function (e) {
        handleMouseMove(e);
    });
    $("#" + element.id).mouseup(function (e) {
        handleMouseUp(e);
    });
    $("#" + element.id).mouseout(function (e) {
        handleMouseOut(e);
    });
  }
  else
  {

    new_img = new Image();
    new_img.onload = function() {
      this.width /= 3; //TODO: Figure out what this should be, right now it is just a "magic number"
      this.height /= 3;

      element.appendChild(new_img);
      $(new_img).draggable({ containment: "parent" });
    };

    new_img.src = SITE_URL + "/system/photo/cf_preview/" + selected_fid;
  }
  console.log("new image: " + new_img.src);
}

I need the image to be a pattern because it is contained within a path. Right now the code works when called with drawImage.

Basically I need it to look like this (which it does when I use the pattern code):

enter image description here

AllisonC
  • 2,973
  • 4
  • 29
  • 46
  • The image's width/height are read-only. You need to either paint the image into a canvas at the size you want or use scale to scale the context before drawing the pattern –  Dec 30 '13 at 16:58

1 Answers1

0

You can drag your image (or filled pattern) by listening to mouse events.

Demo: http://jsfiddle.net/m1erickson/66ywJ/

In mousedown:

  • Get the mouse position,
  • Check if the mouse is inside the image,
  • If inside, set the isDown flag to indicate the drag has begun.

In mousemove:

  • Get the mouse position,
  • Calculate how far the mouse has dragged since the last mousemove
  • Change the image position by the amount dragged
  • Redraw the image at its new position

In mouseup or mouseout:

  • Clear the isDown flag to indicate the drag is over.

Here is 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 canvasOffset=$("#canvas").offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;
    var isDown=false;
    var startX;
    var startY;
    var imgX=50;
    var imgY=50;
    var imgWidth,imgHeight;

    var img=new Image();img.onload=start;img.src="house32x32.png";

    function start(){
        imgWidth=img.width;
        imgHeight=img.height;
        ctx.drawImage(img,imgX,imgY);
    }

    function handleMouseDown(e){
      e.preventDefault();
      startX=parseInt(e.clientX-offsetX);
      startY=parseInt(e.clientY-offsetY);

      // Put your mousedown stuff here
      if(startX>=imgX && startX<=imgX+imgWidth && startY>=imgY && startY<=imgY+imgHeight){
          isDown=true;
      }
    }

    function handleMouseUp(e){
      e.preventDefault();
      isDown=false;
    }

    function handleMouseOut(e){
      e.preventDefault();
      isDown=false;
    }

    function handleMouseMove(e){
      if(!isDown){return;}
      e.preventDefault();
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);

      // Put your mousemove stuff here
      if(!isDown){return;}
      imgX+=mouseX-startX;
      imgY+=mouseY-startY;
      startX=mouseX;
      startY=mouseY;
      ctx.clearRect(0,0,canvas.width,canvas.height);
      ctx.drawImage(img,imgX,imgY);
    }

    $("#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>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
markE
  • 102,905
  • 11
  • 164
  • 176
  • When I implemented your code, it works for me in Firefox, but not Chrome, any idea why? In Chrome, the event handlers are firing but the image does not move. Also, I need it to be a pattern, not drawImage, because I have letters drawn with a path that it fills. – AllisonC Dec 31 '13 at 13:29
  • In Chrome, when I output startY in handleMouseDown it gives me a negative number, while in Firefox, it does not. – AllisonC Dec 31 '13 at 14:12
  • By using the answer in http://stackoverflow.com/questions/13710610/whats-a-workaround-for-chrome-for-androids-incorrect-clientx-and-clienty-behav I was able to get it to work. – AllisonC Dec 31 '13 at 14:26
  • Instead of clearRect and drawImage, I used the second solution here: http://stackoverflow.com/questions/7698949/moving-the-start-position-of-canvas-pattern var pattern = ctx.createPattern(new_img, "no-repeat"); ctx.save(); ctx.translate(imgX, imgY); ctx.fillStyle = pattern; ctx.fill(); ctx.restore(); Thanks for your help markE – AllisonC Dec 31 '13 at 14:51