border for d3 stack bar chart on selection

Trying to implement border for selected bar in d3 stack bar chart. Here the first bar’s top border goes behind second bar a little bit. How to avoid this?

var svg, height, width, margin, parentWidth, parentHeight;

// container size
parentWidth = 700;
parentHeight = 500;
margin = {top: 50, right: 20, bottom: 35, left: 30};
width = parentWidth - margin.left - margin.right;
height = parentHeight - margin.top - margin.bottom;

var selectedSection = window.sessionStorage.getItem('selectedSection');

// data
var dataset = [{"label":"DEC","Set Up":{"count":12,"id":1,"label":"Set Up","year":"2016","graphType":"setup"},"Not Set Up":{"count":12,"id":0,"label":"Not Set Up","year":"2016","graphType":"setup"}},{"label":"JAN","Set Up":{"count":6,"id":1,"label":"Set Up","year":"2017","graphType":"setup"},"Not Set Up":{"count":21,"id":0,"label":"Not Set Up","year":"2017","graphType":"setup"}},{"label":"FEB","Set Up":{"count":1,"id":1,"label":"Set Up","year":"2017","graphType":"setup"},"Not Set Up":{"count":2,"id":0,"label":"Not Set Up","year":"2017","graphType":"setup"}},{"label":"MAR","Set Up":{"count":0,"id":1,"label":"Set Up","year":"2017","graphType":"setup"},"Not Set Up":{"count":0,"id":0,"label":"Not Set Up","year":"2017","graphType":"setup"}},{"label":"APR","Set Up":{"count":0,"id":1,"label":"Set Up","year":"2017","graphType":"setup"},"Not Set Up":{"count":0,"id":0,"label":"Not Set Up","year":"2017","graphType":"setup"}}];

// x cord
var x = d3.scale.ordinal()
    .rangeRoundBands([0, width], 0.2);

// color helper
var colorRange = d3.scale.category20();
var color = d3.scale.ordinal()
    .range(colorRange.range());

// x axis
var xAxis = d3.svg.axis()
    .scale(x)
    .orient('bottom');

var colors = ['#50BEE9', '#30738C'];

// Set SVG
svg = d3.select('#chart')
  .append('svg')
  .attr('width', width + margin.left + margin.right)
  .attr('height', height + margin.top + margin.bottom )
  .attr('class', 'setup')
  .append('g')
  .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

color.domain(d3.keys(dataset[0]).filter(function(key) { return key !== 'label'; }));

dataset.forEach(function(d) {
  var y0 = 0;
  d.values = color.domain().map(function(name) { 
    return {
      name: name, 
      y0: y0, 
      y1: y0 += +d[name].count, 
      patientStatus:d[name].id,
      graphType:d[name].graphType,  
      fromDate:{
        month:d.label,
        year:d[name].year
      },
      toDate:{
        month:d.label,
        year:d[name].year
      }  
    }; 
  });
  d.total = d.values[d.values.length - 1].y1;
});

var y = d3.scale.linear()
    .domain([0, d3.max(dataset, function(d) {  
    return d.total;
  })])
    .range([height, 0]);

var ticks = y.ticks(),
    lastTick = ticks[ticks.length-1];    
var newLastTick = lastTick + (ticks[1] - ticks[0]);  
if (lastTick<y.domain()[1]){
  ticks.push(lastTick + (ticks[1] - ticks[0]));
}

// adjust domain for further value
y.domain([y.domain()[0], newLastTick]);

// y axis
var yAxis = d3.svg.axis()
    .scale(y)
    .orient('left')
    .tickSize(-width, 0, 0) 
    .tickFormat(d3.format('d'))
    .tickValues(ticks);

x.domain(dataset.map(function(d) { return d.label; }));
y.domain([0, d3.max(dataset, function(d) { return d.total; })]);

svg.append('g')
  .attr('class', 'x axis')
  .attr('transform', 'translate(0,' + height + ')')
  .call(xAxis);

svg.append('g')
  .attr('class', 'y axis')
  .call(yAxis);

var bar = svg.selectAll('.label')
    .data(dataset)
    .enter().append('g')
    .attr('class', 'g')
    .attr('id', function(d, i) {
    return i;
  })
    .attr('transform', function(d) { return 'translate(' + x(d.label) + ',0)'; });

var barEnter = bar.selectAll('rect')
    .data(function(d) { return d.values; })
    .enter();

barEnter.append('rect')
  .attr('width', x.rangeBand())
  .attr('y', function(d) { 
    return y(d.y1); 
    })
  .attr('class', function(d, i){
    return 'bar';
    })
  .attr('height', function(d) { return y(d.y0) - y(d.y1); })
  .style('fill', function(d,i) { return colors[i]; })
  .on('click', function(d, i) {
    d3.selectAll('.bar').classed('selected', false);
    d3.select(this)
      .classed('bar selected', true);  
    });

barEnter.append('text')
  .text(function(d) { 
    var calcH = y(d.y0) - y(d.y1);
    var inText = (d.y1-d.y0);
    if(calcH >= 20) {
      return inText;
    } else {
      return '';
    }
})
.attr('class','inner-text')
.attr('y', function(d) { return y(d.y1)+(y(d.y0) - y(d.y1))/2 + 5; })
.attr('x', function(){
  return (x.rangeBand()/2) - 10;
}); 

svg
  .select('.y')
  .selectAll('.tick')
  .filter(function (d) { 
    return d % 1 !== 0;    
    })
  .style('display','none');

