#javascript #reactjs #d3.js #data-visualization #linechart
Вопрос:
Я получаю данные для своего линейного графика из API. Каждый раз, когда данные обновляются, они не перерисовываются с плавным переходом, а вместо этого рисуют новые линии в верхней части существующей диаграммы. Это выглядит грязно. У меня нет жизненного цикла, как я пою useEffect
. Это как-то связано с line().remove().merge()
этим ? Что я делаю не так?
useEffect(() => {
const svg = d3
.select(svgRef.current)
.append("g")
.attr("transform", "translate(0," -130 ")");
const xScale = d3.scaleTime();
const yScale = d3.scaleLinear();
const xAxisDateFormat = d3.timeFormat("%b");
// line generator
const line = d3
.line()
.curve(d3.curveCatmullRom.alpha(1))
.x((d) => xScale(new Date(d.date)))
.y((d) => yScale(d.value));
// draw line chart
const lines = svg.append("g").attr("class", "lines");
lines
.selectAll(".line-group")
.data(lineChartData.values)
.enter()
.append("g")
.attr("class", "line-group")
.append("path")
.attr("class", "line")
.attr("stroke", (d, i) => colorScale(d.lineColor))
.attr("d", (d) => line(d.dataset));
}, [lineChartData]);
Ответ №1:
Вы можете просто очистить содержимое svg перед добавлением новых элементов.
Вместо:
const svg = d3
.select(svgRef.current)
.append("g")
делать:
const svgEl = d3.select(svgRef.current);
svgEl.selectAll('*').remove();
const svg = svgEl
.append('g')
Комментарии:
1. Это действительно возможно, но это приводит к ненужным вставкам/удалениям в DOM.
Ответ №2:
exit()
отсутствует в вашем коде:
const lines = svg.append("g")
.classed("lines", true);
const groups = lines
.selectAll(".line-group")
.data(lineChartData.values);
const newGroups = groups.enter()
.append("g")
.classed("line-group", true);
newGroups.append("path")
.classed("line", true)
.attr("stroke", (d, i) => colorScale(d.lineColor))
.attr("d", (d) => line(d.dataset));
const oldGroups = groups.exit();
oldGroups.remove();
Комментарии:
1. Спасибо, Майкл! Я не вижу, где в вашем примере используются новые группы?
2. Моя цель состояла в том, чтобы подчеркнуть, что
enter()
возвращает новые элементы (newGroups
), в то времяexit()
как возвращает старые элементы (oldGroups
), которые вам нужно удалить. Кроме того, важно отделить код, используемый для создания<g>
элементов, от кода, который добавляет<path>
элементы под ними (во избежание путаницы)… Это распространенная проблема, которую я вижу во многих примерах D3.3. Спасибо, что рассказали об этом подробнее. К сожалению, это не работает.
4. В моем ответе есть ошибка: должно быть
newGroups.append("path")
вместоgroups.append("path")
(я исправил это в ответе). Помогает ли это?5. Это то, что я изначально думал, так как newGroups на самом деле никогда не использовался, однако он по-прежнему рисуется поверх существующей диаграммы, поэтому я должен использовать решение, предоставленное @edgarkiljak.