我正在尝试在D3中创建一个具有可以使用滑块调整的比例的绘图。好像它略有失败;当我重新调整比例时,网格线有伪影。
知道我做错了什么吗?我有一个带onChange
方法的滑块,调用ysc.domain([0,this.value]);
重新缩放y轴,并重绘图形,包括轴刻度和网格线。
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.8.0/d3.min.js"></script>
<script type='text/javascript'>
document.addEventListener("DOMContentLoaded", function(event) {
var margin = {top: 10, right: 20, bottom: 20, left: 30},
width = 600,
height = 180;
// add the graph canvas to the body of the webpage
var svg = d3.select("div#plot1").append("svg")
.attr("width", width)
.attr("height", height);
var axis = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var xsc= d3.scaleLinear().domain([0,1]).range([0, width-margin.left-margin.right]),
ysc= d3.scaleLinear().domain([0,1]).range([height-margin.top-margin.bottom,0]);
var N = 500;
axis.append("path");
var line = d3.line()
.x(function(d,i) { return xsc(i/N); })
.y(function(d,i) { return ysc(d); });
var axis_drawn = d3.axisLeft( ysc );
axis.call( axis_drawn);
function drawGridLines ()
{
var grid=axis.selectAll("line.horizontalGrid");
grid.data( ysc.ticks( )).enter()
.append("line")
.attr('class','horizontalGrid')
.attr('x1',margin .right)
.attr('x2',width)
.attr('fill','none')
.attr( "shape-rendering" , "crispEdges")
.attr( "stroke" , "black")
.attr("stroke-width" , "1px")
.attr('opacity','0.2')
.merge(grid)
.attr('y1', ysc)
.attr('y2', ysc);
grid.exit().remove();
}
function drawGraph()
{
var data = [];
var ylim = ysc.domain();
for (var i = 0; i < N; ++i)
{
data.push((Math.cos(i*8*Math.PI/N) + 1)/2.0);
}
var waveform = axis.selectAll("path");
waveform.datum(data)
.attr("fill","none")
.attr("stroke","steelblue")
.attr("d", line);
axis.call( axis_drawn);
drawGridLines();
}
drawGraph();
function showRange(x) {
d3.select('#rangeLabel').text(x);
}
showRange(1);
d3.select('#range')
.on('change', function(d) {
ysc.domain([0,this.value]);
drawGraph();
showRange(this.value);
});
}); // DOMContentLoaded event
</script>
<style type='text/css'>
svg {
display: block;
margin-left: auto;
margin-right: auto;
}
.grid line {
stroke: lightgrey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
.hidden {
display: none;
}
div#interactive-container {
vertical-align: top;
display: inline-block;
position: relative;
left: 0;
}
form#interactive-controls {
border: 1px solid black;
display: inline-block;
}
div#plot2 {
display: inline-block;
position: relative;
left: 0;
}
</style>
</head><body>
<div id="plot1">
</div>
<div id='bottom-panel'>
<div id='interactive-container' class='hidden'>
<form id='interactive-controls'>
<input type="range" id='range' value='1', min='1', max='10', step='1'><span id='rangeLabel'></span>
</form>
</div>
</div>
</body>
</html>
答案 0 :(得分:2)
文档在这方面并不十分清楚,我之前就已经坚持过了。
selection.data().enter()...
selection.exit()...
与:
不同selection.data();
selection.enter()...
selection.exit()...
我们经常看到.data()。enter()链接只是因为所有元素都会被输入而没有退出:
如果我们没有现有元素,例如空页?然后 我们将数据加入到空选择中,所有数据都会结束 输入
这种模式很常见,你经常会看到selectAll +数据+ 输入+ append方法顺序调用,一个紧跟在后面 其他。尽管它很常见,但请记住,这只是一个 数据连接的特例。 (Mike's three little circles)。
您的代码适用于初始附加,因为所有数据最终都以enter()选择结束。在滴答数超过10之前不会出现任何问题,此时每当滴答数减少时,出口选择显然不能按预期工作。它是空的,没有删除任何东西。使用此设置:
selection.data();
selection.enter()...
selection.exit()...
应该解决这个问题:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.8.0/d3.min.js"></script>
<script type='text/javascript'>
document.addEventListener("DOMContentLoaded", function(event) {
var margin = {top: 10, right: 20, bottom: 20, left: 30},
width = 600,
height = 180;
// add the graph canvas to the body of the webpage
var svg = d3.select("div#plot1").append("svg")
.attr("width", width)
.attr("height", height);
var axis = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var xsc= d3.scaleLinear().domain([0,1]).range([0, width-margin.left-margin.right]),
ysc= d3.scaleLinear().domain([0,1]).range([height-margin.top-margin.bottom,0]);
var N = 500;
axis.append("path");
var line = d3.line()
.x(function(d,i) { return xsc(i/N); })
.y(function(d,i) { return ysc(d); });
var axis_drawn = d3.axisLeft( ysc );
axis.call( axis_drawn);
function drawGridLines ()
{
var grid=axis.selectAll("line.horizontalGrid")
.data( ysc.ticks() );
grid.enter()
.append("line")
.attr('class','horizontalGrid')
.attr('x1',margin .right)
.attr('x2',width)
.attr('fill','none')
.attr( "shape-rendering" , "crispEdges")
.attr( "stroke" , "black")
.attr("stroke-width" , "1px")
.attr('opacity','0.2')
.merge(grid)
.attr('y1', ysc)
.attr('y2', ysc);
grid.exit().remove();
}
function drawGraph()
{
var data = [];
var ylim = ysc.domain();
for (var i = 0; i < N; ++i)
{
data.push((Math.cos(i*8*Math.PI/N) + 1)/2.0);
}
var waveform = axis.selectAll("path");
waveform.datum(data)
.attr("fill","none")
.attr("stroke","steelblue")
.attr("d", line);
axis.call( axis_drawn);
drawGridLines();
}
drawGraph();
function showRange(x) {
d3.select('#rangeLabel').text(x);
}
showRange(1);
d3.select('#range')
.on('change', function(d) {
ysc.domain([0,this.value]);
drawGraph();
showRange(this.value);
});
}); // DOMContentLoaded event
</script>
<style type='text/css'>
svg {
display: block;
margin-left: auto;
margin-right: auto;
}
.grid line {
stroke: lightgrey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
.hidden {
display: none;
}
div#interactive-container {
vertical-align: top;
display: inline-block;
position: relative;
left: 0;
}
form#interactive-controls {
border: 1px solid black;
display: inline-block;
}
div#plot2 {
display: inline-block;
position: relative;
left: 0;
}
</style>
</head><body>
<div id="plot1">
</div>
<div id='bottom-panel'>
<div id='interactive-container' class='hidden'>
<form id='interactive-controls'>
<input type="range" id='range' value='1', min='1', max='10', step='1'><span id='rangeLabel'></span>
</form>
</div>
</div>
</body>
</html>