Quantcast
Channel: User i alarmed alien - Stack Overflow
Viewing all articles
Browse latest Browse all 42

Answer by i alarmed alien for D3js horizontal bar chart: how to add numbers from data at the end of every bar?

$
0
0

It sounds like you were almost there with adding the labels. You want to add them to the g element that holds the rect bars, and add them after the rects so they will appear on top of the bars, so:

  var element = g.append("g")    .selectAll("g")    .data(data)    .enter().append("g")    .attr("transform", function(d) {      return "translate(0,"+ y0(d[yAxis]) +")";    });  var rect = element.selectAll("rect")    .data(function(d, i) {      return keys.map(function(key) {        return {          key: key,          value: d[key],          index: key +"_"+ i +"_"+ d[yAxis]        };      });    })    .enter().append("rect")    .attr("width", function (d) {      return x(d.value);    })    [ etc. ]  // add the text elements  element.append('text')

The text element needs to be at the end of the bar, and the bar width is x(d.value) using the data bound to the rect elements. d.value translates to d.num in terms of the data you already have attached to the g elements, so we can set the x attribute as x(d.num). If the text-anchor is set to end, that will align the end of the text with the end of the bar; we want a little space between text and end of bar, so add in a small offset:

element.append('text') .attr('text-anchor', 'end') .attr('x', d => x(d.num) - 5)

The value to be shown in the bar is also going to be d.num, so we can add that:

element.append('text') .attr('text-anchor', 'end') .attr('x', d => x(d.num) - 5) .text(d => d.num )

If you run the code now, you'll find that the numbers are partially obscured by the bar above, so let's sort out the y offset. The bar width is y1.bandwidth(); to align the baseline of the text with the bottom of the bar, add

element.append('text') .attr('text-anchor', 'end') .attr('x', d => x(d.num) - 5) .attr('y', y1.bandwidth()) .text(d => d.num )

Depending on what size you anticipate your users viewing the chart at, you might want to try to centre the text over the bar -- e.g. try

element.append('text') .attr('text-anchor', 'end') .attr('x', d => x(d.num) - 5) .attr('y', y1.bandwidth()/2) .attr('dy', '0.25em') .text(d => d.num )

Here's a working example:

