javascript - 移动折线图上的圆圈
问题描述
想在我的实时折线图上绘制圆圈。该图表每次迭代都会生成随机 y 值并将其绘制在图表上,从而移动域。这是我的代码-
const svg = d3.select('svg');
const MARGIN = {TOP: 50, BOTTOM: 50, LEFT: 50, RIGHT: 50};
const WIDTH = svg.attr('width') - MARGIN.LEFT - MARGIN.RIGHT;
const HEIGHT = svg.attr('height') - MARGIN.TOP - MARGIN.BOTTOM;
const limit = 60;
const duration = 500;
let dataList = [];
let g = svg.append('g').attr('transform', `translate( ${MARGIN.LEFT}, ${MARGIN.TOP} )`);
g.append('defs').append('clipPath')
.attr('id', 'clip2')
.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', WIDTH)
.attr('height', HEIGHT);
// ParseTime
const timeScale = d3.scaleTime()
.range([0, WIDTH]);
const valueScale = d3.scaleLinear()
.domain([0, 10])
.range([HEIGHT, 0]);
const line = d3.line()
.curve(d3.curveBasis)
.x((d) => timeScale(d.time))
.y((d) => valueScale(d.value));
const xAxis = d3.axisBottom(timeScale);
const axisCall = g.append('g')
.attr('transform', `translate(0, ${HEIGHT})`);
axisCall.call(xAxis);
g.append('g')
.attr('class', 'axis axis--y')
.call(d3.axisLeft(valueScale))
let pathsG = g.append('g').attr('id', 'paths').attr('class', 'paths').attr('clip-path', 'url(#clip2)');
function updateChart() {
let now = Date.now();
dataList.push({
time: now,
value: Math.floor(Math.random() * 10)
});
// Shift domain
timeScale.domain([now - ((limit - 2) * duration), now - duration]);
axisCall.transition().duration(duration).ease(d3.easeLinear, 2).call(xAxis);
let minerG = pathsG.selectAll('.minerLine').data([dataList]);
let minerGEnter = minerG.enter()
.append('g')
.attr('class', 'minerLine')
.merge(minerG);
let minerSVG = minerGEnter.selectAll('path').data(function(d) {
return [d];
});
let minerSVGenter = minerSVG.enter()
.append('path').attr('class', 'line')
.style('stroke', '#D073BA')
.style('fill', 'none')
.merge(minerSVG)
.transition()
.duration(duration)
.ease(d3.easeLinear, 2)
.attr('d', line(dataList))
.attr('transform', null);
let circles = minerGEnter.selectAll('circle')/*.data(function(d) {
return [d];
});*/
circles.data(dataList)
.enter()
.append('circle')
.merge(circles)
.transition()
.duration(duration)
.ease(d3.easeLinear, 2)
.attr('r', 5)
.attr('cx', (d, i) => timeScale(d.time))
.attr('cy', d => valueScale(d.value));
circles.exit().remove();
}
setInterval(function(){
//console.log('hello');
updateChart();
}, 500);
<!DOCTYPE html>
<html>
<head></head>
<title>Real-time Line Chart D3</title>
<link rel="stylesheet" href="styles.css">
<script src="https://d3js.org/d3.v5.min.js"></script>
<body>
<svg width="960" height="500">
</svg>
<script src="bundle.js"></script>
</body>
</html>
如您所见,图表有效,但圆圈无效。他们是两个问题。图表显示圆圈进入图表的动画,圆圈似乎有错误的 y 值。我很确定我添加圆圈的方式不正确。尝试从在线代码中获取示例,但没有任何效果。
任何想法如何解决这两个问题?
解决方案
圆圈的位置没有错,它们是正确的。它们可能看起来是错误的,因为您d3.curveBasis
对路径使用了插值器 ( ),它会修改它:删除插值器可以清楚地说明这一点,如下面的演示所示。此外,关于转换,解决方案可能是在输入选择中设置圆的位置,并且仅x
在更新选择中转换位置。
这是您的代码,仅包含这 2 个更改:
const svg = d3.select('svg');
const MARGIN = {
TOP: 50,
BOTTOM: 50,
LEFT: 50,
RIGHT: 50
};
const WIDTH = svg.attr('width') - MARGIN.LEFT - MARGIN.RIGHT;
const HEIGHT = svg.attr('height') - MARGIN.TOP - MARGIN.BOTTOM;
const limit = 60;
const duration = 500;
let dataList = [];
let g = svg.append('g').attr('transform', `translate( ${MARGIN.LEFT}, ${MARGIN.TOP} )`);
g.append('defs').append('clipPath')
.attr('id', 'clip2')
.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', WIDTH)
.attr('height', HEIGHT);
// ParseTime
const timeScale = d3.scaleTime()
.range([0, WIDTH]);
const valueScale = d3.scaleLinear()
.domain([0, 10])
.range([HEIGHT, 0]);
const line = d3.line()
.x((d) => timeScale(d.time))
.y((d) => valueScale(d.value));
const xAxis = d3.axisBottom(timeScale);
const axisCall = g.append('g')
.attr('transform', `translate(0, ${HEIGHT})`);
axisCall.call(xAxis);
g.append('g')
.attr('class', 'axis axis--y')
.call(d3.axisLeft(valueScale))
let pathsG = g.append('g').attr('id', 'paths').attr('class', 'paths').attr('clip-path', 'url(#clip2)');
function updateChart() {
let now = Date.now();
dataList.push({
time: now,
value: Math.floor(Math.random() * 10)
});
// Shift domain
timeScale.domain([now - ((limit - 2) * duration), now - duration]);
axisCall.transition().duration(duration).ease(d3.easeLinear, 2).call(xAxis);
let minerG = pathsG.selectAll('.minerLine').data([dataList]);
let minerGEnter = minerG.enter()
.append('g')
.attr('class', 'minerLine')
.merge(minerG);
let minerSVG = minerGEnter.selectAll('path').data(function(d) {
return [d];
});
let minerSVGenter = minerSVG.enter()
.append('path').attr('class', 'line')
.style('stroke', '#D073BA')
.style('fill', 'none')
.merge(minerSVG)
.transition()
.duration(duration)
.ease(d3.easeLinear, 2)
.attr('d', line(dataList))
.attr('transform', null);
let circles = minerGEnter.selectAll('circle').data(function(d) {
return d;
});
circles.exit().remove();
circles = circles.enter()
.append('circle')
.attr('r', 5)
.attr('cx', (d, i) => timeScale(d.time))
.attr('cy', d => valueScale(d.value))
.merge(circles);
circles.transition()
.duration(duration)
.ease(d3.easeLinear, 2)
.attr('cx', (d, i) => timeScale(d.time));
}
setInterval(function() {
//console.log('hello');
updateChart();
}, 500);
<!DOCTYPE html>
<html>
<head></head>
<title>Real-time Line Chart D3</title>
<link rel="stylesheet" href="styles.css">
<script src="https://d3js.org/d3.v5.min.js"></script>
<body>
<svg width="960" height="500">
</svg>
<script src="bundle.js"></script>
</body>
</html>
推荐阅读
- c# - iTextSharp 不适用于 foreach 循环
- linux - sftp 通过 cronjob 中的 bash 脚本:找不到“get”和“rm”命令?
- python - 无论如何要避免正则表达式函数区分字符串中的特殊字符
- javascript - Safari - iPhone - 自动更改网站规模
- javascript - 使用 request-promise 使用 jwt 进行 API 调用。[ERR_INVALID_ARG_TYPE] 收到
- python - 在日期时间解析中使用当前月/日
- python - 创建一个新列,该列是满足两个条件的多个其他列中的日期数之和
- scala - reduceByKey 函数可以更改密钥吗?
- python - 如何最有效地存储矩阵的值
- java - 在android studio中选择多个复选框时自动显示值