我有完全相似的问题
Eliminate sudden additions/deletions in D3 line chart transition
一个不同之处在于,我将线插入为"基础"
var line = d3.svg.line().interpolate('basis')
正好挣扎了13个小时:/请帮忙
<html>
<head>
<title>Chart</title>
<style>
path {
stroke: #f00;
}
.line {
stroke: #0f0;
fill: none;
stroke-width: 2px;
}
.rule {
stroke: #ccc;
stroke-width: 1px;
}
</style>
</head>
<body>
<p>I want to get the chart below to transition such that
the points on the lines appear to move up and down, not
side to side.
</p>
<p>When transitioning to the smaller data-set especially,
I'd like to not have a white gap appear before the lines
take shape.
</p>
<p>Also, the grid-lines should slide into and out of
existence, rather than appearing or disappearing. Ideas?
</p>
<script src="http://d3js.org/d3.v2.min.js"></script>
<script>
var data = [
[1,8,8,8,8,8,8,8,8,8,8,8,8,8,8],
[8,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
];
var data3 = [
[1,1,1],
[8,8,8],
];
var w = 500,
h = 100;
var chart = d3.select('body').append('div')
.attr('class', 'chart')
.append('svg:svg')
.attr('width', w)
.attr('height', h);
var color = d3.scale.category10();
// Add path interpolator to d3
d3.interpolators.push(function(a, b) {
debugger;
var isPath, isArea, interpolator, ac, bc, an, bn, d;
// Create a new array of a given length and fill it with the given value
function fill(value, length) {
return d3.range(length)
.map(function() {
return value;
});
}
// Extract an array of coordinates from the path string
function extractCoordinates(path) {
return path.substr(1, path.length - (isArea ? 2 : 1)).split('L');
}
// Create a path from an array of coordinates
function makePath(coordinates) {
return 'M' + coordinates.join('L') + (isArea ? 'Z' : '');
}
// Buffer the smaller path with coordinates at the same position
function bufferPath(p1, p2) {
var d = p2.length - p1.length;
if (isArea) {
return fill(p1[0], d/2).concat(p1, fill(p1[p1.length - 1], d/2));
} else {
return fill(p1[0], d).concat(p1);
}
}
isPath = /M-?\d*\.?\d*,-?\d*\.?\d*(L-?\d*\.?\d*,-?\d*\.?\d*)*Z?/;
if (isPath.test(a) && isPath.test(b)) {
isArea = a[a.length - 1] === 'Z';
ac = extractCoordinates(a);
bc = extractCoordinates(b);
an = ac.length;
bn = bc.length;
if (an > bn) {
bc = bufferPath(bc, ac);
}
if (bn > an) {
ac = bufferPath(ac, bc);
}
// Create an interpolater with the buffered paths (if both paths are of the same length,
// the function will end up being the default string interpolator)
interpolator = d3.interpolateString(bn > an ? makePath(ac) : a, an > bn ? makePath(bc) : b);
// If the ending value changed, make sure the final interpolated value is correct
return bn > an ? interpolator : function(t) {
return t === 1 ? b : interpolator(t);
};
}
});
function drawdata(data, chart) {
var num = data[0].length-1;
var x = d3.scale.linear().domain([0, num]).range([0,w]);
var y = d3.scale.linear().domain([0, 10]).range([h, 0]);
var line = d3.svg.line().interpolate('basis')
.x(function(d, i) { return x(i); })
.y(function(d) { return y(d); });
var flat = d3.svg.line()
.x(function(d, i) { return x(i); })
.y(y(-1));
var lines = chart.selectAll('.line')
.data(data);
lines.enter().append('path')
.attr('class', 'line')
.style('stroke', function(d,i) { return color(i); })
.attr('d', line);
lines.transition()
.ease('linear')
.duration(500)
.attr('d', line);
lines.exit().remove();
// legend
var ticks = chart.selectAll('line')
.data(x.ticks(num));
ticks.enter().append('line')
.attr('x1', x)
.attr('x2', x)
.attr('y1', 0)
.attr('y2', h)
.attr('class', 'rule');
ticks.transition()
.ease('linear')
.duration(500)
.attr('x1', x)
.attr('x2', x)
.attr('y1', 0)
.attr('y2', h);
ticks.exit().remove();
}
var dats = [data, data3];
function next() {
var it = dats.shift();
dats.push(it);
drawdata(it, chart);
}
setInterval(next, 2000);
next();
</script>
</body>
</html
&#13;
答案 0 :(得分:3)
部分答案:对于网格线,使用大于width
的值设置“输入”和“退出”选择:
<html>
<head>
<title>Chart</title>
<style>
path {
stroke: #f00;
}
.line {
stroke: #0f0;
fill: none;
stroke-width: 2px;
}
.rule {
stroke: #ccc;
stroke-width: 1px;
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var data = [
[0,2,3,2,8],
[2,4,1,5,3],
];
var data2 = [
[0,1,2,3,4,5],
[9,8,7,6,5,6],
];
var data3 = [
[1,3,2],
[0,8,5],
];
var w = 300,
h = 100;
var chart = d3.select('body').append('div')
.attr('class', 'chart')
.append('svg:svg')
.attr('width', w)
.attr('height', h);
var color = d3.scale.category10();
function drawdata(data, chart) {
var num = data[0].length-1;
var x = d3.scale.linear().domain([0, num]).range([0,w]);
var y = d3.scale.linear().domain([0, 10]).range([h, 0]);
var line = d3.svg.line().interpolate('basis')
.x(function(d, i) { return x(i); })
.y(function(d) { return y(d); });
var flat = d3.svg.line()
.x(function(d, i) { return x(i); })
.y(y(-1));
var lines = chart.selectAll('.line')
.data(data);
lines.enter().append('path')
.attr('class', 'line')
.style('stroke', function(d,i) { return color(i); })
.attr('d', line);
lines.transition()
.ease('linear')
.duration(500)
.attr('d', line);
lines.exit().remove();
// legend
var ticks = chart.selectAll('line')
.data(x.ticks(num));
ticks.enter().append('line')
.attr('x1', w+10)
.attr('x2', w+10)
.attr('y1', 0)
.attr('y2', h)
.attr('class', 'rule')
.transition()
.duration(500)
.attr('x1', x)
.attr('x2', x)
.attr('y1', 0)
.attr('y2', h);
ticks.transition()
.ease('linear')
.duration(500)
.attr('x1', x)
.attr('x2', x)
.attr('y1', 0)
.attr('y2', h);
ticks.exit().transition()
.duration(500)
.attr('x1', w+10)
.attr('x2', w+10)
.attr('y1', 0)
.attr('y2', h)
.remove();
}
var dats = [data, data2, data3];
function next() {
var it = dats.shift();
dats.push(it);
drawdata(it, chart);
}
setInterval(next, 2000);
next();
</script>
</body>
</html>
答案 1 :(得分:1)
我相信d3有更清洁的解决方案。请参阅var points0 = [
[1,8,8,8,8,8,8,8,8,8,8,8,8,8,8],
[8,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
];
var points1 = [
[1,1,1],
[8,8,8],
];
var w = 500,
h = 100;
var chart = d3.select('body').append('div')
.attr('class', 'chart')
.append('svg')
.attr('width', w)
.attr('height', h)
var color = d3.scale.category10();
function drawdata(data, svg) {
var num = data[0].length-1;
var x = d3.scale.linear().domain([0, num]).range([0,w]);
var y = d3.scale.linear().domain([0, 10]).range([h, 0]);
var line = d3.svg.line().interpolate('basis')
.x(function(d, i) { return x(i); })
.y(function(d) { return y(d); });
var flat = d3.svg.line()
.x(function(d, i) { return x(i); })
.y(y(-1));
var lines = chart.selectAll('path.line')
.data(data);
lines
.enter()
.append('path')
.attr('class', 'line')
.style('stroke', (d,i) => color(i))
lines
// .attr('d', line)
.transition()
.ease('linear')
.duration(500)
.attrTween("d", function(d) { return pathTween(line(d), 4, this)})
lines
.exit()
.remove();
// legend
var ticks = chart.selectAll('line')
.data(x.ticks(num));
ticks.enter()
.append('line')
.attr('x1', w+10) // HACK
.attr('x2', w+10) // HACK
.attr('y1', 0)
.attr('y2', h)
.attr('class', 'rule')
ticks.transition()
.ease('linear')
.duration(500)
.attr('x1', x)
.attr('x2', x)
.attr('y1', 0)
.attr('y2', h)
ticks.exit().remove();
}
const data = [points0, points1]
setInterval(() => {
const point = data[0]
data.reverse()
drawdata(point, chart)
}, 1e3);
function pathTween(d1, precision, path0) {
var path1 = path0.cloneNode(),
n0 = path0.getTotalLength(),
n1 = (path1.setAttribute("d", d1), path1).getTotalLength();
// Uniform sampling of distance based on specified precision.
var distances = [0], i = 0, dt = precision / Math.max(n0, n1);
while ((i += dt) < 1) {
distances.push(i);
}
distances.push(1);
// Compute point-interpolators at each distance.
var points = distances.map(function(t) {
var p0 = path0.getPointAtLength(t * n0),
p1 = path1.getPointAtLength(t * n1);
return d3.interpolate([p0.x, p0.y], [p1.x, p1.y]);
});
return function(t) {
return "M" + points.map(function(p) { return p(t); }).join("L");
};
}
。
path {
stroke: #f00;
}
.line {
stroke: #0f0;
fill: none;
stroke-width: 2px;
}
.rule {
stroke: #ccc;
stroke-width: 1px;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
&#13;
{{1}}&#13;
答案 2 :(得分:1)
使用Peter Beshai的d3-line-chunked!它完全符合您的需求:&#34;创建指示缺口数据缺失的行或不同样式的块/线段。&#34;
另见博客文章,他解释了同一问题的各种方法:how to display missing data。