我正在用 D3.js 創建一個折線圖。data在“動態”計算新資料點(即陣列不斷增長)時,該線應隨時間出現。我有進行資料計算的函式,以及updateLine()你在下面看到的函式,在setInterval(). 我的問題是,此函式為每個新添加的資料點創建一個新的 svg 路徑,從而產生大量<path>元素。
function updateLine() {
canvas
.append('path')
.datum(data)
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 1.5)
.attr('d', d3.line()
.x(function(d, i) {return xSc(d.x)})
.y(function(d, i) {return ySc(d.z)})
)
}
如何使用新資料點“擴展”現有路徑?
uj5u.com熱心網友回復:
我找到了答案:
顯然,上面的代碼在<path>每次呼叫函式時都會附加一個新的。為了避免<path>DOM 中的“洪水”,我找到了兩個選項:
選項1
在添加新路徑之前,選擇缺少新資料點的舊路徑,并通過呼叫remove(). 為了避免選擇錯誤的路徑,我使用了 ID 選擇器。
function updateLine() {
canvas
.selectAll('#myPath').remove();
canvas
.append('path')
.datum(data)
.attr('id', '#myPath')
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 1.5)
.attr('d', d3.line()
.x(function(d, i) {return xSc(d.x)})
.y(function(d, i) {return ySc(d.z)})
)
}
選項2(我認為更優雅)
使用 aselectAll()選擇路徑,將資料系結到選擇并在選擇上呼叫 a join()。在第一次呼叫中updateLine(),創建了路徑(不存在 SVG 路徑,我們有一個非空的輸入選擇,其中附加了 SVG 路徑并設定了所有屬性)。在以下呼叫中,路徑存在于 DOM 中,并且新更新的資料陣列系結到它。因此,輸入選擇為空,更新選擇變得相關,我們用新資料更新路徑。
function updateLine() {
canvas.selectAll('#myPath')
.data([data])
.join(
function(enter) {
console.log('Enter selection:');
console.log(enter);
return enter
.append('path')
.attr('id', 'myPath')
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 1.5)
.attr('d', d3.line()
.x(function(d, i) {return xSc(d.x)})
.y(function(d, i) {return ySc(d.z)})
);
},
function(update) {
console.log('Update selection:');
console.log(update);
return update
.attr('d', d3.line()
.x(function(d, i) {return xSc(d.x)})
.y(function(d, i) {return ySc(d.z)})
);
}
);
}
關于選項 2 代碼的一些注意事項:
- 在這里使用 a
selectAll()而不僅僅是 a很重要select(),因為在函式的第一次呼叫中,不<path>存在。select()將選擇在這種情況下保持為空的第一個匹配項。 - 我呼叫
data([data])并因此將data陣列中的資料點與 SVG 元素連接起來。datum()據我了解,不會執行連接,但是,這在這里很重要,因為我們依賴于更新選擇。 - 再次將資料陣列作為陣列傳遞以
data([data])將所有資料點的資料系結到一個路徑元素,這正是我們在這里想要的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/506780.html
標籤:d3.js
