Search code examples
javascriptd3.jsleaflet

How to remove white line in d3.js legend?


How can I remove white line (space) in d3.js legend? I am defining a colorscale range and it works perfectly except it adds white line sapce between values. Here is an example https://jsfiddle.net/aba2s/u46xoh97/1/

function drawLinkLegend(colorscale, min, max) {
    linkLabel.style.display = 'block'
    var legendWidth = 100
        legendMargin = 10
        legendLength = document.getElementById('legend-links-container').offsetHeight - 2*legendMargin

    var legendSvg = d3.select('#legend-links-svg')
                .append('g')
                .attr("id", "linkLegendSvg");

    var dif = colorscale.domain()[1] - colorscale.domain()[0];
    var intervals = d3.range(400).map(function(d,i) {
        return dif * i / 400 + colorscale.domain()[0]
    })
    intervals.push(colorscale.domain()[1]);
    var intervalHeight = legendLength / intervals.length;    
    var bars = legendSvg.selectAll(".bars")
      .data(intervals)
      .enter().append("rect")
        .attr("class", "bars")
        .attr("x", 0)
        .attr("y", function(d, i) { return Math.round((intervals.length - 1 - i)  * intervalHeight) + legendMargin; })
        .attr("height", intervalHeight)
        .attr("width", legendWidth-50)
        .style("fill", function(d, i) { return colorscale(d) })
        .attr("stroke-width",0)
    var legendAxis = d3.scaleLinear()
        .domain([min, max])
        .range([legendLength, 0]);
    legendSvg.append("g")
         .attr("class", "legend axis")
         .attr("transform", "translate(" + (legendWidth - 50) + ", " + legendMargin + ")")
         .call(d3.axisRight().scale(legendAxis).ticks(10))
}

Solution

  • When creating your legend, you're setting a height of intervalHeight for each of the legend colour blocks, and you're calculating a y attribute for where to place each of the legend blocks based on that intervalHeight, however, you're rounding that calculated y attribute, which is sometimes making that yvalue higher than it should be, resulting in a gap.

    To solve this, you could modify your y to be set to

    function(d, i) { return ((intervals.length - 1 - i)  * intervalHeight) + legendMargin; }
    

    without the rounding, or a neat solution I found was to make the height just a little bigger to bridge that gap be setting

    .attr("height", intervalHeight + 1)
    

    This way, the height of each bar is a little bit too tall, but it will be masked by the next one anyway. The only visual difference is that the white gap is no longer there.