5

Description of requirement:

I am using d3 to parse a .csv file for data and then populate various items on a page dynamically. One section is shown below:

Requirement

My Code progression:

  • I started out by housing each dynamically retrieved number within its own div tag and setting the background image for each dynamically. Here is the d3 JavaScript code:

    careerstage_td.append("div")
    .text(function(d){ return d.count })
    .attr("class", "career-count")
    .style("color", function(d){return d.color;})
    .style("background-image", function(d){return "url('images/" + d.icon + "')";})
    .style("background-repeat", "no-repeat")
    .style("background-position", "center center");
    

    (Notice that I am using a function to dynamically populate the number as well as to figure out which image to overlay)

    This gave me the following expected result, where the images were behind the text:

First implementation pass result

  • The next step was to figure out how to overlay that background image on top of the text. For this I started digging around on google and found this question on SO: How to overlay images. Over here I identified two different solutions:

    Solution 1: (from the top answer on that page) add a span in the div with the number, then position the span absolutely in the center using css, like so

    div.career-count span.stickperson
    {
        position:absolute;
        left:45%;
        top: 34%;
    }
    

    Solution 2: (from another answer on that page) Add the following css that extends the class of the div with the dynamic text, like so

    .career-count:after
    {
        content: url(/images/person_assoc.gif);
        position: absolute;
        left:45%;
        top: 34%;
    }
    

Both solutions work, but Solution 1 only works in Chrome, and Solution 2 doesn't allow me to set the images dynamically since it is all done in css and the 'after' contruct cannot be used in-line.

I would appreciate help in figuring out a solution that allows me to set the image dynamically and also works in Chrome, Firefox 25 and IE 11.

EDIT: Thanks for the up-votes, folks. I added images now :)

Community
  • 1
  • 1
BakaTono
  • 479
  • 6
  • 13
  • 1
    Have you tried not setting the background image on the first set of `div`s and adding an identical set of `div`s afterwards with the images as background? – Lars Kotthoff Nov 15 '13 at 20:10
  • @Lars: Solution 1 above is similar to what you are saying, in that I am overlaying a span on top of the div with text, and adding the image to that span as content. I tried the same solution with a div instead of a span tag, and it still only displays in Chrome. I will adding the image as a background image instead of content and see what happens. Stay tuned. – BakaTono Nov 15 '13 at 23:04
  • @LarsKotthoff: I tried your suggestion. It did not display anything in all three browsers, so I reverted to solution 1 for now. The thing I like most about Solution 1 is that a single css definition is needed. If I were to use Solution 2, I would have to create a separate css definition for each block to define the respective image foregrounds. The nice thing about Solution 2 is that it works on all browsers and does not require extra elements on the html side. – BakaTono Nov 15 '13 at 23:47
  • Could you post a complete working example please? That would make it much easier to play around with it. – Lars Kotthoff Nov 16 '13 at 11:06

1 Answers1

2

Actually I think the best solution is not to add a background-image to the div elements in which you put your text, but rather to create a child div for each div you created, and work with the image inside the child.

careerstage_td.selectAll('div')
    .data(dataset)
    .enter().append('div')
    .attr("class", "career-count")
    .text(function(d){return d;})
    .style("color", function(d){return d.color;})
    .append('div')
    .attr("class", "childClass")
    .style("background-image", function(d){return "url('images/" + d.icon + "')";})
    .style("background-repeat", "no-repeat")
    .style("background-position", "center center");

In the given code, I generate my divs thanks to the data, and for each div I append a new div (classnames "childClass"). Now I can play on this childClass.

See the jsfiddle for an example. (note that I used a simplified dataset so I pushed always the image as a background, and the same text color).

The trick to ensure that the icon displays in the middle of the parent node is to define the parent as position:relative and the children as absolute with a width and height of 100%. Centering the background both on x and y does the job.

leMoisela
  • 1,046
  • 8
  • 17
  • Thanks. I will try this out and respond with my results, although there doesn't seem to be a lot of difference from Solution 1 in my description above. Seems like the main difference is that you are using z-index instead of axis positioning. Am I wrong? – BakaTono Nov 16 '13 at 22:02
  • 1
    oups, no actually you can remove the z-index, it will work also without. It might look like solution 1, but a) it is supported by all modern browsers b) there is no % guess to center the element (left:45%; top: 34%;). Since the child Div is exactly the same size as the parentDiv (100% width and height), and at the same position (absolute, with respect to the parent which is relative), there is no need to play with both axis positions. In particular since simply defining "center center" for the background makes the math for you. – leMoisela Nov 16 '13 at 22:46
  • This solution worked. Lars Kotthoff had suggested the same thing that you did, but he missed this part: width: 100%; height: 100%; Because of that, it was not displaying the div. Now I got it to work on Chrome, Firefox and IE. Thank you very much leMoisela! – BakaTono Nov 18 '13 at 21:01