I'm trying to create a d3 area chart with a gradient area fill. But if the graph data starts or ends at value anything other than 0 then the area fills above the line. Here is the working fiddle with the code.
https://jsfiddle.net/damamgova/dhLb67mt/
var svg = d3.select("#" + id)
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Get the data
data.forEach(function(d) {
d.date = parseDate(d.date);
d.value = d.value;
});
var area = d3.svg.area()
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.value); })
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
const maxY = d3.max(data, function(d) { return d.value; });
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("stroke", color)
.attr("stroke-width", 3)
.attr("fill", "url(#gradient)")
.attr("d", valueline(data));
// Add Gradient
svg.append("linearGradient")
.attr("id", "gradient")
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", 0).attr("y1", y(0))
.attr("x2", 0).attr("y2", y(maxY))
.selectAll("stop")
.data([
{ offset: "0%", color: "transparent" },
{ offset: "50%", color: color + "50" },
{ offset: "100%", color: color }
])
.enter().append("stop")
.attr("offset", function(d) { return d.offset; })
.attr("stop-color", function(d) { return d.color; });
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
You are defining an area
path generator, but are not using it to generate the path for your line.
Instead, (in your fiddle, but not in the code above) you have defined a line generator called valueline
and are using that to generate the path.
If there is a fill, the line generator will close the line end with the line start and fill in the enclosed space, which is why you are seeing the fill above the line.
With the area generator you specify the y0
property, which in the case of your chart will simply be the bottom of the chart. The outputted path will then close along the base-line and any applied fill will be for the whole area.
Your path definition using the area path generator would be simply:
svg.append("path")
.attr("class", "line")
.attr("stroke", color)
.attr("stroke-width", 3)
.attr("fill", "url(#gradient)")
.attr("d", area(data));
There is an issue with this though, and that is that as you are not using a solid fill for your area and you are using a stroke, the bottom edge of the area will also be stroked. You could add a couple of pixels onto the height of the y0
parameter of your area
function so that the x axis covers it...