rekoDolph
rekoDolph

Reputation: 823

How do I apply the drag to a rect/image?

Such a stupid question and probably have a simple answer but I am unable to drag my images around my canvas. Here is my code for my images :

    function simpleButton(origImage, overlay, iconWidth, iconHeight, xpos, ypos, whenClicked, title)
{
    svg.append("svg:image")
    .datum({
      x: xpos, //-starting 'x' position
      y: ypos  //-starting 'y' position
    })
    .attr("x", function (d) { return d.x; }) 
    .attr("y", function (d) { return d.y; })

        .attr("xlink:href", origImage) //-original image
        // .attr("x",xpos) //-starting 'x' position
        // .attr("y",ypos) //-starting 'y' position
        .attr("width",iconWidth) //-icon width
        .attr("height",iconHeight) //-icon height
        .on("click",whenClicked) //-call when button is clicked
        .on("mouseover",function(){d3.select(this).attr("xlink:href", overlay);}) //-change image when mouseover
        .on("mouseout",function(){d3.select(this).attr("xlink:href", origImage);}) //-reset image
        .call(button_drag)
        .append("svg:title")
            .text(title); //-give the button a title        
}

And my drag function:

var button_drag = d3.behavior.drag()

    .on("dragstart", function(){
        clog("dragstart");
    })
    .on("drag", function(d,i) {
             d.x += d3.event.dx
             d.y += d3.event.dy
            d3.select(this).attr("transform", function(d,i){
                return "translate(" + [ d.x,d.y ] + ")"
            })
        })
    .on("dragend", function(){
        clog("dragend");
    });

I get the error when trying to drag one of the images :

 Uncaught TypeError: Cannot read property 'x' of undefined

I have tried to research it and apparently I don't have data applied to my rectangle. How do I fix this ?

Upvotes: 1

Views: 156

Answers (1)

meetamit
meetamit

Reputation: 25157

Drag is supposed to pass d — the datum bound to the element being dragged – into your handler function .on("drag", function(d,i) { ... }.

In your case d is undefined, which is why setting d.x complains that it can't read property 'x' of undefined. The reason d is undefined is because no datum is bound to the image. The way data gets bound to elements is either:

  1. Using d3 selection's .data() method to bind and then append the enter()'ing to elements — rather than just svg.appending them as you do. Or,
  2. If you don't want to do #1, then you need to explicitly bind a datum to the element you created, using the .datum() method.

Doing one of those 2 raises the question of what d is supposed to be. Well... it should be an object with properties x and y, since the drag handler wants to modify those props.

x and y should probably be initialized to xpos and ypos, i.e. the initial position. Once x and y are part of a datum, you should switch to setting the image's x and y positions based on them, rather than hardcoded to xpos, ypos.

Putting it all together, if you picked option #2, then it looks like this:

svg.append("svg:image") 
    .datum({
      x: xpos, //-starting 'x' position
      y: ypos  //-starting 'y' position
    })
    .attr("xlink:href", origImage) //-original image
    .attr("x", function (d) { return d.x; }) 
    .attr("y", function (d) { return d.y; })
    .attr("width",iconWidth) //-icon width
    .attr("height",iconHeight) //-icon height       
    .call(button_drag)

Upvotes: 2

Related Questions