57

I am trying to set an icon with FontAwesome instead of text in my D3 nodes. This is the original implmentation, with text:

g.append('svg:text')
    .attr('x', 0)
    .attr('y', 4)
    .attr('class', 'id')
    .text(function(d) { return d.label; });

And now I try with icons:

g.append('svg:i')
   .attr('x', 0)
   .attr('y', 4)
   .attr('class', 'id icon-fixed-width icon-user');

But this is not working, even though the markup is right, and the CSS rules are properly hit: the icons are not visible.

Any idea why?

Here is the related jsbin

EDIT

I have found this alternative to insert images: http://bl.ocks.org/mbostock/950642

node.append("image")
    .attr("xlink:href", "https://github.com/favicon.ico")
    .attr("x", -8)
    .attr("y", -8)
    .attr("width", 16)
    .attr("height", 16);

Which is exactly what I want to do, but it does not work with <i> elements used by FontAwesome.

blueFast
  • 41,341
  • 63
  • 198
  • 344

9 Answers9

89

You need to use the proper Unicode inside a normal text element, and then set the font-family to "FontAwesome" like this:

 node.append('text')
    .attr('font-family', 'FontAwesome')
    .attr('font-size', function(d) { return d.size+'em'} )
    .text(function(d) { return '\uf118' }); 

This exact code will render an "icon-smile" icon. The unicodes for all FontAwesome icons can be found here:

http://fortawesome.github.io/Font-Awesome/cheatsheet/

Be aware that you need to adapt the codes in the cheatsheet from HTML/CSS unicode format to Javascript unicode format so that &#xf118; must be written \uf118 in your javascript.

