D3.js分组柱状图自定义X轴带图文混合标签的实现方法
完全可以实现,你需要替换D3默认生成的纯文本X轴刻度,自定义刻度标签内容即可,具体修改方案如下:
核心修改要点
- 增大SVG底部边距,给包含图片、多行文本的自定义标签预留足够的显示空间,原代码底部边距仅30,可调整为80左右
- 渲染默认X轴后移除自带的文本标签,避免和自定义内容重叠
- 单独为每个X轴分组创建标签容器,绑定对应数据后按需求插入图片、文本,设置水平居中属性即可实现对齐效果
完整修改后代码
<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: 'Model1', titleText1: 'T1', titleText2: 'T2' }, field1: '1000', field2: '2000', }, { category: { model: 'Model2', titleText1: 'T3', titleText2: 'T4' }, field1: '2000', field2: '3000', } ]; // 调整底部边距预留标签空间 const margin = { top: 20, right: 30, bottom: 80, 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]); // 渲染X轴后移除默认文本 g.append('g') .attr('class', 'axis') .attr('transform', 'translate(0,' + height + ')') .call(d3.axisBottom(x0)) .selectAll('text') .remove(); g.append('g') .attr('class', 'axis') .call(d3.axisLeft(y).ticks(null, 's')); 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)); // ========== 新增自定义X轴标签代码 ========== const xLabelGroups = g.append('g') .selectAll('.custom-x-label') .data(data) .enter() .append('g') .attr('class', 'custom-x-label') // 定位到每个分组的水平中心,实现居中 .attr('transform', d => `translate(${x0(d.category.model) + x0.bandwidth()/2}, ${height + 10})`); // 上层左侧图片 xLabelGroups.append('image') .attr('xlink:href', '替换为你的上层图片实际地址') .attr('width', 16) .attr('height', 16) .attr('x', -30) .attr('y', 0); // 上层第一个文本Model xLabelGroups.append('text') .attr('text-anchor', 'middle') .attr('x', 0) .attr('y', 12) .style('font-size', '12px') .text(d => d.category.model); // 上层第二个文本T1 xLabelGroups.append('text') .attr('text-anchor', 'middle') .attr('x', 20) .attr('y', 12) .style('font-size', '12px') .text(d => d.category.titleText1); // 下层左侧图片 xLabelGroups.append('image') .attr('xlink:href', '替换为你的下层图片实际地址') .attr('width', 16) .attr('height', 16) .attr('x', -30) .attr('y', 25); // 下层单行文本 xLabelGroups.append('text') .attr('text-anchor', 'middle') .attr('x', 0) .attr('y', 38) .style('font-size', '12px') .text(d => d.category.titleText2); </script> </body> </html>
你可以根据自己的需求调整图片地址、尺寸、文本位置偏移量,即可完全匹配预期效果。
内容的提问来源于stack exchange,提问作者hanik
相关产品推荐
相关产品推荐

