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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more