curly_brackets
curly_brackets

Reputation: 5598

Raphael JS combine paths

I'm pretty new at SVG and Raphael, but I've been using Illustrator for many years, so I have some assumptions on how it works. I want to combine two paths which should return a single element.

I need to make a speech bubble, but it could be anything really. In this case I tried to make two rect, one with round corners and another square rect which was rotated. It looked alright, but when I tried to move the speech bubble, the rotated element moved in the wrong direction, because of the 45 degree rotation.

How can I compbine paths which I can later manipulate as if it was a single element/path?

Example of speech bubble

Upvotes: 3

Views: 3930

Answers (3)

user56reinstatemonica8
user56reinstatemonica8

Reputation: 34074

If you mean merging paths like using the Illustrator Pathfinder panel - turning several paths into one path (not a set of paths), merging overlap - I'm pretty sure there's no direct Raphael or SVG equivalent.

The closest thing is, creating a compound path (aka composite path) - the equivalent of cmd-8 or Object > Make Compound Path in Illustrator. This merges paths together into one path, but doesn't remove areas of overlap.

Basically, for a set paper.set( paper.path('M0,0 4,0 0,4z'),paper.path('M9,9 4,9 9,4z') );, an equivalent compound path would be paper.path('M0,0 4,0 0,4z M9,9 4,9 9,4z'); - just joining the path definitions into one, each starting with its own M.

Some differences to Raphael sets:

  • Less overhead (it's just one complex path, not several separate individual path elements)
  • Fewer surprises when you move it, sort it, etc:
    • Things applied to a Raphael set apply to each item in turn, not to the set as a unit - so for example toFront() changes the order within the set, and transforms centre around each item, like Illustrator's transform each, unless you give the transform static co-ordinates.
    • Things applied to a compound path, however, apply to the whole compound path as one unit.
  • It's not possible for subpaths of a compound path to have different attributes
  • Things like gradients apply once across the whole of the compound path, whereas with sets, there will be separate gradients on each separate path

JSBIN demo - compare the gradients, and see how the compound pair is just one path on the DOM.


Here's a simple plugin that adds the ability to take a set and create a compound path from it:

Raphael.st.compoundPath = function(){
    var positions = [];
    this.forEach( function( element ){
        positions.push( element.compoundPath() );
    });
    return positions.join('');
} 
Raphael.el.compoundPath = function(){
    var path = this.attr('path');
    return path ? Raphael.parsePathString( path ).join('') : '';
}

Then use it like this:

var someSet = paper.set(paper.path('M0,0 4,0 0,4z'),paper.path('M9,9 4,9 9,4z'));
var compPath = paper.path( someSet.compoundPath() );
someSet.remove(); // if you want to replace the set with a compound path

Note that it only combines paths in a set - if you need to combine other shapes with paths, you'll need a way to convert them into paths first.

Upvotes: 2

Brian
Brian

Reputation: 5028

Here you go DEMO

var paper = Raphael('canvas',400,400),
    r1    = paper.rect(100,100,200,100).attr({fill:'black'}),
    r2    = paper.rect(130,130,140,40,5).attr({fill:'white','stroke':'white'}),
    r3    = paper.path("M200 170L240 170 220 180z").attr({fill:'white', 'stroke':'white'}), 
    p     = paper.set(r1,r2,r3);

// the rest of the code is in the demo

Note, that it is easier to create triangle via path() and not worry about rotation. Good Luck ;)

Upvotes: 2

Mathieu Marques
Mathieu Marques

Reputation: 1748

First thing is that you could push your 2 elements into a Raphael set which you would later move with Element.transform(). This would let you apply the move handler once, and not twice.

Also for your issue, it is acually documented:

... There are also alternative “absolute” translation, rotation and scale: T, R and S. They will not take previous transformation into account. For example, ...T100,0 will always move element 100 px horisontally, while ...t100,0 could move it vertically if there is r90 before. Just compare results of r90t100,0 and r90T100,0. ...

Upvotes: 1

Related Questions