如何在D3.js中为垂直折线图填充Y轴与折线间的区域?
解决D3.js垂直折线图填充折线与Y轴区域的问题
我完全懂你现在的困扰——做垂直折线图时,想用d3.area填充折线到Y轴的区域,常规的y0设置不管用,只能靠加虚假数据凑效果,总觉得这不是最优解。其实不用修改原始数据,我们只需要给area生成器补充两个临时点,就能完美实现完整填充。
问题根源
你的垂直图表中,Y轴对应的是xScale(0)的位置,但当前的area生成器只使用了原始数据点,没有把折线的首尾和Y轴连接起来,所以只会填充折线首尾两点的连线区域,而不是折线到Y轴的全部区域。
解决方案:临时补充连接点
我们可以在绘制填充区域时,给数据临时添加两个点:一个是和原始数据起点同深度、parameter为0(对应Y轴)的点,另一个是和原始数据终点同深度、parameter为0的点。这样既不用修改原始数据,又能让area生成器自动完成完整填充。
修改后的代码实现
首先删掉你原来添加虚假数据的data.unshift(startElement)这一行,然后在绘制填充区域前,生成处理后的填充数据:
// 生成填充区域专用数据,在首尾添加连接到Y轴的点 const areaData = [ { depth: data[0].depth, parameter: 0 }, // 起点对应Y轴位置 ...data, // 原始数据 { depth: data[data.length - 1].depth, parameter: 0 } // 终点对应Y轴位置 ];
然后把原来填充区域的.datum(data)改成.datum(areaData),折线部分依然用原始data即可。完整修改后的draw2函数如下:
function draw2(selector2, allArray) { var data = allArray; // 移除原来的虚假数据添加逻辑 var margin = { top: 20, right: 20, bottom: 0, left: 35 }; var width = 150 - margin.left, height = 580 - margin.top; var svg = d3.select(selector2) .append("svg") .attr("class", "SVGcontent") .attr("width", width + margin.left) .attr("height", height + margin.top); // Pattern definition const defs = svg.append('defs') .append('pattern') .attr('id', 'whitecarbon2') .attr('patternUnits', 'userSpaceOnUse') .attr('width', 4) .attr('height', 4) .append('path') .attr('stroke', '#010101') .attr('stroke-width', 1) .attr("opacity", 0.5) .attr('d', 'M-1,1 l2,-2 M0,4 l4,-4 M3,5 l2,-2'); data.forEach(function(d) { d.parameter = parseFloat(d.parameter); }); var xScale = d3.scaleLinear() .domain([ d3.max(data, function(d) { return d.parameter }) + 0.4, 0 ]) .range([0, width]); var yScale = d3.scaleLinear() .domain([ 0, d3.min(data, function(d) { return d.depth }) ]) .range([0, height - 20]); var line = d3.line() .x(function(d) { return xScale(d.parameter) }) .y(function(d) { return yScale(d.depth) }); var artboard = svg.append("g") .attr("transform", "translate(35," + margin.top + ")"); var area = d3.area() .x1(function(d) { return xScale(d.parameter) }) .x0(xScale(0)) .y(function(d) { return yScale(d.depth) }); // 新增:生成填充区域的专用数据 const areaData = [ { depth: data[0].depth, parameter: 0 }, ...data, { depth: data[data.length - 1].depth, parameter: 0 } ]; // 绘制纯色填充层 artboard.append("path") .datum(areaData) .attr("class", "areaColore1") .attr("d", area) .attr("fill", "#fefefe"); // 绘制带图案的填充层 artboard.append("path") .datum(areaData) .attr("class", "area") .attr("d", area) .style('stroke', '#777777') .attr("fill", "url(#whitecarbon2)"); // 绘制折线(仍用原始数据) artboard.append("path") .attr("d", line(data)) .attr("stroke-width", "2") .attr("fill", "none"); var xAxis = d3.axisTop(xScale); ticks = xScale.ticks(1); ticks.push(0); ticks.push(0.3); xAxis.tickValues(ticks); var yAxis = d3.axisLeft(yScale); artboard.append("g") .attr("class", "xAxis") .call(xAxis) .selectAll("text") .attr("y", -15) .attr("x", 0) .attr("dy", ".35em") .attr("transform", "rotate(none)") .style("text-anchor", "middle"); artboard.append("g") .attr("transform", "translate(0,0)") .attr("class", "yAxis") .call(yAxis); // 添加Y轴标题 artboard.append("text") .attr("transform", "rotate(90)") .attr("y", 30) .attr("x", 6) .style('fill', '#777777') .style("text-anchor", "start") .text("Depth [m]"); function make_x_gridlines() { return xAxis.ticks(1); } function make_y_gridlines() { return yAxis.ticks(11); } artboard.append("g") .attr("class", "grid gridX") .call(make_x_gridlines() .tickSize(-height + margin.top - 50) .tickFormat("") ) artboard.append("g") .attr("class", "grid gridY2") .attr("transform", "translate(0,0)") .call(make_y_gridlines() .tickSize(-200) .tickFormat("") ) }
效果说明
这样修改后,填充区域会自动连接折线的起点和终点到Y轴(x=0)的位置,完美覆盖折线与Y轴之间的全部区域,同时原始数据不会被修改,保持了数据的纯净性。
内容的提问来源于stack exchange,提问作者Massimo
相关产品推荐
相关产品推荐

