我正在尝试首次进入D3.js的目的-目的是创建具有可拖动点的分组多线图,其中拖动点会导致连接线也被更新。最终,更新的数据应传递回r(通过r2d3())。到目前为止,我设法获得了基准图并使点可拖动...但是当涉及到更新线(并传回数据?)时,我已经碰壁了几个小时。希望有人可以帮助我吗?
我要粘贴完整的脚本,因为我不相信自己在任何地方都没有做过真正意想不到的事情。与拖动有关的代码都位于底部。在当前形式下,拖动圆圈会使第一行(淡蓝色的线条)消失-不管拖动哪个圆圈。在draggend上,将使用默认(较小)笔划再次绘制线条,这当然不是最后的方式。理想情况下,线条会随着拖动运动而移动,但是如果在拖动结束后才再次绘制更新的线条,我也很高兴。
我认为我需要知道的是如何从拖动的圆中获取标识信息,并使用它来更新数据中的相应变量(数据是宽格式,顺便说一句),并更新相应的路径。
额外的问题:制作x scaleOrdinal(按预期)时,拖动不起作用。有没有解决方法?
// !preview r2d3 data= data.frame(id = c(1,1,2,2,3,3,4,4,5,5), tt = c(1, 2, 1, 2, 1, 2, 1, 2, 1, 2), val = c(14.4, 19.3, 22.0, 27.0, 20.7, 25.74, 16.9, 21.9, 18.6, 23.6))
var dById = d3.nest()
.key(function(d) {
return d.id;
})
.entries(data);
var margin = {
top: 40,
right: 40,
bottom: 40,
left: 40
},
width = 450 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var color = d3.scaleOrdinal()
.range(["#a6cee3", "#1f78b4", "#b2df8a", "#33a02c", "#fb9a99"]);
var x = d3.scaleLinear()
.range([0.25 * width, 0.75 * width])
.domain([1, 2]);
var y = d3.scaleLinear()
.rangeRound([height, 0])
.domain([0, d3.max(data, function(d) {
return d.val * 1.1;
})]);
var xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y);
// Define the line by data variables
var connectLine = d3.line()
.x(function(d) {
return x(d.tt);
})
.y(function(d) {
return y(d.val);
});
svg.append('rect')
.attr('class', 'zoom')
.attr('cursor', 'move')
.attr('fill', 'none')
.attr('pointer-events', 'all')
.attr('width', width)
.attr('height', height)
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var focus = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
focus.selectAll('lines')
.data(dById)
.enter().append("path")
.attr("class", "line")
.attr("d", function(d) {
return connectLine(d.values);
})
.attr("stroke", function(d) {
return color(d.key);
})
.attr('stroke-width', 4);
focus.selectAll('circles')
.data(dById)
.enter().append("g")
.attr("class", "dots")
.selectAll("circle")
.data(function(d) {
return d.values;
})
.enter().append("circle")
.attr("cx", function(d) {
return x(d.tt);
})
.attr("cy", function(d) {
return y(d.val);
})
.attr("r", 6)
.style('cursor', 'pointer')
.attr("fill", function(d) {
return color(d.id);
})
.attr("stroke", function(d) {
return color(d.id);
});
focus.append('g')
.attr('class', 'axis axis--x')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);
focus.append('g')
.attr('class', 'axis axis--y')
.call(yAxis);
/// drag stuff:
let drag = d3.drag()
.on('start', dragstarted)
.on('drag', dragged)
.on('end', dragended);
focus.selectAll('circle')
.call(drag);
// focus.selectAll('line')
// .call(drag);
function dragstarted(d) {
d3.select(this).raise().classed('active', true);
dragID = Math.round(x.invert(d3.event.x));
// get x at start in order to force the dragged circle to stay at this x-value (i.e. allow it to vertically only)
}
function dragged(d) {
dragNewY = y.invert(d3.event.y);
d3.select(this)
.attr('cx', x(dragID))
.attr('cy', y(dragNewY));
// focus.selectAll('path')
// .attr("d", function(d) { return connectLine(d); }); // removes all lines (to be redrawn at dragended with a smaller stroke)
focus.select('path').attr("d", function(d) {
return connectLine(d);
}); // removes first lines (to be redrawn at dragended with a smaller stroke)
// How do I select only the line associated with the dragged circle?
}
function dragended(d) {
d3.select(this).classed('active', false);
focus.selectAll('lines')
.data(dById)
.enter().append("path")
.attr("class", "line")
.attr("d", function(d) {
return connectLine(d.values);
})
.attr("stroke", function(d) {
return color(d.key);
});
}
答案 0 :(得分:0)
更新与圆相关的数据点,然后更新圆和所有线。
请勿在{{1}}
中添加新行dragend()