Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D3.js: Using images (with filenames specified in data) as tick values on axis

I currently have this data:

var dataset = [ {  "bank": "Bank 1",  "img": "Picture1.png" }, {  "bank": "Bank 2",  "img": "Picture2.png" },                   {  "bank": "Bank 3",  "img": "Picture3.png" } ]; 

Complex real-world data, right? Sure. OK, I currently have "bank" as the tick values on my axis with this D3.js code:

var w = 1000; var h = 700; var padding = 30; var wpadding = 120; var svg = d3.select("body")             .append("svg")             .attr("width", w)             .attr("height", h+padding);  var yScale = d3.scale.ordinal()                 .domain(dataset.map(function (d) { return d.bank; }))                 .rangeRoundBands([0, h], 0.55);  var yAxis = d3.svg.axis()                 .scale(yScale)                 .orient("left");      svg.append("g")                 .attr("class", "axis")                 .attr("transform", "translate(" + wpadding + ", 0)")                 .call(yAxis);                

Anyway, I'm sure you can see where I'm going with this. I'm now trying to make the tick values on my axis reference the img value in my dataset, rather than just the bank value.

At first I thought it was a case of using axis.tickValues([values]) with an anonymous function to reference the img values in my JSON data, but it's not working. Or I'm doing it horribly wrong.

Then I thought it was a case of using:

 var imgs = svg.selectAll("img").data([dataset]); 

but then my concern with this method is that this won't be properly bound to the axis, like proper tick values; It's like they're just a collection of images which happen to be sitting next to my axis, and sizing/positioning changes I make to my axis I have to separately apply to my collection of images as well. It just doesn't seem as elegant as having proper images-as-tick-values-on-my-axis.

Am I doing something horribly wrong? Does anyone need me to provide more info?

Thanks again gals & guys!

UPDATE: Thanks to @larskotthoff , I've added this:

svg.select(".axis").selectAll("text").remove();  var ticks = svg.select(".axis").selectAll(".tick")                     .data(dataset)                     .append("svg:image")                     .attr("xlink:href", function (d) { return d.img ; })                     .attr("width", 100)                     .attr("height", 100); 

And it (almost) works! Well, it shows images, but as you can guess, the origin point of each image (ie., their top-left corner) is where each tick ends, resulting in the image now rendering inside the diagram, instead of outside of it beside the tick:

can't insert images without enough StackOverflow rep, so here's the URL: i.stack.imgur.com/s2CX0.png Tick image appears inside diagram instead of alongside tick

Clearly I need to manipulate the images' x's and y's, but how do I do that relative to the position of the individual tick? In other words, how do I say in D3: "Take the x,y of the tick and subtract (a hardcoded value of) 150 for both, and make that my new x,y for my image." ?

Thanks again for your help!

UPDATE #2: After finally discovering this.parentNode and digging into it, I just newbie-ly discovered that the x,y attributes as set on the images current bound to my axis are relative to each respective tick! By that I mean, I can just simply add:

                    .attr("x", -120)                     .attr("y", -50); 

as additional attributes for my images, and it positions them to the left of their respective ticks (back on the axis label position, not sitting on top of the diagram).

like image 598
Belinda-Jane Netan Avatar asked Jul 15 '14 16:07

Belinda-Jane Netan


1 Answers

Dataset:

var dataset = [ {  "bank": "Bank 1",  "img": "Picture1.png" }, {  "bank": "Bank 2",  "img": "Picture2.png" },                   {  "bank": "Bank 3",  "img": "Picture3.png" } ]; 

D3 JS code:

var w = 1000; var h = 700; var padding = 30; var wpadding = 120; var svg = d3.select("body")             .append("svg")             .attr("width", w)             .attr("height", h+padding);   svg.select(".axis").selectAll("text").remove();  var ticks = svg.select(".axis").selectAll(".tick")                     .data(dataset)                     .append("svg:image")                     .attr("xlink:href", function (d) { return d.img ; })                     .attr("width", 100)                     .attr("height", 100);                     .attr("x", -120);                     .attr("y", -50);   var yScale = d3.scale.ordinal()                 .domain(dataset.map(function (d) { return d.bank; }))                 .rangeRoundBands([0, h], 0.55);  var yAxis = d3.svg.axis()                 .scale(yScale)                 .orient("left");      svg.append("g")                 .attr("class", "axis")                 .attr("transform", "translate(" + wpadding + ", 0)")                 .call(yAxis);   
like image 135
morganpdx Avatar answered Oct 09 '22 03:10

morganpdx