問題:我想更新圖表中的條形圖,以便在單擊“Dreamworks”按鈕時,它會附加新條形圖并洗掉舊條形圖。我知道這是一個 enter()、exit() 問題,但我不知道如何實作它。
背景關系:單擊我的按鈕時,它會激活一個函式,該函式會提取我的按鈕的內部 HTML 并使用它來過濾我的資料,因此只保留來自公司的觀察結果。該代碼有效,但不是擺脫舊條,而是將新條附加到舊條之上。當您查看控制臺時,每次單擊按鈕時都會出現一個新的“g”元素(其中包含新的“rects”)。我降低了“rects”的不透明度以顯示發生了什么。我從代碼中洗掉了所有 exit() 和 remove() 嘗試,因為沒有任何效果。
HTML 代碼:
<div class= "button-holder">
<button class= "button button-dreamworks">DreamWorks</button>
<button class= "button button-disney">Disney</button>
<button class= "button button-pixar">Pixar</button>
</div>
<div class = "chart chart1"></div>
JS代碼:
async function drawBar() {
// 2. Create Chart Dimensions
const width = 600
let dimensions = {
width,
height: width*0.6,
margin: {
top: 30,
right: 10,
bottom: 50,
left: 50
}
}
dimensions.boundedWidth = dimensions.width
-dimensions.margin.right -dimensions.margin.left
dimensions.boundedHeight = dimensions.height
-dimensions.margin.top -dimensions.margin.left
// 3. Draw Canvas
const wrapper = d3.select(".chart1")
.append("svg")
.attr("width", dimensions.width)
.attr("height", dimensions.height)
// 4. Load Data
const raw_data = await d3.csv("./data/all_movie_data.csv")
const drawBarChart = function(company_name) {
const dataset = raw_data.filter(function(d){ return d["company"] == company_name })
const xAccessor = d => d["name"]
const yAccessor = d => parseFloat(d.budget)
let bounds = wrapper
.append("g")
.attr("class", "bounds")
.style(
"transform",
`translate(${dimensions.margin.left}px,${dimensions.margin.top}px)`
);
// 5. Create scales
const xScale = d3.scaleBand()
.domain(dataset.map(xAccessor))
.range([0,dimensions.boundedWidth])
.padding(0.4);
const yScale = d3.scaleLinear()
.domain(d3.extent(dataset,yAccessor))
.range([dimensions.boundedHeight, 0])
// 6. Draw Data
bounds.selectAll("rect")
.data(dataset)
.join("rect")
.attr("x", (d) => xScale(xAccessor(d)))
.attr("y", (d) => yScale(yAccessor(d)))
.attr("width", xScale.bandwidth())
.attr("height", (d) => dimensions.boundedHeight - yScale(yAccessor(d)))
.attr("fill", "blue");
}
//6. Interactions
drawBarChart("Pixar");
const button1 = d3.select(".button-dreamworks")
.node()
.addEventListener("click", onClick1)
function onClick1() {
const company = document.querySelector(".button-dreamworks").innerHTML;
drawBarChart(company);
}
}
drawBar();
您可以在此代碼筆中找到我的代碼版本:https ://codepen.io/larylc/pen/XWzbQGy
一切都是一樣的,除了資料,我只是為了說明問題而編造的。
uj5u.com熱心網友回復:
答:我現在了解 enter()、exit() 結構。
通過將“rects”設定為變數(我稱之為條形圖),我現在可以操縱它們(這給了我一個與以前不同的選擇物件)。
我現在可以將 exit() 和 remove() 添加到 bars 變數。這在以前是不可能的。
我將 bounds 變數移動到我的畫布所在的部分,這完成了 exit() 和 enter() 模式。每次單擊按鈕時,DOM 中的 SVG 元素(條形)都會匹配應該添加的資料元素的數量。因此,如果我在 DOM 中有 22 個柱,它將更新為 34(或任何新資料集)。我之前試過這個,它有效,但我的欄沒有正確更新,這讓我想到了我的最后一點。
最后一個問題是添加或洗掉條形以匹配新資料點的數量而不更改現有資料點。這意味著 DOM 不會更新條形圖以匹配實際資料。因此,如果我有 13 個現有柱并且新資料是 22,它將只保留 13 并添加最后的 9。這不一定與資料匹配。所以我需要添加 merge(bars) 陳述句以確保我所有的 bar(包括現有的 bar)都會更新。
我的新 JS 代碼(所有按鈕都作業)
async function drawBar() {
// Create Chart Dimensions
const width = 600
let dimensions = {
width,
height: width*0.6,
margin: {
top: 30,
right: 10,
bottom: 50,
left: 50
}
}
dimensions.boundedWidth = dimensions.width
-dimensions.margin.right -dimensions.margin.left
dimensions.boundedHeight = dimensions.height
-dimensions.margin.top -dimensions.margin.left
// Draw Canvas
const wrapper = d3.select(".chart1")
.append("svg")
.attr("width", dimensions.width)
.attr("height", dimensions.height)
let bounds = wrapper
.append("g")
.attr("class", "bounds")
.style(
"transform",
`translate(${dimensions.margin.left}px,${dimensions.margin.top}px)`
);
// Load Data
const raw_data = await d3.csv("./data/all_movie_data.csv")
// Function that draws data
const drawBarChart = function(company_name) {
const dataset = raw_data.filter(function(d){ return d["company"] == company_name })
const xAccessor = d => d["name"]
const yAccessor = d => parseFloat(d.budget)
// Create scales
const xScale = d3.scaleBand()
.domain(dataset.map(xAccessor))
.range([0,dimensions.boundedWidth])
.padding(0.4);
const yScale = d3.scaleLinear()
.domain(d3.extent(dataset,yAccessor))
.range([dimensions.boundedHeight, 0])
// Draw Data
const bars = bounds.selectAll("rect")
.data(dataset)
bars.join("rect").merge(bars)
.attr("x", (d) => xScale(xAccessor(d)))
.attr("y", (d) => yScale(yAccessor(d)))
.attr("width", xScale.bandwidth())
.attr("height", (d) => dimensions.boundedHeight - yScale(yAccessor(d)))
.attr("fill", "blue")
.attr("opacity", 0.4)
bars.exit().remove();
}
// Interactions
drawBarChart("Pixar");
// All Buttons and functions that triggers data change
const button1 = d3.select(".button-dreamworks")
.node()
.addEventListener("click", onClick1)
function onClick1() {
const company = document.querySelector(".button-dreamworks").innerHTML;
drawBarChart(company);
}
const button2 = d3.select(".button-disney")
.node()
.addEventListener("click", onClick2)
function onClick2() {
const company2 = document.querySelector(".button-disney").innerHTML;
drawBarChart(company2);
}
const button3 = d3.select(".button-pixar")
.node()
.addEventListener("click", onClick3)
function onClick3() {
const company3 = document.querySelector(".button-pixar").innerHTML;
drawBarChart(company3);
}
}
drawBar();
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/427205.html
標籤:javascript d3.js
下一篇:y軸下方的條形圖出血D3.js
