【问题标题】:SVG Legend for multi line chart d3 v6多折线图 d3 v6 的 SVG 图例
【发布时间】:2021-10-25 07:29:43
【问题描述】:

我正在尝试为这个多折线图表创建一个图例,这将是一条直线,那么如何根据之前分组的项目宽度计算分组项目的变换转换值。

<g class="legend">
   <g class="legend-group" transform="translate(0, 0)">
      <rect x="0" y="0" width="12" height="12" style="fill: red"/>
      <text x="16.79999" y="6" text-anchor="left" style="alignment-baseline: middle">Text 1</text>
   </g>
   <g class="legend-group" transform="translate(120, 0)">
      <rect x="0" y="0" width="12" height="12" style="fill: green"/>
      <text x="16.79999" y="6" text-anchor="left" style="alignment-baseline: middle">Text 2</text>
   </g>
   <g class="legend-group" transform="translate(240, 0)">
      <rect x="0" y="0" width="12" height="12" style="fill: red"/>
      <text x="16.79999" y="6" text-anchor="left" style="alignment-baseline: middle">Text 3 - Long Texttttt</text>
   </g>
</g>

所以在这里,就像这些文本的长度不同,因此为所有图例组提供固定宽度不起作用,最好的解决方案是什么,这是代码,有没有更好的方法来做到这一点?

let {data} = this.props,
  size = 12, 
  width = 120;

let legendGroup = select(node)
     .selectAll('.legend-group')
     .data(data)
     .enter()
     .append('g')
     .class('class', 'legend-group')
     .attr('transform', function(d, i) {
        return `translate(${width * i}, 0)`
     });

     legendGroup
       .append('rect')
       .attr('x', 0)
       .attr('y', 0)
       .attr('width', size)
       .attr('height', size)
       .style('fill', d => d.color);

     legendGroup
        .append('text')
        .attr('x', size * 1.4)
        .attr('y', size/2)
        .text(d => d.name)
        .attr('text-anchor', 'left')
        .style('alignment-baseline', 'middle')

【问题讨论】:

    标签: java svg d3.js charts


    【解决方案1】:

    这是一个获取每个组的宽度并使用它来设置位置的示例。

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <script src="https://d3js.org/d3.v7.js"></script>
    </head>
    
    <body>
        <div id="chart"></div>
    
        <script>
          // standard margin convention set up
    
          const margin = { top: 5, bottom: 5, left: 5, right: 5 };
    
          const width = 500 - margin.left - margin.right;
          const height = 500 - margin.top - margin.bottom;
    
          const svg = d3.select('#chart')
            .append('svg')
              .attr('width', width + margin.left + margin.right)
              .attr('height', height + margin.top + margin.bottom)
              .attr('font-family', 'sans-serif');
    
          const g = svg.append('g')
              .attr('transform', `translate(${margin.left},${margin.top})`);
    
          // color scale
    
          const color = d3.scaleOrdinal()
              .domain(['Label 1', 'Much much much longer label 2', 'Label 3'])
              .range(d3.schemeCategory10);
    
          // color legend
          
          const legend = g.append('g')
              .attr('font-family', 'sans-serif');
    
          // create one g for each entry in the color scale
          const cell = legend.selectAll('g')
            .data(color.domain())
            .join('g');
    
          const squareSize = 14;
    
          // add the colored square for each entry
          cell.append('rect')
              .attr('fill', d => color(d))
              .attr('width', squareSize)
              .attr('height', squareSize)
    
          // add the text label for each entry
          cell.append('text')
              .attr('dominant-baseline', 'middle')
              .attr('x', squareSize * 1.5)
              .attr('y', squareSize / 2)
              .text(d => d);
    
          // position the cells
          let xPosition = 0;
    
          cell.each(function(d, i) {
            d3.select(this)
                .attr('transform', `translate(${xPosition})`);
            
            xPosition += (this.getBBox().width + squareSize);
          });
        </script>
    </body>
    </html>

    或者,您也可以使用 HTML 创建图例。然后你可以利用 flexbox 来定位图例条目。

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <script src="https://d3js.org/d3.v7.js"></script>
    </head>
    
    <body>
        <div id="chart"></div>
    
        <script>
          // color scale
    
          const color = d3.scaleOrdinal()
              .domain(['Label 1', 'Much much much longer label 2', 'Label 3'])
              .range(d3.schemeCategory10);
    
          // color legend
    
          // create div for the legend to go in
          const legend = d3.select('#chart')
            .append('div')
              .style('display', 'flex')
              .style('font-family', 'sans-serif');
    
          // create one div for each entry in the color scale
          const cell = legend.selectAll('div')
            .data(color.domain())
            .join('div')
              .style('margin-right', '1em')
              .style('display', 'flex')
              .style('align-items', 'center');
    
          // add the colored square for each entry
          cell.append('div')
              .style('background', d => color(d))
              .style('min-width', '14px')
              .style('min-height', '14px')
              .style('margin-right', '0.5em');
    
          // add the text label for each entry
          cell.append('div')
              .text(d => d);
        </script>
    </body>
    </html>

    或者,如果图例需要在 SVG 元素中,那么您可以将 HTML 放在 &lt;foreignObject&gt; 中。

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <script src="https://d3js.org/d3.v7.js"></script>
    </head>
    
    <body>
        <div id="chart"></div>
    
        <script>
          // standard margin convention set up
    
          const margin = { top: 5, bottom: 5, left: 5, right: 5 };
    
          const width = 500 - margin.left - margin.right;
          const height = 500 - margin.top - margin.bottom;
    
          const svg = d3.select('#chart')
            .append('svg')
              .attr('width', width + margin.left + margin.right)
              .attr('height', height + margin.top + margin.bottom)
              .attr('font-family', 'sans-serif');
    
          const g = svg.append('g')
              .attr('transform', `translate(${margin.left},${margin.top})`);
    
          // color scale
    
          const color = d3.scaleOrdinal()
              .domain(['Label 1', 'Much much much longer label 2', 'Label 3'])
              .range(d3.schemeCategory10);
    
          // color legend
          
          const legend = g.append('g')
            .append('foreignObject')
              .attr('x', 0)
              .attr('y', 0)
              .attr('width', width)
              .attr('height', 20)
            .append('xhtml:div')
              .style('display', 'flex')
              .style('font-family', 'sans-serif');
    
          // create one div for each entry in the color scale
          const cell = legend.selectAll('div')
            .data(color.domain())
            .join('div')
              .style('margin-right', '1em')
              .style('display', 'flex')
              .style('align-items', 'center');
    
          // add the colored square for each entry
          cell.append('div')
              .style('background', d => color(d))
              .style('min-width', '14px')
              .style('min-height', '14px')
              .style('margin-right', '0.5em');
    
          // add the text label for each entry
          cell.append('div')
              .text(d => d);
        </script>
    </body>
    </html>

    【讨论】:

      猜你喜欢
      • 2012-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-24
      • 2016-10-06
      • 1970-01-01
      • 2022-09-23
      相关资源
      最近更新 更多