用新的替换 d3.js 路径转换?
Posted
技术标签:
【中文标题】用新的替换 d3.js 路径转换?【英文标题】:Replacing a d3.js path transition with a new one? 【发布时间】:2015-02-13 09:10:09 【问题描述】:我见过this question 和many other 的例子,但它没有帮助。我正在尝试this page 上的最后一个示例,5 秒后,我希望正在绘制的弯曲路径完全消失,再过 5 秒,我希望创建一条新路径。
我已经尝试了下面的代码,但是虽然整个 svg
元素本身已被删除,但当我使用 appendGraph() 再次创建 svg
和路径时,相同的旧路径重新出现。如何确保完全删除旧路径并且在删除图形时也不会调用刻度函数?
小提琴在这里:http://jsfiddle.net/nav9/5uygqj9v/
代码是:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<style>
svg
font: 10px sans-serif;
.noselect
/* these are to disable text selection */
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
.axis path,
.axis line
fill: none;
stroke: #000;
opacity: 0.5;
shape-rendering: crispEdges;
rect.zoom
stroke: steelblue;
fill-opacity: 0.3;
#placeholder margin: 10px 5px 15px 70px;
</style>
<script type="text/javascript" src="http://d3js.org/d3.v3.js"></script>
</head>
<body>
<div id="placeholder" ></div>
<script>
//---------globals
var timer = null, interval = 500, value = 0;
var value1 = 0;
var n = 143, duration = interval, now = new Date(Date.now() - duration), count = 0, data = d3.range(n).map(function() return 0; );
var margin = top: 20, right: 40, bottom: 50, left: 60, width = 580 - margin.right, height = 420 - margin.top - margin.bottom;
var x = d3.time.scale().domain([now - (n - 2) * duration, now - duration]).range([0, width]);
var y = d3.scale.linear().domain([-1, 1]).range([height, 0]);
var line = d3.svg.line().interpolate("basis")
.x(function(d, i) return x(now - (n - 1 - i) * duration); )
.y(function(d, i) return y(d); );
var svg, path, yaxis, axis;
//--------program starts
appendGraph();
tick();
value1 = 0;
setTimeout(function() removeGraph();, 5000);
setTimeout(function() addGraphAgain();, 10000);
//-------------------------------functions -------------------------------
function appendGraph()
svg = d3.select("body").select("#placeholder").append("p").append("svg:svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("id", "mainSVG")
.style("margin-left", -margin.left + "px")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
axis = svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(x.axis = d3.svg.axis().scale(x).orient("bottom"));
yaxis = svg.append("g")
.attr("class", "y axis")
.call(y.axis = d3.svg.axis().scale(y).orient("left"));
path = svg.append("g")
.attr("clip-path", "url(#clip)")
.append("path")
.data([data])
.attr("id", "line1")
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-width", "1.5px")
.style("visibility","visible");
//appendGraph
//TODO: These tick functions could be simplified to handle more lines on the graph
function tick()
// push the accumulated count onto the back, and reset the count
value1 = Math.random() * 100;
if (value1 >= 0) data.push(value1); else data.push(0);//ensure that no NaN or undefined values corrupt the range
// update the domains
now = new Date();
x.domain([now - (n - 2) * duration, now - duration]);
count = 0;
// redraw the lines
svg.select("#line1").attr("d", line).attr("transform", null);
// slide the line left
path.transition().duration(duration).ease("linear").attr("transform", "translate(" + x(now - (n - 1) * duration) + ")").each("end", tick);
y.domain([0, 100]);
y = d3.scale.linear().domain([0, 100]).range([height, 0]);
yaxis.call(y.axis = d3.svg.axis().scale(y).orient("left"));
// pop the old data point off the front
data.shift();
console.log("tick being called");
function removeGraph()
path.transition().duration(0).each(function() this.__transition__.active = 0; );//at least this is stopping tick from being called
svg.selectAll("*").remove();
//-------tried these too
// d3.select("#mainSVG").remove("svg");
// d3.select("#line1").remove("path");
// path.remove();
//d3.selectAll("path").attr("d", "Z");
console.log("REMOVED");
//removeGraph
function addGraphAgain()
appendGraph();
tick();
value1 = 0;
console.log("ADDED AGAIN");
//addGraphAgain
</script>
</body>
</html>
【问题讨论】:
【参考方案1】:不是这个问题的确切答案,但因为我问这个问题的原因是因为我想要有阶段,我想将空输入发送到图表,除了删除线之外似乎没有其他方法可以做到这一点并将其替换为新行。
在 d3.js 中处理 null 或 NaN 数据或缺失数据或暂时不显示数据的技巧是使用 defined。
它的一个工作示例here 在行转换中是这样的:
我在if (counter%5==0) ran = null;data.push(ran);
提供一个随机数,.defined(function(d) return d != null; )
负责处理空值,而不是在那里画线。
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg
font: 10px sans-serif;
.line
fill: none;
stroke: #000;
stroke-width: 1.5px;
.axis path,
.axis line
fill: none;
stroke: #000;
shape-rendering: crispEdges;
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var n = 40,
random = d3.random.normal(0, .2),
data = d3.range(n).map(random);
var margin = top: 20, right: 20, bottom: 20, left: 40,
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.domain([0, n - 1])
.range([0, width]);
var y = d3.scale.linear()
.domain([-1, 1])
.range([height, 0]);
var line = d3.svg.line()
.defined(function(d) return d != null; )
.x(function(d, i) return x(i); )
.y(function(d, i) return y(d); );
var svg = d3.select("body").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 + ")");
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.svg.axis().scale(x).orient("bottom"));
svg.append("g")
.attr("class", "y axis")
.call(d3.svg.axis().scale(y).orient("left"));
var path = svg.append("g")
.attr("clip-path", "url(#clip)")
.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
var counter = 0;
tick();
function tick()
// push a new data point onto the back
var ran = random();
counter++;
if (counter%5==0) ran = null;
data.push(ran);
// redraw the line, and slide it to the left
path
.attr("d", line)
.attr("transform", null)
.transition()
.duration(500)
.ease("linear")
.attr("transform", "translate(" + x(-1) + ",0)")
.each("end", tick);
// pop the old data point off the front
data.shift();
</script>
【讨论】:
以上是关于用新的替换 d3.js 路径转换?的主要内容,如果未能解决你的问题,请参考以下文章
d3.js 使用 exit() 和 enter() 进行子转换