多折线图 d3 v6 的 SVG 图例
Posted
技术标签:
【中文标题】多折线图 d3 v6 的 SVG 图例【英文标题】:SVG Legend for multi line chart d3 v6 【发布时间】:2021-10-25 07:29:43 【问题描述】:我正在尝试为这个多折线图表创建一个图例,这将是一条直线,那么如何根据之前分组的项目宽度计算分组项目的变换转换值。
<g class="legend">
<g class="legend-group" transform="translate(0, 0)">
<rect x="0" y="0" 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" 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" 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')
【问题讨论】:
【参考方案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 放在 <foreignObject>
中。
<!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>
【讨论】:
以上是关于多折线图 d3 v6 的 SVG 图例的主要内容,如果未能解决你的问题,请参考以下文章