I use D3.js
to import data from my CSV file into the project folder, using Live Server to create the HTML page produced in Visual Studio Code.
This piece of code is aimed at defining the text
of a div
:
enter.append("div")
.text(d => d.attackmomentum)
.style("color", "White");
The CSV
file(./stackoverflow.csv) has this format:
id,attackmomentum
9832401,25
The value 25
is exactly the text value, in case it changes like for example to 90
, the text would change from 25
to 90
.
With that in mind, in the update script, I added .data(data,d=>d.attackmomentum)
:
let update_5 = select_5.selectAll(".matches")
.data(data,d=>d.id)
.data(data,d=>d.attackmomentum);
But when updating the attackmomentum
column values in my CSV every 5 seconds according to the trigger I created, the value doesn't change according to what's in the file, it keeps the value from when I created the page.
What should I change to make this text update without needing to refresh the entire page?
Here is my full code (hiding only personal data for easy viewing).
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.1.1/d3.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-fetch@3"></script>
</head>
<body>
<div class="grid games" id="jogos-stackoverflow">
</div>
<script id="script-da-caixa-de-selecao-suspensa-5">
var select_5 = d3.select("#jogos-stackoverflow")
.append("div")
.attr("id","select-box-5")
.style("width","100%")
function valorparaiframe(iframevalue) {
let link = iframevalue;
return "https://........../" iframevalue "/";
}
async function update() {
let data = await d3.csv("./stackoverflow.csv");
let update_5 = select_5.selectAll(".matches")
.data(data,d=>d.id)
.data(data,d=>d.attackmomentum);
update_5.exit().remove();
// Enter new divs:
const enter = update_5.enter()
.append("div")
.attr("class","matches");
// Append the sum
enter.append("div")
.text(d => d.attackmomentum)
.style("color", "White");
// Append the children to entered divs:
enter.append("iframe")
.attr("src",d => valorparaiframe(d.id))
.style("width","100%")
.style("height","110");
}
update();
setInterval(update,5000);
</script>
</div>
</body>
</html>
CodePudding user response:
The double .data
is confusing me, but this is how I would do it.
You only updated the text of the new elements (after .enter()
only the new elements are selected), and not of the existing elements. In my opinion, , using .join
instead of .enter
makes it much easier to separate the one-off logic with the updating logic. This gives the following code:
async function update() {
let data = await d3.csv("./stackoverflow.csv");
select_5.selectAll(".matches")
.data(data, d => d.id)
.join(
enter => {
// First append the containing div
const divs = enter
.append("div")
.attr("class", "matches");
// Append a div with the text and the iframe
divs.append("div")
.style("color", "white");
divs.append("iframe")
.attr("src", d => valorparaiframe(d.id))
.style("width", "100%")
.style("height", "110")
// Return the divs matching ".matches" to be joined to the selection
return divs;
}
)
.select('div')
.text(d => d => d.attackmomentum);
}
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>