0👍
Here’s a revised version of your code that shows how to accomplish what you’re trying to do. (I wasn’t sure what your barChart
object looks like, so I substituted something relatively simple that should be close enough for demo purposes.)
Each button has a "data attribute" called number
whose value gets passed to the changeTo
function so the correct number of elements will be shown. (It’s fine, if you prefer, to use the changeTo
function itself as the listener function instead of using a separate handleClick
function that calls changeTo
— you would just need to move handleClick
‘s logic, including retrieving the number
, to inside of changeTo
.)
The code is shortened a bit further by putting the data arrays (newConfirmedCases
, etc.) into an array of arrays, which parallels the barChart.data.datasets
array of .data
objects — this lets us copy (the desired part of) each data array into the corresponding .data
object within a loop, according to its index (i
) in datasets
.
See the in-code comments for further clarifications. And look up anything you want to know more about on MDN (eg "data attributes", "arrow functions", "event listeners", or "foreach").
const
// Simulates your barChart object for initial display
barChart = getBarChart();
// Simulates your data arrays
newConfirmedCases = [11, 22, 33, 44, 55],
newConfirmedRecovered = [ 5, 10, 15, 20, 25],
newConfirmedDeaths = [ 1, 2, 3, 4, 5],
formattedDates = ["1/1/21", "1/2/21", "1/3/21", "1/4/21", "1/5/21"],
// Identifies relevant DOM elements
buttonContainer = document.getElementById("buttonContainer");
// Calls handler func when anything in buttonContainer is clicked
buttonContainer.addEventListener("click", handleClick);
// Triggers initial display of all data
changeTo("Infinity");
// Defines listener function
function handleClick(event){ // Listener knows about triggering event
const clickedThing = event.target; // Event has useful properties
if(clickedThing.tagName != "BUTTON"){ return; } // Ignores irrelevant clicks
// Gets number from custom attribute; passes it to `changeTo`
changeTo(clickedThing.getAttribute("data-number"));
}
// Defines the function that does the heavy lifting
function changeTo(howMany) {
// - Takes a number (including JS's global "infinity")
// - Updates barChart object, then updates display
const
// Simulates barChart object for local use
barChart = getBarChart(),
// Makes a `datasets` matrix (an array of arrays)
datasets = [newConfirmedCases, newConfirmedRecovered, newConfirmedDeaths];
// Applies an anonymous function to each array in matrix
datasets.forEach( (dataset, i) => {
const whereToSliceData = Math.max(dataset.length - howMany, 0);
// Left side is the corresponding array from inside `barChart`
// Right side is a slice of the current array from matrix
barChart.data.datasets[i].data = dataset.slice(whereToSliceData);
});
// A similar process sets barChart's labels
const whereToSliceDates = Math.max(formattedDates.length - howMany, 0);
barChart.data.labels = formattedDates.slice(whereToSliceDates);
// Finally, calls `.update` method to change the display
barChart.update();
}
// Mostly ignore this, just simulates your barChart obj (poorly)
function getBarChart(){
const barChart = {
data: {
datasets: [{},{},{}],
labels: []
},
update: function(){
const display = document.getElementById("display");
display.innerHTML = "";
for (let dataset of this.data.datasets){
for (let datum of dataset.data){
const spaces = 8 - datum.toString().length;
display.innerHTML += " ".repeat(spaces) + datum;
}
display.innerHTML += "<br/>";
}
display.innerHTML += "<br/>" + " ".repeat(3);
for (let label of this.data.labels){
display.innerHTML += " ".repeat(2) + label;
}
}
}
return barChart;
}
#display{ font-family: monospace; }
<div id="buttonContainer">
<button data-number="Infinity">Default</button>
<button data-number="2">Last Two</button>
<button data-number="3">Last Three</button>
<button data-number="4">Last Four</button>
</div>
<hr/>
<div id="display"></div>
3👍
You could implement a solution that both cleans up and adds flexibility to your code, which is to create a single changeTo()
function, taking as argument the number of days you would like to slice your newConfirmed...
array.
Additionally, you could use a map to save the index of datasets
as key and the corresponding newConfirmed...
array as value.
Eventually, add the eventListeners
by calling the changeTo()
function for the amount of days you require.
//Key of map is dataset index, value is newConfirmed array
let map = new Map();
map.set(0, newConfirmedCases);
map.set(1, newComfirmedRecovered);
map.set(2, newConfirmedDeaths);
//This operation is done multiple times in your code, let's make it a function
function slicer(val, number) {
return val.slice(Math.max(val.length - number, 0));
}
function changeTo(number = 0) {
//Iterate through map and set data
//If number is 0, whole array is returned, else the sliced array
for (const [key, val] of map.entries())
barChart.data.datasets[key].data = (number) ? slicer(val, number) : val;
barChart.data.labels = (number) ? slicer(formattedDates, number) : formattedDates;
barChart.update()
}
//Set eventListeners by calling changeTo() for the required amount of days
//Remember that if you give no argument, it will act like former changeToBeginning
document.getElementById("defaultState").addEventListener("click", changeTo());
document.getElementById("lastSeven").addEventListener("click", changeTo(7));
document.getElementById("lastThirty").addEventListener("click", changeTo(30));
document.getElementById("lastNinety").addEventListener("click", changeTo(90));
0👍
function updateUI() {
updateStats();
chartDrawing();
}
barChart = new Chart(chartTwo, {
type: "bar",
data: {
datasets: [{
label: "Nowych Zarażeń",
data: newConfirmedCases,
fill: false,
borderColor: "gray",
backgroundColor: "crimson",
borderWidth: 1,
},
{
label: "Nowych Ozdrowień",
data: newConfirmedRecovered,
fill: false,
borderColor: "gold",
backgroundColor: "green",
borderWidth: 1,
},
{
label: "Nowych Zgonów",
data: newConfirmedDeaths,
fill: false,
borderColor: "brown",
backgroundColor: "coral",
borderWidth: 1,
},
],
labels: formatedDates,
},
options: {
responsive: true,
maintainAspectRatio: false,
}
})
The rest of a code, unfortunately i am getting "undefined" of barChart.data.
The chartDrawing function have all the code in itself.