8

I want to this this Fill SVG element with with a background-image with an offset, but using Raphael JS.

Displaying an rectangle with a background image without the offset is easy.

canvas.rect(
    positionx, positiony, width, height
).attr(
    {fill: "url('/content/image_set.gif')"}
);

The code above will display only the upper-left corner of the image. I want to shift it and display another part of it. How can I do it?

Community
  • 1
  • 1
jpbochi
  • 4,366
  • 3
  • 34
  • 43

2 Answers2

14

I'd suggest drawing the image separately from the rect. If you need the stroke you can either draw a filled rect behind the image or draw the rect on top with stroke and no fill.

The image is drawn with clipping to clip out the part you want, and you can control the offset of the image either with img.translate(x,y) or by the paper.image params:

var img = paper.image("foo.png", 10, 10, 80, 80);
img.attr({ "clip-rect": "20,20,30,30" });

This above works only for rectangular clipping (svg itself supports arbitrary clipping via the 'clip-path' property). If you want a pattern fill, then you currently have to step outside of what raphaël provides. Easiest is probably to just extend raphaël to do that, and to provide some other fallback to the browser(s) that doesn't support svg.

SVG Web seems to have at least partial support for svg patterns if you're looking for something to work as a fallback for old browsers.

Erik Dahlström
  • 59,452
  • 12
  • 120
  • 139
  • 1
    An image really seems to make more sense that a rect. I'm trying to use the "clip-rect" attribute, but I'm having a hard time getting it to work. What are those 4 numbers, exactly? I couldn't find any documentation on the internet. :S I think I'll have to go for the "clip-path" anyways... – jpbochi Mar 22 '11 at 19:13
  • 1
    Just to document it, the "clip-rect" arguments are X, Y, Width, and Height. – jpbochi Mar 22 '11 at 19:44
  • 1
    Indeed, I took some time to realize that "clip-rect" is a Raphael thing and it uses SVG's "clip-path" underneath. As you can see, I'm quite a newbe in SVG. :S – jpbochi Mar 22 '11 at 23:07
0

The above with clip-rect only works for rectangles - if you need to set a background-position offset for a path, there's a relatively easy way:

  1. Make the fill position relative to the shape (else things get messy)
  2. Add an extra M segment with just two co-ordinates to the start of your path string. This changes the point that is considered the path's origin, thus changing the position the image begins at.

So imagine you had a triangle path defined as M0,0 50,0 25,35Z. If you want to offset the background image left by 20px and up by 5px, append M-20,-5 to the start of the string, giving M-20,-5 M0,0 50,0 25,35Z.

Here's a demo of exactly that:

http://jsbin.com/oxuyeq/14/edit

Note that, the actual background offset will be the difference between the values you input and the top left bounding box of the path at the time the fill is applied. If you can make sure when defining the original path that this is 0,0, then life will be easier.


If you're thinking of defining a function or custom attribute that applies background position on the fly - for example, using element.getBBox() to counteract the above issue - be aware that there's a bug in VML mode which means that in IE8 any additional M segments get scrubbed out of the path if you update the path using .attr('path').

Also, in SVG mode, you need to refresh the fill, which may mean you need to reapply the relative position fix.

Here's a demo of a custom attribute working for the above in everything except IE8 - click the shape to update background position - with some failed attempts to make it work in IE8... http://jsbin.com/oxuyeq/13/edit

Community
  • 1
  • 1
user56reinstatemonica8
  • 32,576
  • 21
  • 101
  • 125