$(window).on('resize', function(event) {  $("#chart").width(window.innerWidth * 0.9);  $("#chart").height(window.innerHeight);});function horizontalGroupBarChart(config) {  function setReSizeEvent(data) {    var resizeTimer;    var interval = 500;    window.removeEventListener('resize', function() {});    window.addEventListener('resize', function(event) {      if (resizeTimer !== false) {        clearTimeout(resizeTimer);      }      resizeTimer = setTimeout(function() {        $(data.mainDiv).empty();        drawHorizontalGroupBarChartChart(data);        clearTimeout(resizeTimer);      }, interval);    });  }  drawHorizontalGroupBarChartChart(config);  setReSizeEvent(config);}function createhorizontalGroupBarChartLegend(mainDiv, columnsInfo, colorRange) {  var z = d3.scaleOrdinal()    .range(colorRange);  var mainDivName = mainDiv.substr(1, mainDiv.length);  $(mainDiv).before("<div id='Legend_"+ mainDivName +"' class='pmd-card-body' style='margin-top:0; margin-bottom:0;text-align:center'></div>");  var keys = Object.keys(columnsInfo);  keys.forEach(function(d) {    var cloloCode = z(d);    $("#Legend_"+ mainDivName).append("<span class='team-graph team1' style='display: inline-block; margin-right:10px;'>\<span style='background:"+ cloloCode +";width: 10px;height: 10px;display: inline-block;vertical-align: middle;'>&nbsp;</span>\<span style='padding-top: 0;font-family:Source Sans Pro, sans-serif;font-size: 13px;display: inline;'>"+ columnsInfo[d] +"</span>\</span>");  });}function drawHorizontalGroupBarChartChart(config) {  var data = config.data;  var columnsInfo = config.columnsInfo;  var xAxis = config.xAxis;  var yAxis = config.yAxis;  var colorRange = config.colorRange;  var mainDiv = config.mainDiv;  var mainDivName = mainDiv.substr(1, mainDiv.length);  var label = config.label;  var requireLegend = config.requireLegend;  d3.select(mainDiv).append("svg").attr("width", $(mainDiv).width()).attr("height", $(mainDiv).height() * 0.80).attr("class", "mainSVG")  var svg = d3.select(mainDiv +" svg"),    margin = {      top: 20,      right: 20,      bottom: 40,      left: 40    },    width = +svg.attr("width") - margin.left - margin.right,    height = +svg.attr("height") - margin.top - margin.bottom;  var g = svg.append("g").attr("transform", "translate("+ (margin.left * 2.3) +","+ margin.top +")");  if (requireLegend != null && requireLegend != undefined && requireLegend != false) {    $("#Legend_"+ mainDivName).remove();    createhorizontalGroupBarChartLegend(mainDiv, columnsInfo, colorRange);  }  $(".mainSVG").attr("transform", "translate(5,10)")  var y0 = d3.scaleBand()    .rangeRound([height, 0])    .paddingInner(0.1);  var y1 = d3.scaleBand()    .padding(0.05);  var x = d3.scaleLinear()    .rangeRound([0, width - margin.left]);  var z = d3.scaleOrdinal()    .range(colorRange);  var keys = Object.keys(columnsInfo);  y0.domain(data.map(function(d) {    return d[yAxis];  }));  y1.domain(keys).rangeRound([0, y0.bandwidth()]);  x.domain([0, d3.max(data, function(d) {    return d3.max(keys, function(key) {      return d[key];    });  })]).nice();  var maxTicks = d3.max(data, function(d) {    return d3.max(keys, function(key) {      return d[key];    });  });  var element = g.append("g")    .selectAll("g")    .data(data)    .enter().append("g")    .attr("transform", function(d) {      return "translate(0,"+ y0(d[yAxis]) +")";    });  var rect = element.selectAll("rect")    .data(function(d, i) {      return keys.map(function(key) {        return {          key: key,          value: d[key],          index: key +"_"+ i +"_"+ d[yAxis]        };      });    })    .enter().append("rect")    .attr("y", function(d) {      return y1(d.key);    })    .attr("width", function(d) {      return x(d.value);    })    .attr("data-index", function(d, i) {      return d.index;    })    .attr("height", y1.bandwidth())    .attr("fill", function(d) {      return z(d.key);    })   element.append('text')     .attr('x', d => x(d.num) - 5)     .attr('y', y1.bandwidth()/2)     .attr('dy', '0.35em')     .attr('text-anchor', 'end')     .text(d => d.num )  var datax = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];  var tScale = d3.scaleLinear()    .rangeRound([0, width - margin.left]);  tScale.domain(d3.extent(datax)).nice();  //CBT:add tooltips  var self = {};  self.svg = svg;  self.cssPrefix = "horgroupBar0_";  self.data = data;  self.keys = keys;  self.height = height;  self.width = width;  self.label = label;  self.yAxis = yAxis;  self.xAxis = xAxis;  horBarTooltip.addTooltips(self);  rect.on("mouseover", function() {    var currentEl = d3.select(this);    var index = currentEl.attr("data-index");    horBarTooltip.showTooltip(self, index);  });  rect.on("mouseout", function() {    var currentEl = d3.select(this);    var index = currentEl.attr("data-index");    horBarTooltip.hideTooltip(self, index);  });  rect.on("mousemove", function() {    horBarTooltip.moveTooltip(self);  });  g.append("g")    .attr("class", "axis")    .attr("transform", "translate(0,"+ height +")")    .call(d3.axisBottom(x).ticks(maxTicks))    .append("text")    .attr("x", width / 2)    .attr("y", margin.bottom * 0.7)    .attr("dx", "0.32em")    .attr("fill", "#000")    .attr("font-weight", "bold")    .attr("text-anchor", "start")  g.append("g")    .attr("class", "axis")    .call(d3.axisLeft(y0).ticks(null, "s"))    .append("text")    .attr("x", height * 0.4 * -1)    .attr("y", margin.left * 0.8 * -1) //y(y.ticks().pop()) + 0.5)    .attr("dy", "0.71em")    .attr("fill", "#00338D")    .attr("font-weight", "bold")  // .attr("text-anchor", "start")}var helpers = {  getDimensions: function(id) {    var el = document.getElementById(id);    var w = 0,      h = 0;    if (el) {      var dimensions = el.getBBox();      w = dimensions.width;      h = dimensions.height;    } else {      console.log("error: getDimensions() "+ id +" not found.");    }    return {      w: w,      h: h    };  }}var horBarTooltip = {  addTooltips: function(pie) {    var keys = pie.keys;    // group the label groups (label, percentage, value) into a single element for simpler positioning    var element = pie.svg.append("g")      .selectAll("g")      .data(pie.data)      .enter().append("g")      .attr("class", function(d, i) {        return pie.cssPrefix +"tooltips"+"_"+ i      });    tooltips = element.selectAll("g")      .data(function(d, i) {        return keys.map(function(key) {          return {            key: key,            value: d[key],            index: key +"_"+ i +"_"+ d[pie.yAxis]          };        });      })      .enter()      .append("g")      .attr("class", pie.cssPrefix +"tooltip")      .attr("id", function(d, i) {        return pie.cssPrefix +"tooltip"+ d.index;      })      .style("opacity", 0)      .append("rect")      .attr("rx", 2)      .attr("ry", 2)      .attr("x", -2)      .attr("opacity", 0.71)      .style("fill", "#000000");    element.selectAll("g")      .data(function(d, i) {        return keys.map(function(key) {          return {            key: key,            value: d[key],            index: key +"_"+ i +"_"+ d[pie.yAxis]          };        });      })      .append("text")      .attr("fill", function(d) {        return "#efefef"      })      .style("font-size", function(d) {        return 10;      })      .style("font-family", function(d) {        return "arial";      })      .text(function(d, i) {        var caption = ""+ pie.label.xAxis +":{value}";        return horBarTooltip.replacePlaceholders(pie, caption, i, {          value: d.value,        });      });    element.selectAll("g rect")      .attr("width", function(d, i) {        var dims = helpers.getDimensions(pie.cssPrefix +"tooltip"+ d.index);        return dims.w + (2 * 4);      })      .attr("height", function(d, i) {        var dims = helpers.getDimensions(pie.cssPrefix +"tooltip"+ d.index);        return dims.h + (2 * 4);      })      .attr("y", function(d, i) {        var dims = helpers.getDimensions(pie.cssPrefix +"tooltip"+ d.index);        return -(dims.h / 2) + 1;      });  },  showTooltip: function(pie, index) {    var fadeInSpeed = 250;    if (horBarTooltip.currentTooltip === index) {      fadeInSpeed = 1;    }    horBarTooltip.currentTooltip = index;    d3.select("#"+ pie.cssPrefix +"tooltip"+ index)      .transition()      .duration(fadeInSpeed)      .style("opacity", function() {        return 1;      });    horBarTooltip.moveTooltip(pie);  },  moveTooltip: function(pie) {    d3.selectAll("#"+ pie.cssPrefix +"tooltip"+ horBarTooltip.currentTooltip)      .attr("transform", function(d) {        var mouseCoords = d3.mouse(this.parentNode);        var x = mouseCoords[0] + 4 + 2;        var y = mouseCoords[1] - (2 * 4) - 2;        return "translate("+ x +","+ y +")";      });  },  hideTooltip: function(pie, index) {    d3.select("#"+ pie.cssPrefix +"tooltip"+ index)      .style("opacity", function() {        return 0;      });    // move the tooltip offscreen. This ensures that when the user next mouseovers the segment the hidden    // element won't interfere    d3.select("#"+ pie.cssPrefix +"tooltip"+ horBarTooltip.currentTooltip)      .attr("transform", function(d, i) {        // klutzy, but it accounts for tooltip padding which could push it onscreen        var x = pie.width + 1000;        var y = pie.height + 1000;        return "translate("+ x +","+ y +")";      });  },  replacePlaceholders: function(pie, str, index, replacements) {    var replacer = function() {      return function(match) {        var placeholder = arguments[1];        if (replacements.hasOwnProperty(placeholder)) {          return replacements[arguments[1]];        } else {          return arguments[0];        }      };    };    return str.replace(/\{(\w+)\}/g, replacer(replacements));  }};var groupChartData = [{"num": 1,"over": "Singapore"}, {"num": 1.3,"over": "The Netherlands"}, {"num": 2,"over": "United Kingdom"}, {"num": 2.4,"over": "United States"}, {"num": 2.6,"over": "New Zealand"}, {"num": 2.8,"over": "Sweden"}, {"num": 3,"over": "Canada"}, {"num": 3,"over": "UAE"}, {"num": 4,"over": "Australia"}, {"num": 4.4,"over": "France"}, {"num": 5,"over": "South Korea"}, {"num": 5.2,"over": "Germany"}, {"num": 5.5,"over": "Austria"}, {"num": 6,"over": "Austria"}, {"num": 7,"over": "Brazil"}, {"num": 7,"over": "China"}, {"num": 8,"over": "Japan"}, {"num": 10,"over": "Russia"}, {"num": 11,"over": "Mexico"}, {"num": 12,"over": "India"}, ];var columnsInfo = {"num": "<span class='mainTitle KPMGWeb-ExtraLight'>Technology & innovation pillar: score by country</span>"};$("#chart").empty();var barChartConfig = {  mainDiv: "#chart",  colorRange: ["#0091DA", "#6D2077"],  data: groupChartData,  columnsInfo: columnsInfo,  xAxis: "runs",  yAxis: "over",  label: {    xAxis: "",    yAxis: ""  },  requireLegend: true};var groupChart = new horizontalGroupBarChart(barChartConfig);
.mainTitle {  font-size: 3em;}svg text {  font-size: 10px;  font-family: sans-serif;}
<script src="https://code.jquery.com/jquery-latest.min.js"></script><script src="https://d3js.org/d3.v4.min.js"></script><div id="chart" style="width: 800;height: 600">

By the way, I noticed that there seem to be two bars on the same line for Austria - not sure if that is deliberate or not.


Viewing all articles
Browse latest Browse all 42

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>