svg
  .select('.y')
  .selectAll('.tick')
  .filter(function (d) { 
    return d === 0;    
    })
  .select('text')
  .style('display','none');

JSFiddle

  • How can I show a loading screen while a really large image is loading?
  • I have an issue with swiper and arrow buttons (magic)
  • Getting font css property does not work in IE and Firefox with jQuery
  • What are the best books for HTML, CSS, PHP, Javascript, etc
  • Create DIV with onMouseOver effect with JS
  • Dropzone.js resize image to fit the thumbnail size
  • JSFiddle with d3 v4

  • AngularJS set width using ng-style
  • Media queries not working in Safari but in IE, Firefox and Chrome
  • Triggering CSS :active selector for non-anchor elements
  • multiple checkbox div 100% height of body
  • overflow not hidden but opacity changed
  • Need to find height of hidden div on page (set to display:none)
  • 2 Solutions collect form web for “border for d3 stack bar chart on selection”

    In a SVG, just like a real painter putting ink to a white canvas, the element that is painted last stays on top (read this example at S.O. docs: SVG: the drawing order).

    Right now, the behaviour you’re seeing is the expected one, because each stacked bar (rectangle) is in a different <g> element, and the groups, of course, have a given order in the SVG structure.

    The solution involves just one line:

    d3.select(this.parentNode).raise();
    

    What this line does is selecting the group of the clicked rectangle and raising it (that is, moving it down in the DOM tree), so that group will be on top of all others. According to the API, raise():

    Re-inserts each selected element, in order, as the last child of its parent. (emphasis mine)

    “Moving down”, “be on top” and “be the last child” may be a bit confusing and seem contradictory, but here is the explanation. Given this SVG structure:

    <svg>
        <foo></foo>
        <bar></bar>
        <baz></baz>
    </svg>
    

    <baz>, being the last element, is the one painted last, and it is the element visually on the top in the SVG. So, raising an element means moving it down in the SVG tree structure, but moving it up visually speaking.

    Here is your updated fiddle: https://jsfiddle.net/86Lgaupt/

    PS: I increased the stroke-width just to make visibly clear that the clicked rectangle is now on top.

    Tag:

      <div id='stacked-bar'></div>
    

    Script:

        var initStackedBarChart = {
        draw: function(config) {
            me = this,
            domEle = config.element,
            stackKey = config.key,
            data = config.data,
            margin = {top: 20, right: 20, bottom: 30, left: 50},
            parseDate = d3.timeParse("%m/%Y"),
            width = 550 - margin.left - margin.right,
            height = 400 - margin.top - margin.bottom,
            xScale = d3.scaleBand().range([0, width]).padding(0.1),
            yScale = d3.scaleLinear().range([height, 0]),
            color = d3.scaleOrdinal(d3.schemeCategory20),
            xAxis = d3.axisBottom(xScale).tickFormat(d3.timeFormat("%b")),
            yAxis =  d3.axisLeft(yScale),
            svg = d3.select("#"+domEle).append("svg")
                    .attr("width", width + margin.left + margin.right)
                    .attr("height", height + margin.top+10 + margin.bottom+10)
                    .append("g")
                    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
            var stack = d3.stack()
                .keys(stackKey)
                .order(d3.stackOrderNone)
                .offset(d3.stackOffsetNone);
    
            var layers= stack(data);
                data.sort(function(a, b) { return b.total - a.total; });
                xScale.domain(data.map(function(d) { return parseDate(d.date); }));
                yScale.domain([0, d3.max(layers[layers.length - 1], function(d) { return d[0] + d[1]; }) ]).nice();
    
            var layer = svg.selectAll(".layer")
                .data(layers)
                .enter().append("g")
                .attr("class", "layer")
                .style("fill", function(d, i) { return color(i); });
    
              layer.selectAll("rect")
                  .data(function(d) { return d; })
                .enter().append("rect")
            .attr('class', 'bar')
                  .attr("x", function(d) { return xScale(parseDate(d.data.date)); })
                  .attr("y", function(d) { return yScale(d[1]); })
                  .attr("height", function(d) { return yScale(d[0]) - yScale(d[1]) -1; })
                  .attr("width", xScale.bandwidth())
            .on('click', function(d, i) {
              d3.selectAll('.bar').classed('selected', false);
              d3.select(this).classed('selected', true);
            });
    
                svg.append("g")
                .attr("class", "axis axis--x")
                .attr("transform", "translate(0," + (height+5) + ")")
                .call(xAxis);
    
                svg.append("g")
                .attr("class", "axis axis--y")
                .attr("transform", "translate(0,0)")
                .call(yAxis);                           
        }
    }
    var data = [
    {"date":"4/1854","total":45,"disease":12,"wounds":14,"other":25},
    {"date":"5/1854","total":23,"disease":12,"wounds":0,"other":9},
    {"date":"6/1854","total":38,"disease":11,"wounds":0,"other":6},
    {"date":"7/1854","total":26,"disease":11,"wounds":8,"other":7}
    ];
    var key = ["wounds", "other", "disease"];
    initStackedBarChart.draw({
        data: data,
        key: key,
        element: 'stacked-bar'
    });
    

    Css:

    .axis text {
      font: 10px sans-serif;
    }
    .axis line,
    .axis path {
      fill: none;
      stroke: #000;
      shape-rendering: crispEdges;
    }
    .axis--x path {
      display: none;
    }
    .path-line {
      fill: none;
      stroke: yellow;
      stroke-width: 1.5px;
    }
    svg {
      background: #f0f0f0;
    }
    .selected{
      stroke:#333;
      stroke-width:2;
    
    }