Я пытаюсь совершить свой первый набег в D3.js - цель - это сгруппированный многострочный график с перетаскиваемыми точками, в результате перетаскивания точки также обновляется соединительная линия.В конце концов, обновленные данные должны быть переданы обратно в r (через r2d3 ()).До сих пор мне удавалось получить базовый сюжет и сделать точки перетаскиваемыми ... но когда дело доходит до обновления линии (и передачи данных назад), я уже несколько часов бьюсь об стену.Надеетесь, что кто-то может мне помочь?
Я вставляю полный сценарий, потому что я не верю, что нигде не сделал чего-то действительно неожиданного.Код, связанный с перетаскиванием, расположен внизу.В его текущей форме перетаскивание круга приводит к исчезновению первой из линий (светло-синей) независимо от того, какие из кругов перетаскиваются.При перетаскивании линии рисуются снова с использованием стандартного (меньшего) обводки, что, конечно, не так, как это должно работать в конце.В идеале линия движется с движением перетаскивания, хотя я также был бы рад, если бы обновленная линия была отрисована снова только после окончания перетаскивания.
Я думаю, что мне нужно знать, как получить идентификационную информацию из перетаскиваемого круга, использовать ее для обновления соответствующей переменной в данных (данные в широком формате, кстати) и обновления соответствующего пути,
бонусный вопрос: перетаскивание не работает при создании 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);
});
}