1👍
✅
You can render you entire object rounds
as JSON within a thymeleaf inline <script>
tag
<script th:inline="javascript">
let rounds = /*[[${rounds}]]*/ {};
</script>
So as per my codepen, the code remains the same
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.2.1/dist/chart.umd.min.js"></script>
</head>
<body>
<div>
<canvas id="myChart" width="600" height="250" ></canvas>
</div>
<script th:inline="javascript">
var datasets = [];
var label = [];
var rounds = /*[[${roundsJson}]]*/ {};
console.log(rounds);
var i = 0;
for(var prop in rounds) {
var dataset = []
for(var j=0;j<rounds[prop][0].scores.length;j++) {
dataset.push(rounds[prop][0].scores[j].score)
}
console.log(dataset)
const counts = {};
for (const num of dataset) {
counts[num] = counts[num] ? counts[num] + 1 : 1;
}
console.log(counts)
label.push("Score Round " + (i+1))
i++;
datasets.push(counts)
}
console.log(datasets)
var newdatasets = [];
var keys = Object.keys(datasets[0])
for(var j=0;j<keys.length;j++) {
newdatasets.push({
data: [],
key: keys[j],
label: "Score " + keys[j]
});
}
for(var i=0;i<newdatasets.length;i++) {
for(j=0;j<datasets.length;j++) {
console.log(datasets[j][newdatasets[i].key]);
newdatasets[i].data.push(datasets[j][newdatasets[i].key])
}
}
console.log(newdatasets)
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: label,
datasets: newdatasets
},
options: {
responsive: true,
maintainAspectRatio: false,
indexAxis: 'y',
scales: {
x: {
stacked: true,
display: false
},
y: {
stacked: true,
display: false
}
},
plugins: {
legend: {
display: false
}
},
}
});
</script>
</body>
</html>
modify the for loop and change the chart as per your needs
Regarding your class structure please use this code
To convert your class structure to plain JSON
try {
ObjectMapper mapper = new ObjectMapper();
Map<Course, List<Round>> mapRoundsByCourse = rounds.stream().collect(Collectors.groupingBy(Round::getCourse));
JsonNode jsonNode = mapper.valueToTree(mapRoundsByCourse);
model.addAttribute("roundsJson", jsonNode);
} catch (IOException e) {
Then change your <script>
to
<script th:inline="javascript">
let rounds = /*[[${roundsJson}]]*/ {};
</script>
0👍
So for anyone else having the same issue to create a chart in a thymeleaf loop with an accordion. I pass a list of rounds to the javascript, then in the loop pass the roundId. Then create a loop with the roundId’s with a chart inside and get the round if using the getRoundId method. Check above for data and more info.
Html
<th:block th:each="round : ${roundCourse.rounds}">
...
<div class="container-fluid">
<canvas th:roundId="${round.barChartArray}" th:id="'myChart-' + ${round.roundId}"></canvas>
</div>
</th:block>
...
<script th:inline="javascript">
let rounds = /*[[${roundsJsonNode}]]*/ {};
</script>
javascript
function getRoundById(rounds, roundId) {
return rounds.find((round) => round.roundId === Number(roundId));
}
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.maxHeight) {
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + "px";
}
});
}
const charts = document.querySelectorAll('[roundId]');
charts.forEach(chart => {
const getRound = chart.getAttribute('roundId').split(',');
const roundData = getRoundById(rounds, getRound);
const scoreCount = roundData.scores.length;
const scoreData = {};
for (let i = 0; i < scoreCount; i++) {
const score = roundData.scores[i];
if (!scoreData[score.name]) {
scoreData[score.name] = {
count: 0,
color: score.color,
score: score.score,
};
}
scoreData[score.name].count += 1;
}
const datasets = [];
Object.entries(scoreData).forEach(([name, data]) => {
datasets.push({
label: name,
backgroundColor: data.color,
data: [data.count],
score: data.score, // add score value to dataset object
});
});
datasets.sort((a, b) => a.score - b.score); // sort datasets by score value
const myChart = new Chart(chart, {
type: 'bar',
options: {
responsive: true,
maintainAspectRatio: false,
indexAxis: 'y',
scales: {
x: {
stacked: true,
display: false,
},
y: {
stacked: true,
display: false,
},
},
plugins: {
legend: {
display: false,
},
},
},
data: {
labels: [''],
datasets,
},
});
});
Source:stackexchange.com