Search code examples
raphaelpalette

RaphaelJS palette behaviour


How can I make a palette behaviour (elements being dragged and dropped from a 'palette' to a 'canvas') in raphaelJS?


Solution

  • You'll have to add to every palette element this startFunction:

    //DragFunctions is the object that has all the 3 d&d methods, clearer in the complete file
    paletteStart: function () {
        // keep the relative coords at the start of the drag
        this.ox = 0;
        this.oy = 0;
    
        // as we are dragging the palette element, we clone it to leave one in his place.
        var newPaletteObj = this.clone();
    
        //we give the new palette element the behaviour of a palette element
        DragFunctions.addDragAndDropCapabilityToPaletteOption(newPaletteObj);
    
        //nice animation
        this.animate({
            "opacity": 0.5
        }, 500);
    }
    

    Now we need the function while the element is being dragged:

    move: function (dx, dy) {
        // calculate translation coords
        var new_x = dx - this.ox;
        var new_y = dy - this.oy;
    
        // transforming coordinates
        this.transform('...T' + new_x + ',' + new_y);
    
        // save the new values for future drags
        this.ox = dx;
        this.oy = dy;
    }
    

    And finally, the function executed at finish dropping:

    paletteUp: function () {
        if (!DragFunctions.isInsideCanvas(this)) {
            this.remove();
            //notify the user as you want!
        } else {
            //Giving the new D&D behaviour
            this.undrag();
            //give the element the new d&d functionality!
            this.animate({
                "opacity": 1
            }, 500);
        }
    }
    

    2 things to comment here, when the element is dropped, you will have to remove the palette behaviour and give it another one (a plain d&d functionality), if not, it will continue cloning elements all around. Here I give you some nice behaviour to give them:

    start: function () {
        // keep the relative coords at the start of the drag
        this.ox = 0;
        this.oy = 0;
        // animate attributes to a "being dragged" state
        this.animate({
            "opacity": 0.5
        }, 500);
    },
    //same move function
    up: function () {
        if (!DragFunctions.isInsideCanvas(this)) {
            this.animate({
                transform: '...T' + (-this.ox) + ',' + (-this.oy)
            }, 1000, "bounce");
        }
        this.animate({
            "opacity": 1
        }, 500);
    },
    
    //and the method that gives the behaviour
    addDragAndDropCapabilityToSet: function (compSet) {
        compSet.drag(this.move, this.start, this.up, compSet, compSet, compSet);
    }
    

    And as you may also see, we have a validator that sees if the element is inside the canvas, it is a very useful function, here:

    isInsideCanvas: function (obj) {
        var canvasBBox = //get your 'canvas'
        var objectBBox = obj.getBBox();
        var objectPartiallyOutside = !Raphael.isPointInsideBBox(canvasBBox, objectBBox.x, objectBBox.y) || !Raphael.isPointInsideBBox(canvasBBox, objectBBox.x, objectBBox.y2) || !Raphael.isPointInsideBBox(canvasBBox, objectBBox.x2, objectBBox.y) || !Raphael.isPointInsideBBox(canvasBBox, objectBBox.x2, objectBBox.y2);
        return !(objectPartiallyOutside);
    } Finally,
    the place to call to give the element all this behaviour:
    
    //this works for elements and sets
    addDragAndDropCapabilityToPaletteOption: function (compSet) {
        compSet.drag(this.move, this.paletteStart, this.paletteUp, compSet, compSet, compSet);
    }
    

    A demo of this is in a website I created to play with raphael, called comoformamos.com The hole code is in a github gist or hosted on github so if you want to get a little deeper in the code feel free to do it.

    Explained more beautifully at this blog entry: devhike, I'm the author.