D3.js分组条形图网格线与坐标轴刻度自定义实现问题
解决方案
针对你提出的三个问题,修改方案如下:
1. 调整X轴网格线到分组结束边界
原有X轴网格线默认使用x0比例尺的刻度(即每个分组的中心位置),我们可以自定义网格刻度值,计算每个分组的右侧边界位置作为网格线的绘制位置。
2. 网格线移至图表下层
SVG元素遵循「先渲染的元素层级更低」的规则,将网格线的渲染逻辑移到条形图柱子、坐标轴的渲染逻辑之前即可。
3. Y轴刻度改为完整数值
原有Y轴调用了ticks(null, 's'),其中s参数表示使用SI单位缩写,删除该参数即可取消k格式的简写。
修改后完整代码
<html> <head> <meta charset="UTF-8" /> </head> <body> <div id="grouped-chart"></div> <script src="https://d3js.org/d3.v4.min.js"></script> <script> const data = [ { category: { model: 'A', }, type1: '1000', type2: '2000', }, { category: { model: 'B', }, type1: '2000', type2: '3000', }, { category: { model: 'C', }, type1: '1500', type2: '4000', }, ]; const margin = { top: 20, right: 30, bottom: 30, left: 60 }; const width = 400 - margin.left - margin.right; const height = 400 - margin.top - margin.bottom; const svg = d3 .select('#grouped-chart') .append('svg') .attr('width', width + margin.left + margin.right) .attr('height', height + margin.top + margin.bottom) .style('background', '#fff'); const g = svg .append('g') .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); const x0 = d3.scaleBand().rangeRound([0, width]).paddingInner(0.1); const x1 = d3.scaleBand().padding(0.05); const y = d3.scaleLinear().rangeRound([height, 0]); const z = d3.scaleOrdinal().range(['#004c6d', '#255e7e', '#3d708f']); const keys = Object.keys(data[0]).slice(1); x0.domain(data.map((d) => d.category.model)); x1.domain(keys).rangeRound([0, x0.bandwidth()]); y.domain([0, 4000]); // 先渲染网格(最下层) // Y轴网格 g.append('g') .attr('class', 'grid') .call(d3.axisLeft().scale(y).tickSize(-width, 0, 0).tickFormat('')); // X轴网格:自定义刻度为每个分组的右侧边界 const xGridTicks = x0.domain().map(d => x0(d) + x0.bandwidth()); g.append('g') .attr('class', 'grid') .attr('transform', `translate(0, ${height})`) .call(d3.axisBottom().scale(x0.copy().domain(xGridTicks)).tickSize(-height, 0, 0).tickFormat('')); // 再渲染坐标轴 const gX = g .append('g') .attr('class', 'axis') .attr('transform', 'translate(0,' + height + ')') .call(d3.axisBottom(x0)); const gY = g .append('g') .attr('class', 'axis') // 删除's'参数取消SI单位缩写 .call(d3.axisLeft(y).ticks(null)); // 最后渲染柱子(最上层) g.append('g') .selectAll('g') .data(data) .enter() .append('g') .attr('transform', (d) => 'translate(' + x0(d.category.model) + ',0)') .selectAll('rect') .data((d) => keys.map((key) => { return { key: key, value: d[key] }; }) ) .enter() .append('rect') .attr('x', (d) => x1(d.key)) .attr('y', (d) => y(d.value)) .attr('width', x1.bandwidth()) .attr('height', (d) => height - y(d.value)) .attr('fill', (d) => z(d.key)); </script> </body> </html>
内容的提问来源于stack exchange,提问作者hanik
相关产品推荐
相关产品推荐

