SG_P2_Math_Volume_1 / index.html
saurabh2086's picture
First Commit
d459d14 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Volume Quiz</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
font-family: 'Inter', sans-serif;
background-color: #f0f9ff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center; /* Vertically centers the content */
min-height: 100vh;
margin: 0;
padding: 2rem 1rem; /* Added padding for spacing */
box-sizing: border-box;
}
#main-container {
display: flex;
justify-content: center;
align-items: flex-end;
gap: 2rem;
margin-top: 2rem;
width: 100%;
max-width: 600px;
flex-wrap: wrap;
}
.beaker-container {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
cursor: pointer;
padding: 1rem;
border-radius: 20px;
border: 4px solid transparent;
transition: all 0.3s ease;
position: relative;
}
.beaker-container.selected {
border-color: #4f46e5;
background-color: #eef2ff;
}
.beaker-container.correct {
border-color: #22c55e;
background-color: #f0fdf4;
}
.beaker-container.incorrect {
border-color: #ef4444;
background-color: #fef2f2;
}
.order-number {
position: absolute;
top: -10px;
right: -10px;
background-color: #4f46e5;
color: white;
width: 30px;
height: 30px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1rem;
border: 2px solid white;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
.beaker {
width: 120px;
height: 240px;
border: 8px solid #9ca3af;
border-top: none;
border-radius: 0 0 20px 20px;
background-color: rgba(255, 255, 255, 0.5);
position: relative;
overflow: hidden;
}
.water {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
background-color: #3b82f6;
transition: height 1s ease-in-out;
}
.beaker-label {
margin-top: 1rem;
font-size: 1.8rem;
color: #1e3a8a;
}
#feedback {
height: 3rem;
font-size: 1.5rem;
margin-top: 1rem;
}
.hidden {
display: none;
}
#order-answer-panel {
margin-top: 1.5rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
.answer-slots {
display: flex;
gap: 1rem;
}
.slot {
width: 50px;
height: 50px;
border: 2px dashed #9ca3af;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
font-weight: bold;
color: #374151;
background-color: #f9fafb;
}
</style>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
</head>
<body class="bg-blue-50">
<div id="ui-panel" class="text-center p-4 bg-white rounded-xl shadow-lg w-full max-w-3xl">
<h1 id="question-text" class="text-3xl text-blue-700"></h1>
<p id="instruction-text" class="text-gray-600 mt-2 max-w-prose mx-auto"></p>
<p id="feedback" class=""></p>
<div id="order-answer-panel" class="hidden">
<p class="text-gray-600">Your Answer:</p>
<div id="answer-slots" class="answer-slots"></div>
</div>
</div>
<div id="main-container"></div>
<div id="button-container" class="mt-6 flex flex-wrap justify-center gap-4">
<button id="submit-button" class="bg-indigo-600 text-white py-3 px-8 rounded-lg shadow-md hover:bg-indigo-700 transition-transform transform hover:scale-105">
Submit
</button>
<button id="reset-selection-button" class="bg-gray-500 text-white py-3 px-8 rounded-lg shadow-md hover:bg-gray-600 transition-transform transform hover:scale-105 hidden">
Reset Selection
</button>
<button id="new-question-button" class="bg-green-600 text-white py-3 px-8 rounded-lg shadow-md hover:bg-green-700 transition-transform transform hover:scale-105 hidden">
New Question
</button>
</div>
<script>
// --- State ---
let currentQuestion = {};
let selectedAnswer = null;
let selectedOrder = [];
let answered = false;
let questionMode = 'compare'; // 'compare' or 'order'
// --- Elements ---
const questionTextEl = document.getElementById('question-text');
const instructionTextEl = document.getElementById('instruction-text');
const mainContainer = document.getElementById('main-container');
const feedbackEl = document.getElementById('feedback');
const submitButton = document.getElementById('submit-button');
const newQuestionButton = document.getElementById('new-question-button');
const resetSelectionButton = document.getElementById('reset-selection-button');
const orderAnswerPanel = document.getElementById('order-answer-panel');
const answerSlotsContainer = document.getElementById('answer-slots');
// --- Logic ---
function generateUniqueVolumes(count, min, max, step) {
const volumes = new Set();
while (volumes.size < count) {
const volume = Math.floor(Math.random() * ((max - min) / step + 1) + min / step) * step;
volumes.add(volume);
}
return Array.from(volumes);
}
function generateAndLoadQuestion() {
// 1. Reset State
answered = false;
selectedAnswer = null;
selectedOrder = [];
mainContainer.innerHTML = '';
feedbackEl.textContent = '';
feedbackEl.className = '';
orderAnswerPanel.classList.add('hidden');
// 2. Configure Buttons
submitButton.classList.remove('hidden');
newQuestionButton.classList.add('hidden');
resetSelectionButton.classList.add('hidden');
// 3. Decide question type
questionMode = Math.random() < 0.5 ? 'compare' : 'order';
if (questionMode === 'compare') {
generateCompareQuestion();
} else {
generateOrderQuestion();
}
}
function generateCompareQuestion() {
instructionTextEl.textContent = "Click to select a container, then press Submit.";
const [volume1, volume2] = generateUniqueVolumes(2, 50, 450, 5);
const questionType = Math.random() < 0.5 ? 'smaller' : 'greatest';
const correctAnswer = (questionType === 'smaller' ? (volume1 < volume2 ? 'A' : 'B') : (volume1 > volume2 ? 'A' : 'B'));
currentQuestion = {
question: `Container <span class="text-gray-400">___</span> has the ${questionType} volume of water.`,
containers: [{ name: 'A', volume: volume1 }, { name: 'B', volume: volume2 }],
correctAnswer: correctAnswer,
maxVolume: 500
};
renderBeakers();
}
function generateOrderQuestion() {
instructionTextEl.textContent = "Click the containers in the correct order.";
resetSelectionButton.classList.remove('hidden');
const volumes = generateUniqueVolumes(3, 50, 450, 5);
const containers = [
{ name: 'A', volume: volumes[0] },
{ name: 'B', volume: volumes[1] },
{ name: 'C', volume: volumes[2] },
];
const orderType = Math.random() < 0.5 ? 'ascending' : 'descending'; // smallest to greatest OR greatest to smallest
const sortedContainers = [...containers].sort((a, b) => orderType === 'ascending' ? a.volume - b.volume : b.volume - a.volume);
currentQuestion = {
question: `Arrange the containers in ${orderType} order of volume.`,
containers: containers,
correctAnswer: sortedContainers.map(c => c.name),
maxVolume: 500
};
renderBeakers();
renderAnswerSlots();
}
function renderBeakers() {
questionTextEl.innerHTML = currentQuestion.question;
currentQuestion.containers.forEach(containerData => {
const containerEl = document.createElement('div');
containerEl.className = 'beaker-container';
containerEl.dataset.name = containerData.name;
containerEl.innerHTML = `
<div class="beaker"><div class="water" style="height: 0%;"></div></div>
<p class="beaker-label">${containerData.name}</p>
`;
mainContainer.appendChild(containerEl);
setTimeout(() => {
const waterEl = containerEl.querySelector('.water');
const percentage = (containerData.volume / currentQuestion.maxVolume) * 100;
waterEl.style.height = `${percentage}%`;
}, 100);
containerEl.addEventListener('click', () => handleSelection(containerEl));
});
}
function renderAnswerSlots() {
orderAnswerPanel.classList.remove('hidden');
answerSlotsContainer.innerHTML = '';
for (let i = 0; i < currentQuestion.containers.length; i++) {
const slot = document.createElement('div');
slot.className = 'slot';
slot.textContent = selectedOrder[i] || '';
answerSlotsContainer.appendChild(slot);
}
}
function handleSelection(selectedContainerEl) {
if (answered) return;
const name = selectedContainerEl.dataset.name;
if (questionMode === 'compare') {
document.querySelectorAll('.beaker-container').forEach(el => el.classList.remove('selected'));
selectedContainerEl.classList.add('selected');
selectedAnswer = name;
} else { // Order mode
if (selectedOrder.includes(name)) return; // Already selected
if (selectedOrder.length < currentQuestion.containers.length) {
selectedOrder.push(name);
selectedContainerEl.classList.add('selected');
const orderNumberDiv = document.createElement('div');
orderNumberDiv.className = 'order-number';
orderNumberDiv.textContent = selectedOrder.length;
selectedContainerEl.appendChild(orderNumberDiv);
renderAnswerSlots();
}
}
}
function handleSubmit() {
if (answered) return;
if ((questionMode === 'compare' && !selectedAnswer) || (questionMode === 'order' && selectedOrder.length < currentQuestion.containers.length)) {
feedbackEl.textContent = "Please make a complete selection.";
feedbackEl.className = "text-yellow-600";
return;
}
answered = true;
let isCorrect = false;
if (questionMode === 'compare') {
isCorrect = selectedAnswer === currentQuestion.correctAnswer;
const selectedEl = document.querySelector(`.beaker-container[data-name="${selectedAnswer}"]`);
if (isCorrect) {
const filledText = `<span class="text-blue-800">${currentQuestion.correctAnswer}</span>`;
questionTextEl.innerHTML = currentQuestion.question.replace(/<span.*>___<\/span>/, filledText);
} else {
selectedEl.classList.add('incorrect');
const correctEl = document.querySelector(`.beaker-container[data-name="${currentQuestion.correctAnswer}"]`);
correctEl.classList.add('correct');
}
selectedEl.classList.add(isCorrect ? 'correct' : 'incorrect');
selectedEl.classList.remove('selected');
} else { // Order mode
isCorrect = JSON.stringify(selectedOrder) === JSON.stringify(currentQuestion.correctAnswer);
if (isCorrect) {
mainContainer.querySelectorAll('.beaker-container').forEach(el => el.classList.add('correct'));
} else {
feedbackEl.textContent = "Not quite. The correct order is shown on the beakers.";
feedbackEl.className = "text-red-600";
// Show correct order numbers
currentQuestion.containers.forEach(container => {
const el = document.querySelector(`.beaker-container[data-name="${container.name}"]`);
el.classList.add('incorrect');
// Remove the user's selection number before showing the correct one
const existingOrderNumber = el.querySelector('.order-number');
if (existingOrderNumber) {
existingOrderNumber.remove();
}
const correctIndex = currentQuestion.correctAnswer.indexOf(container.name);
const orderNumberDiv = document.createElement('div');
orderNumberDiv.className = 'order-number';
orderNumberDiv.style.backgroundColor = '#22c55e'; // Green
orderNumberDiv.textContent = correctIndex + 1;
el.appendChild(orderNumberDiv);
});
}
}
if(isCorrect){
feedbackEl.textContent = "Correct! Great job!";
feedbackEl.className = "text-green-600";
}
submitButton.classList.add('hidden');
resetSelectionButton.classList.add('hidden');
newQuestionButton.classList.remove('hidden');
}
function handleResetSelection() {
selectedOrder = [];
document.querySelectorAll('.beaker-container').forEach(el => {
el.classList.remove('selected');
const orderNum = el.querySelector('.order-number');
if(orderNum) orderNum.remove();
});
renderAnswerSlots();
}
// --- Event Listeners ---
submitButton.addEventListener('click', handleSubmit);
newQuestionButton.addEventListener('click', generateAndLoadQuestion);
resetSelectionButton.addEventListener('click', handleResetSelection)
window.onload = generateAndLoadQuestion;
</script>
</body>
</html>