15

I was trying to make rounded corners for s svg:image (image embedded in SVG) with d3.js. I can't find out how to properly style the image, because according to W3C spec I should be able to use CSS, but neighter border nor rounded edges work for me.

Thanks in advance.

  vis.append("svg:image")
     .attr("width", width/3)
     .attr("height", height-10)
     .attr("y", 5)
     .attr("x", 5)      
     .attr("style", "border:1px solid black;border-radius: 15px;")
     .attr("xlink:href",
           "http://www.acuteaday.com/blog/wp-content/uploads/2011/03/koala-australia-big.jpg"); 

Edit:

Browsers tested: Firefox, Chrome

VividD
  • 10,456
  • 6
  • 64
  • 111
malejpavouk
  • 4,297
  • 6
  • 41
  • 67

4 Answers4

34

'border-radius' doesn't apply to svg:image elements (yet anyway). A workaround would be to create a rect with rounded corners, and use a clip-path.

An example.

The relevant part of the source:

<defs>
    <rect id="rect" x="25%" y="25%" width="50%" height="50%" rx="15"/>
    <clipPath id="clip">
      <use xlink:href="#rect"/>
    </clipPath>
  </defs>

  <use xlink:href="#rect" stroke-width="2" stroke="black"/>
  <image xlink:href="boston.jpg" width="100%" height="100%" clip-path="url(#clip)"/>

It's also possible to create several rect elements instead of using <use>.

Erik Dahlström
  • 59,452
  • 12
  • 120
  • 139
  • I'm having trouble implementing this in d3.js code... @malejpavouk, do you have any more specific code examples of your implementation so that I can add images with rounded corners to my d3 visualization? – wlindner Jan 10 '12 at 19:56
  • My app is little more complicated, but the code you need is copy pasted from the example posted by Erik (if I remember correctly without any significant change). – malejpavouk Jan 11 '12 at 09:05
  • 1
    is this work outside of d3.js? I use it on other places and it doesn't work. – Travis Su Jul 06 '18 at 18:35
9

There is another way to do that nowadays which is a bit cleaner. It's to use an inset clip-path.

<image xlink:href="imgUrl" width="100%" height="100%" clip-path="inset(0% round 15px)">
Py.
  • 3,499
  • 1
  • 34
  • 53
6

Another, easy alternative:

Wrap an html <img> tag in a <foreignObject> tag. This allows you to use normal html styling:

<foreignObject x='0' y='0' width='100px' height='100px'>
  <img
    width='100px'
    height='100px'
    src={'path/to/image.png'}
    style={{ borderRadius: '50%' }}
  />
</foreignObject>
protocodex
  • 61
  • 1
  • 2
  • 1
    Oh wow, I'd never come across foreignObject! This works really well for my case and is really useful for a dynamically generated composited effect I'm trying to create - thanks for the tip! – Iain Collins May 29 '21 at 12:18
5

For those just interested in making rounded avatars, here goes an example using d3 v4. Notice that you need to apply the clipping while the image is at (0,0), so you need to translate() the image to where you want it.

import { select } from 'd3-selection';

const AVATAR_WIDTH = 80;
const avatarRadius = AVATAR_WIDTH / 2;
const svg = select('.my-container');
const defs = this.svg.append("defs");
defs.append("clipPath")
  .attr("id", "avatar-clip")
  .append("circle")
  .attr("cx", avatarRadius)
  .attr("cy", avatarRadius)
  .attr("r", avatarRadius)
svg.append("image")
  .attr("x", 0)
  .attr("y", 0)
  .attr("width", AVATAR_WIDTH)
  .attr("height", AVATAR_WIDTH)
  .attr("xlink:href", myAvatarUrl)
  .attr("clip-path", "url(#avatar-clip)")
  .attr("transform", "translate(posx, posy)")
  .append('My username')
Nacho Coloma
  • 7,070
  • 2
  • 40
  • 43