1

I need to find the last path or circle in a paper, in order to perform further calculations to draw more elements, and calling paper.bottom only gets the last element. Is there any way to get shapes of specific types, e.g. bottom.path, bottom.circle or to traverse for the n'th child?

I want to avoid using jQuery selectors, as i can't retrieve any properties from those.

An example of a paper populated with shapes:

var paper = Raphael('paper',500,500);
var c1 = paper.circle(100,100,50)
var p1 = paper.path("M10 20l70 0")
var c2 = paper.circle(200,100,50)
Eliran Malka
  • 15,821
  • 6
  • 77
  • 100
3gwebtrain
  • 14,640
  • 25
  • 121
  • 247

2 Answers2

1

Checking for the bottom element will get you, well, the bottom element (along the Z axis) - which is undesired. Consider a case where the Z ordering of elements is altered - perhaps by calling Element.toBack() - that will invalidate the check altogether.

Instead you may want to aim for a more semantic approach by iterating over the elements array and retrieving the last element of a certain type (e.g. circle).

Raphaël also allows for extending the built-in set of functions, so we can attach a function to the paper element solely for that purpose. The following snippet shows an example of such a function which returns the last element of the passed type from the paper, or false if no such element was found:

Raphael.fn.last = function(type) {
    var element;
    this.forEach(function(el) {
        if (el.type == type) {
            element = el;
        }
    });
    return element || !!element;
};

Be sure to attach this function before any instanciation of paper elements. Than it's only a matter of calling it, passing the desired element type:

var r = Raphael(paper, '100%', '100%');
// ...
// add elements etcetera
// ...
var lastCircle = r.last('circle');

Note that for the suggested implementation this can result in heavy operations - if the paper contains many elements, but the purpose here is to grant you with the notion of functionality extension, and kick-start the thinking process. Feel free to improve the function to increase its efficiency.


Live Demo

Eliran Malka
  • 15,821
  • 6
  • 77
  • 100
  • Nice. One way to possibly make this more efficient would be to store your various shapes in (semantically-named) sets when you create them. E.g. create a set called AllCircles, and push each of your circles into it. Then you would only have to loop through the relevant set, and not through the whole paper. – Ben Nov 22 '12 at 22:43
  • nice idea, @Ben, although this would require some maintenance - you'd have to add each new shape to the relevant set, which could make coding slightly more awkward. – Eliran Malka Nov 22 '12 at 23:31
1

Regarding how to traverse for the nth child: Just put your paths in a set and they're indexed like any ordinary array. You can easily call out any number from that set, and get full access to its properties:

var myPaper = Raphael('container', '800', '600');

myPaper.setStart();
var circ1 = myPaper.circle(50, 50, 40);
var circ2 = myPaper.circle(150, 50, 40);
var circ3 = myPaper.circle(250, 50, 40);
var circ4 = myPaper.circle(350, 50, 40);
var allCircles = myPaper.setFinish();

allCircles[2].attr({fill: "blue"});

http://jsfiddle.net/eE7xS/

Ben
  • 11,082
  • 8
  • 33
  • 47