我正在尝试向名为 d3.js 的示例添加一个图例 d3.js 中放大的折线图
1°)我添加了脚本:
// Add legend rectangle
line.append('rect')
.attr('x', width - 80)
.attr('y', 90)
.attr('width', 10)
.attr('height', 10)
.style('fill', "steelblue");
// Add legend text
line.append("text")
.attr('x', width - 65)
.attr('y', 100)
.text('Blue line');
2°)我减少了现有代码中的 x 轴以将图例和图表分开:
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width - 100 ]);
不幸的是,当我缩放时,图例与图表合并了!怎么解决这个问题?
您下面的示例遵循
d3
中常用的编码约定,将图表的“绘图区域”围绕一系列边距分开。
// set the dimensions and margins of the graph
var margin = { top: 10, right: 100, bottom: 30, left: 60 },
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3
.select('#my_dataviz')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
我不会尝试按照您的方式调整 x 轴比例,而是增加右边距并将图例移动到那里。
这是一个例子:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="lib/style.css" />
<script src="lib/script.js"></script>
</head>
<body>
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<script>
// set the dimensions and margins of the graph
var margin = { top: 10, right: 100, bottom: 30, left: 60 },
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3
.select('#my_dataviz')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
//Read the data
d3.csv(
'https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/3_TwoNumOrdered_comma.csv',
// When reading the csv, I must format variables:
function (d) {
return { date: d3.timeParse('%Y-%m-%d')(d.date), value: d.value };
},
// Now I can use this dataset:
function (data) {
// Add X axis --> it is a date format
var x = d3
.scaleTime()
.domain(
d3.extent(data, function (d) {
return d.date;
})
)
.range([0, width]);
xAxis = svg
.append('g')
.attr('transform', 'translate(0,' + height + ')')
.call(d3.axisBottom(x));
// Add Y axis
var y = d3
.scaleLinear()
.domain([
0,
d3.max(data, function (d) {
return +d.value;
}),
])
.range([height, 0]);
yAxis = svg.append('g').call(d3.axisLeft(y));
// Add a clipPath: everything out of this area won't be drawn.
var clip = svg
.append('defs')
.append('svg:clipPath')
.attr('id', 'clip')
.append('svg:rect')
.attr('width', width)
.attr('height', height)
.attr('x', 0)
.attr('y', 0);
// Add brushing
var brush = d3
.brushX() // Add the brush feature using the d3.brush function
.extent([
[0, 0],
[width, height],
]) // initialise the brush area: start at 0,0 and finishes at width,height: it means I select the whole graph area
.on('end', updateChart); // Each time the brush selection changes, trigger the 'updateChart' function
// Create the line variable: where both the line and the brush take place
var line = svg.append('g').attr('clip-path', 'url(#clip)');
// Add the line
line
.append('path')
.datum(data)
.attr('class', 'line') // I add the class line to be able to modify this line later on.
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 1.5)
.attr(
'd',
d3
.line()
.x(function (d) {
return x(d.date);
})
.y(function (d) {
return y(d.value);
})
);
// Add the brushing
line.append('g').attr('class', 'brush').call(brush);
// A function that set idleTimeOut to null
var idleTimeout;
function idled() {
idleTimeout = null;
}
// add a legend
let legend = svg.append('g')
.attr('transform', 'translate(' + (width+10) + ', 10)')
.attr('class', 'legend');
legend.append('rect')
.attr('width', 10)
.attr('height', 10)
.attr('fill', 'steelblue');
legend.append('text')
.attr('x', 12)
.attr('y', 10)
.text('My Line!');
// A function that update the chart for given boundaries
function updateChart() {
// What are the selected boundaries?
extent = d3.event.selection;
// If no selection, back to initial coordinate. Otherwise, update X axis domain
if (!extent) {
if (!idleTimeout) return (idleTimeout = setTimeout(idled, 350)); // This allows to wait a little bit
x.domain([4, 8]);
} else {
x.domain([x.invert(extent[0]), x.invert(extent[1])]);
line.select('.brush').call(brush.move, null); // This remove the grey brush area as soon as the selection has been done
}
// Update axis and line position
xAxis.transition().duration(1000).call(d3.axisBottom(x));
line
.select('.line')
.transition()
.duration(1000)
.attr(
'd',
d3
.line()
.x(function (d) {
return x(d.date);
})
.y(function (d) {
return y(d.value);
})
);
}
// If user double click, reinitialize the chart
svg.on('dblclick', function () {
x.domain(
d3.extent(data, function (d) {
return d.date;
})
);
xAxis.transition().call(d3.axisBottom(x));
line
.select('.line')
.transition()
.attr(
'd',
d3
.line()
.x(function (d) {
return x(d.date);
})
.y(function (d) {
return y(d.value);
})
);
});
}
);
</script>
</body>
</html>