Public
Edited
Jun 3, 2024
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
ungroupedData = ["A", "B", "C", "D", "E", "F", "G", "H"];
Insert cell
groupedData = groupData;
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function convertData(data){
const result = [];
data.forEach(d => {
const o = {groupScore: null, groupTotalScore:null, tasks:[], members:d.map(_d => {return {name:_d, contribution:50, score: null}})};
result.push(o);
});
return result;
}
Insert cell
assignmentData = convertData(groupData)
Insert cell
function taskInput(data){
const _data = JSON.parse(JSON.stringify(data));
let taskNameInput = html`<input type="text" placeholder="Enter task name" style="width: 500px">`;
let taskScoreInput = html`<input type="number" placeholder="Total Score" style="width: 100px">`;
let addButton = html`<button>Add</button>`;
addButton.onclick = () => {
let taskName = taskNameInput.value;
let taskScore = parseInt(taskScoreInput.value);
if (taskName && !isNaN(taskScore)) {
const task = {taskName: taskName, taskTotalScore: taskScore, taskScore: null};
_data.forEach(d => {
const newTasks = d.tasks;
d.groupTotalScore += taskScore;
newTasks.push(task);
});
target.value = _data;
target.dispatchEvent(new CustomEvent("input", { bubbles: true }));
} else {
throw new Error("Please enter valid task name and score scale.");
}
};

const target = htl.html`Add a task: ${taskNameInput} ${taskScoreInput} ${addButton}`;
target.value = _data;
return target;
}
Insert cell
obj = htl.html`<div>Data is empty or null!</div>`;
Insert cell
obj
Insert cell
function generateGradebook(data) {
if (!data || data.length === 0) {
return htl.html`<div>Data is empty or null!</div>`;
}

const _data = JSON.parse(JSON.stringify(data));

const gradeSlider = (max, value, task, index) => {
const slider = Inputs.range([0, max], {
step: 1,
value: value,
width: 50
});
slider.oninput = () => {
task.taskScore = parseInt(slider.value);
updateScore(index);
};
return slider;
};

const gradeButton = (task, index) => {
const slider = gradeSlider(task.taskTotalScore, 0, task, index);
slider.style.display = "none";
const button = htl.html`<button>Not graded yet</button>`;
button.onclick = () => {
slider.style.display = "inline-block";
button.style.display = "none";
task.taskScore = 0;
updateScore(index);
};
return htl.html`${button}${slider}`;
};

const updateScore = (index) => {
const total = document.querySelector(`.total-score.group${index}`);
const score = sumScore(_data[index].tasks);
const totalScore = sumTotalScore(_data[index].tasks);
total.innerText = `Group ${index+1} total score: ${score}/${totalScore}`
_data[index].groupScore = score;
_data[index].groupTotalScore = totalScore;
result.value = _data;
result.dispatchEvent(new CustomEvent("input", { bubbles: true }));
};

const tableRows = (tasks, index) => {
if (!tasks || tasks.length === 0) {
return "";
}
return tasks.map((task) => {
return html`
<tr>
<td>${task.taskName}</td>
<td>
${
task.taskScore
? gradeSlider(task.taskTotalScore, task.taskScore, task, index)
: gradeButton(task, index)
}
</td>
<td>${task.taskTotalScore}</td>
</tr>
`;
});
};
const sumScore = (tasks) => {
let sum = 0;
tasks.forEach((task) => {
sum += task.taskScore;
});
return sum;
};
const sumTotalScore = (tasks) => {
let sum = 0;
tasks.forEach((task) => {
sum += task.taskTotalScore;
});
return sum;
};

const groupView = (tasks, index) => {
return htl.html`
<table>
<thead>
<tr>
<th>Task Name</th>
<th>Score</th>
<th>Total Score</th>
</tr>
</thead>
<tbody>
${tableRows(tasks, index)}
</tbody>
</table>
<div class="total-score group${index}">
Group ${index+1} total score: ${sumScore(tasks)}/${sumTotalScore(tasks)}
</div>
`;
};

const groupTabs = _data.map((group, index) => {
return details(`Group${index + 1}`, groupView(group.tasks, index));
});

const result = tabbed(htl.html`${groupTabs}`, { selected: 0 });
result.value = _data;
return result;
}
Insert cell
function generateIndividuleScore(data) {
if (!data || data.length === 0) {
return htl.html`<div>Data is empty or null!</div>`;
}

const _data = JSON.parse(JSON.stringify(data));

const slider = (group, index, m) => {
const s = Inputs.range([0, 100], {
step: 1,
value: 50,
width: 200
});
s.oninput = () => {
m.contribution = s.value;
computeIndividuleScore(group, index);
updateIndividuleScore(group, index);
};
return s;
};

const tableRows = (group, index) => {
if (!group || group.length === 0) {
return "";
}
return group.members.map((m, i) => {
return html`
<tr>
<td>${m.name}</td>
<td>${slider(group, index, m)}</td>
<td class="score group${index} member${i}">${m.score}</td>
<td>${_data[index].groupScore}</td>
<td>${_data[index].groupTotalScore}</td>
</tr>
`;
});
};

const computeIndividuleScore = (group, index) => {
const groupScore = _data[index].groupScore;
const contributionSet = [];
group.members.map((m, i) => {
contributionSet.push(m.contribution);
});
const socrePercentage = computeGroupContribution(contributionSet);
console.log(socrePercentage);
group.members.forEach((m, i) => {
let score = socrePercentage[i] * group.members.length * group.groupScore;
if (score > groupScore) {
score = groupScore;
}
m.score = score;
});
};

const updateIndividuleScore = (group, index) => {
group.members.forEach((m, i) => {
const el = document.querySelector(`.score.group${index}.member${i}`);
el.innerText = group.members[i].score.toFixed(2);
});
};

const groupView = (group, index) => {
return htl.html`
<table>
<thead>
<tr>
<th>Name</th>
<th>Contribution</th>
<th>Individule Score</th>
<th>Group Score</th>
<th>Total Score</th>
</tr>
</thead>
<tbody>
${tableRows(group, index)}
</tbody>
</table>
`;
};
const groupTabs = _data.map((group, index) => {
computeIndividuleScore(group, index);
return details(`Group${index + 1}`, groupView(group, index));
});
const result = tabbed(htl.html`${groupTabs}`, { selected: 0 });
result.value = _data;
return result;
}
Insert cell
csvResult = convert2CSV(individuleScore);
Insert cell
target = new Blob([d3.csvFormat(csvResult)], {type: "text/csv"})
Insert cell
function convert2CSV(data){
const result = [];
data.forEach(d => {
const obj = {name: "", induvidule: 0, group:0, total:0};
d.members.forEach(m => {
const obj = {name: m.name, induvidule: m.score, group: d.groupScore, total: d.groupTotalScore};
result.push(obj);
});
});
return result;
}
Insert cell
Insert cell
Insert cell
Insert cell
require("d3")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more