Carles Andres
  • 1,761
  • 1
  • 15
  • 22
  • 1
    Thanks! This works perfectly. I felled into several pitfalls. First it is worth noting that `` is an svg tag (I looked for it as html tag). I had problems with centering the icons inside the nodes (circles in my case)- Also with styling, since CSS has precedence over the attributes and I had a style set for the `` elements. For reference I will paste my final solution as an answer. – blueFast Nov 10 '13 at 16:21
  • 8
    it doesn't work for me...i took exactly the same code as listed above and i don't get the drawing as expected. do i need to install the fonts locally? i'm using the cdn version of FontAws and wondered if this has anything to do with it (it works everywhere else perfectly but D3) – Or A Dec 03 '13 at 22:56
  • 1
    Thanks Carles, i get it to work by changing attr to style for font-family and font-size – mhd Jun 01 '16 at 14:07
  • 3
    This solution will NOT work on [Font Awesome 5.6.3](https://use.fontawesome.com/releases/v5.6.3/css/all.css). You would need to also set `.attr('font-family', 'Font Awesome 5 Free')` and `.attr('font-weight', 900)` – Ricardo Jan 23 '19 at 07:07
  • How to use FAB or FAR icon ? – Neo Jun 21 '21 at 08:07
38

Thanks to all that replied. My final solution is based on the answer by CarlesAndres:

g.append('text')
    .attr('text-anchor', 'middle')
    .attr('dominant-baseline', 'central')
    .attr('font-family', 'FontAwesome')
    .attr('font-size', '20px')
    .text(function(d) { return ICON_UNICODE[d.nodeType]; });

Be careful with your CSS: it takes precedence over the SVG attributes.

And this is the way it looks:

Node Graph

The good thing about this, compared to the foreignObject solution, is that events are properly handled by D3.

blueFast
  • 41,341
  • 63
  • 198
  • 344
  • 1
    hi, can you send me the snippet of the code that did this for you? for some reason when i use the code you attached above, i don't get any image to show? how did you store the unicode of the images? thanks – Or A Dec 03 '13 at 21:21
  • You probably need the `ICON_UNICODE` array. – forresto Jan 04 '14 at 05:03
  • 2
    Here's the `ICON_UNICODE` object as of font-awesome 4.0.3: https://gist.github.com/forresto/8254791 – forresto Jan 04 '14 at 12:08
  • 2
    @jeckyll2hide quick note: the .attr should be .style to get the icons to show up. This is as of D3.JS version 3.5.3. Tried to just edit your answer but it was a no-go. – Delicia Brummitt Jan 12 '15 at 20:28
  • @DeliciaBrummitt: do you have any reference as to what is a style and what is an attribute in D3? This seems to be a bit [fuzzy](http://www.d3noob.org/2014/02/styles-in-d3js.html) – blueFast Jan 13 '15 at 09:46
  • @jeckyll2hide Fuzzy is the perfect word for it. Per the [D3 wiki](https://github.com/mbostock/d3/wiki/Selections#style) style should be used to set the CSS style attributes. Which would apply to the font-family and font-size [Here](http://www.w3.org/TR/CSS21/fonts.html#font-family-prop). is the W3C documentation. The text-anchor and dominant-baseline are listed as SVG attributes per [Mozilla](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute). – Delicia Brummitt Jan 13 '15 at 13:39
  • 1
    Thanks, this worked. After looking at other answers, I was still missing the font-family setting that I finally stumbled over in your sample code. Stackoverflow-based programming for life – Pirkka Esko Nov 15 '16 at 07:36
12

I'm truly new to d3, but font awesome works by styling an <i> element with a class attribute.

The only way I found is to append a foreignObject and set on it the relevant HTML needed by font awesome.

Reference:

https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject?redirectlocale=en-US&redirectslug=SVG%2FElement%2FforeignObject

http://fortawesome.github.io/Font-Awesome/examples/

Code:

g.append('svg:foreignObject')
    .attr("width", 100)
    .attr("height", 100)
    .append("xhtml:body")
    .html('<i class="icon-fixed-width icon-user"></i>');

Demo: http://jsbin.com/eFAZABe/3/

Irvin Dominin
  • 30,819
  • 9
  • 77
  • 111
  • 1
    Your solution is interesting, but having a foreign object makes the styling complicated. For example, the body CSS styles are automatically applied (in my case, this makes the background of the icon visible within the node graph). I would prefer a solution without this foreignObject, but I do not know if this is at all possible. – blueFast Aug 24 '13 at 10:26
  • I'm checking if it is possible with another way – Irvin Dominin Aug 24 '13 at 10:58
  • Thanks. Another problem with the foreignObject is that it does not relay the events. You can see that problem here: http://jsbin.com/eFAZABe/6: when you try to link the nodes, the icon prevents the onMouseOver. In the original question I have added a link to an example which is using images to achieve a similar effect (but I need font awesome icons) – blueFast Aug 24 '13 at 11:34
  • Sorry, tried tspan and other, but the only way I found is to use foreignObject – Irvin Dominin Aug 24 '13 at 13:28
  • because no-one has yet mentioned patchy browser support for foreign object: http://caniuse.com/#feat=svg-html – ptim Jun 21 '15 at 13:35
8

Given that the other answers don't work anymore (because d3js has been updated in the meanwhile) and because it's not a good solution to use svg:foreignObject due to compatability issues, here is an answer that works without having to use any hacks:

.append("text")      // Append a text element
.attr("class", "fa") // Give it the font-awesome class
.text("\uf005");     // Specify your icon in unicode (https://fontawesome.com/cheatsheet)

Here is a working example (click "Run code snippet" and the d3 code outputs three stars):

var icons = [1, 2, 3];

d3.select("body")
  .selectAll(".text")
  .data(icons)
  .enter()
  .append("text")       // Append a text element
  .attr("class", "fa")  // Give it the font-awesome class
  .text("\uf005");      // Specify your icon in unicode
<link href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
Jean-Paul
  • 19,910
  • 9
  • 62
  • 88
  • 2
    Kudos! This solution also works on [Font Awesome 5.6.3](https://use.fontawesome.com/releases/v5.6.3/css/all.css) AND migrating from 4 doesn't require any extra effort – Ricardo Jan 23 '19 at 07:05
  • 1
    @AhmadKarim The D3.js version was outdated. I added a newer version and now it works again, see above. – Jean-Paul Aug 20 '20 at 12:23
4

I know this question is old, been resolved, but - this worked for me today.

From this site

svg.append('svg:foreignObject')
    .attr("width", 50)
    .attr("height", 50)
    .append("xhtml:body")
    .html('<i class="fa fa-user"></i>');

But for my chart, I dropped the append xhtml:body, otherwise it wouldn't let me set x and y coords.

The element will adopt the width and height of the font you set.

d3.select('svg')
    .append('svg:foreignObject')
    .attr('class', 'handle')
    .attr('x',  +getLeftBarPosition(i+1, 'handle')[0] + +getLeftBarPosition(i+1, 'handle')[1])
    .attr('y', state.barHeight/2)
    .html('<i class="fa fa-user"></i>')
JasTonAChair
  • 1,948
  • 1
  • 19
  • 31
3

Just to put in code here what worked for me based on CarlesAndres's answer and mhd's comment:

node.append("text")
    .attr("style","font-family:FontAwesome;")
    .attr('font-size', "50px" )
    .attr("x", 440)
    .attr("y", 440)
    .text(function(d) { return '\uf118' });
Jason
  • 719
  • 9
  • 19
3

Font awesome 4.x versions are not supporting if we use as follows

svg.append('text')
   .attr('x', 15)
   .attr('y', -17)
   .attr('fill', 'black')
   .attr('font-family', 'FontAwesome')
   .attr('font-size', function (d) { return '20px' })
   .text(function (d) { return '\uf2b9' });

so replace this

.attr('font-family', 'FontAwesome')

with

.attr("class", "fa")

Hope it helps for FA 4.x

Navin
  • 115
  • 1
  • 1
  • 8
2

For those who banging their head hard. D3 - 6.2.0 and FontAwesome - 5.13.0 Below worked

nodeEnter.append('text')
    .attr('width', "10px" ).attr('height', "10px" ) // this will set the height and width
    .attr("class","fas fa-adjust") // Font Awesome class, any
    .attr("x", 15) // for placement on x axis
    .attr("y",-5); // for placement on y axis
Aadam
  • 1,521
  • 9
  • 30
  • 60
1

For those who want to use svg icons from FontAwesome with D3, this snippet should work:

btnGroup.append("g")
  .attr("width", 16)
  .attr("height", 16)
  .attr("class", "fas fa-check-square");

The only drawback here is that width and height are not inherited from CSS. The good news is that class toggling works as expected with d3 and jquery.

Demo with toggling on click: https://jsfiddle.net/diafour/6fagxpt0/

diafour
  • 51
  • 3