Unwanted "border" on overlapping shape with svg / d3

Viewed 26

I followed this tutorial: https://bl.ocks.org/sarahob/1e291c95c4169ddabb77bbd10b6a7ef7 to show a progress bar with SVG / D3. enter image description here

As you can see on the tutorial (at least on Chrome) and this image, the background shape isn't overlapped entirely, so we see a small border.

The two shapes have exactly the same coordinates and sizes.

I could adjust the shape on top to have a slightly bigger size but that's messy and might risk that it looks bigger on some browsers? What's causing this and is there a proper fix?

For reference, the tutorial's code:

var svg = d3.select('.progress')
  .append('svg')
  .attr('height', 100)
  .attr('width', 500);

var states = ['started', 'inProgress', 'completed'],
  segmentWidth = 100,
  currentState = 'started';

var colorScale = d3.scale.ordinal()
  .domain(states)
  .range(['yellow', 'orange', 'green']);

svg.append('rect')
  .attr('class', 'bg-rect')
  .attr('rx', 10)
  .attr('ry', 10)
  .attr('fill', 'gray')
  .attr('height', 15) 
  .attr('width', function(){
    return segmentWidth * states.length;
  })
  .attr('x', 0);

var progress = svg.append('rect')
  .attr('class', 'progress-rect')
  .attr('fill', function(){
    return colorScale(currentState);
  })
  .attr('height', 15)
  .attr('width', 0)
  .attr('rx', 10)
  .attr('ry', 10)
  .attr('x', 0);

progress.transition()
  .duration(1000)
  .attr('width', function(){
    var index = states.indexOf(currentState);
    return (index + 1) * segmentWidth;
  });

function moveProgressBar(state){
  progress.transition()
    .duration(1000)
    .attr('fill', function(){
      return colorScale(state);
    })
    .attr('width', function(){
      var index = states.indexOf(state);
      return (index + 1) * segmentWidth;
    });
}
.progressSelector{
  margin-bottom: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<select class="progressSelector" onchange="moveProgressBar(value)">
  <option value="started" selected>Started</option>
  <option value="inProgress">In Progress</option>
  <option value="completed">Completed</option>
</select>

<div class="progress"></div>

1 Answers

See this post - but for your tutorial, interestingly, it only seems to happen with yellow on grey.

The way to resolve the issue is to set:

.style("shape-rendering", "crispEdges");

On both the background and foreground rect.

Here's a working example:

var svg = d3.select('.progress')
  .append('svg')
  .attr('height', 100)
  .attr('width', 500);

var states = ['started', 'inProgress', 'completed'],
    segmentWidth = 100,
  currentState = 'started';

var colorScale = d3.scale.ordinal()
  .domain(states)
  .range(['yellow', 'orange', 'green']);

svg.append('rect')
  .attr('class', 'bg-rect')
  .attr('rx', 10)
  .attr('ry', 10)
  .attr('fill', 'gray')
  .attr('height', 75) // was 15
  .attr('width', function(){
    return segmentWidth * states.length;
  })
  .attr('x', 0)
  .style("shape-rendering", "crispEdges");

var progress = svg.append('rect')
  .attr('class', 'progress-rect')
  .attr('fill', function(){
    return colorScale(currentState);
  })
  .attr('height', 75) // was 15
  .attr('width', 0)
  .attr('rx', 10)
  .attr('ry', 10)
  .attr('x', 0)
  .style("shape-rendering", "crispEdges");

progress.transition()
  .duration(1000)
  .attr('width', function(){
    var index = states.indexOf(currentState);
    return (index + 1) * segmentWidth;
  });

function moveProgressBar(state){
  progress.transition()
    .duration(1000)
    .attr('fill', function(){
      return colorScale(state);
    })
    .attr('width', function(){
      var index = states.indexOf(state);
      return (index + 1) * segmentWidth;
    });
}
.progressSelector{
  margin-bottom: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<select class="progressSelector" onchange="moveProgressBar(value)">
  <option value="started" selected>Started</option>
  <option value="inProgress">In Progress</option>
  <option value="completed">Completed</option>
</select>

<div class="progress"></div>

Related