I created a world map for learning in a .svg file and wanted to use the panzoom library to enable zooming. However, I encountered a problem that I can’t seem to resolve.
I created a simple game where you need to click on the correct country or island. Some of them are very small, so zooming or panning the map is necessary. The issue arises because when panning the map by clicking and holding the mouse button, releasing the button triggers a click event on the country, which is recognized as an attempt by the player.
Do you have any suggestions on how to prevent this click after releasing while panning the map?
// Tooltip
const tooltip = document.getElementById('tooltip');
const svgContainer = document.getElementById('panzoom-container');
// Add hover and tooltip only to selected elements
idsToHighlight.forEach(id => {
const element = document.getElementById(id);
if (element) {
// Add hover
element.addEventListener('click', (event) => {
element.classList.add('region-hover');
const title = element.getAttribute('title') || 'No title';
tooltip.textContent = title;
tooltip.style.opacity = '1';
});
// Remove hover
element.addEventListener('mouseleave', () => {
element.classList.remove('region-hover');
tooltip.style.opacity = '0';
});
// Update tooltip position
element.addEventListener('mousemove', (event) => {
const bounds = svgContainer.getBoundingClientRect();
tooltip.style.left = `${event.clientX - bounds.left + 10}px`;
tooltip.style.top = `${event.clientY - bounds.top + 10}px`;
});
}
});
// Panzoom Initialization with zoom limits
const svgMap = document.getElementById('svg1');
const panzoom = Panzoom(svgMap, {
contain: 'outside',
minScale: 0.5, // Minimum zoom level
maxScale: 300 // Maximum zoom level
});
svgContainer.addEventListener('wheel', panzoom.zoomWithWheel);
// Button controls
document.getElementById('zoom-in').addEventListener('click', () => panzoom.zoomIn());
document.getElementById('zoom-out').addEventListener('click', () => panzoom.zoomOut());
document.getElementById('reset').addEventListener('click', () => panzoom.reset());
// Global attempts
const correctAnswers = [];
const incorrectAnswers = [];
const attempts = {};
let numberOfSelectedCountries = 0;
// Function to initialize map interactions
function initMapInteraction() {
// Initialize number of selected countries
numberOfSelectedCountries = 1;
document.getElementById('liczba_wylosowanych_krajow').innerText = `${numberOfSelectedCountries}`;
// Select random country
currentTarget = idsToHighlight[Math.floor(Math.random() * idsToHighlight.length)];
document.getElementById('losowy_kraj').innerText = "Choose country: " + document.getElementById(currentTarget).getAttribute('title'); // Display the selected country
console.log(`Current target: ${currentTarget}`);
// Add click listeners for each country
idsToHighlight.forEach((id) => {
const element = document.getElementById(id);
if (element) {
attempts[id] = 0; // Initialize attempt count
element.addEventListener("click", () => {
console.log(`Clicked on country: ${id}`);
if (id === currentTarget) {
// Mark correct answer
if (attempts[currentTarget] >= 2) {
// If there were more than 2 attempts, remove flashing and mark in red
element.classList.remove('migajacy');
element.style.fill = "red";
incorrectAnswers.push(currentTarget);
console.log(`Added to incorrect answers: ${currentTarget}`);
let incorrectCount = incorrectAnswers.length;
document.getElementById('bledne_kraje').innerText = "incorrect: " + incorrectCount;
} else if (attempts[currentTarget] === 1) {
// On the second attempt
element.style.fill = "orange"; // Orange mark
incorrectAnswers.push(currentTarget);
console.log(`Added to incorrect answers: ${currentTarget}`);
let incorrectCount = incorrectAnswers.length;
document.getElementById('bledne_kraje').innerText = "incorrect: " + incorrectCount;
} else {
// On the first attempt
element.style.fill = "white"; // White mark
correctAnswers.push(currentTarget);
console.log(`Added to correct answers: ${currentTarget}`);
let correctCount = correctAnswers.length;
document.getElementById('Poprawne_kraje').innerText = "Correct: " + correctCount;
}
element.style.pointerEvents = "none"; // Disable clicks
correctAnswers.push(currentTarget);
console.log(`Country ${id} marked as correct.`);
numberOfSelectedCountries++; // Increase selected countries count
document.getElementById('liczba_wylosowanych_krajow').innerText = `${numberOfSelectedCountries}`;
// Check if there are still countries to choose
const remaining = idsToHighlight.filter(
(country) => !correctAnswers.includes(country) && !incorrectAnswers.includes(country)
);
if (remaining.length > 0) {
currentTarget = remaining[Math.floor(Math.random() * remaining.length)];
document.getElementById('losowy_kraj').innerText = document.getElementById(currentTarget).getAttribute('title'); // Update the selected country
attempts[currentTarget] = 0; // Reset attempts for new country
} else {
console.log("Game finished. All countries marked correctly.");
alert("All countries have been marked correctly!");
}
} else {
// Handle incorrect selection
attempts[currentTarget]++; // Increase attempts globally
console.log(`Attempts for ${currentTarget}: ${attempts[currentTarget]}`);
if (attempts[currentTarget] === 2) {
// After 2 attempts, add flashing
document.getElementById(currentTarget).classList.add('migajacy');
}
}
});
} else {
console.error(`Element with id ${id} does not exist.`);
}
});
}
// CSS for flashing effect
const style = document.createElement('style');
style.textContent = `
@keyframes blink-red {
0%, 100% { fill: red; }
50% { fill: white; }
}
.migajacy {
animation: blink-red 1s infinite;
}
`;
document.head.appendChild(style);
// Initialize interactions after DOM is loaded
window.addEventListener("DOMContentLoaded", initMapInteraction);
const occurrences = [];
function checkIdOccurrences() {
const allElements = document.querySelectorAll('[id]');
const idCounts = {};
allElements.forEach((element) => {
const id = element.id.toUpperCase(); // Use uppercase for consistency
if (idsToHighlight.includes(id)) {
if (idCounts[id]) {
idCounts[id]++;
} else {
idCounts[id] = 1;
}
}
});
// Find the div with id `wszystkie_kraje`
const allCountriesDiv = document.getElementById('wszystkie_kraje');
if (allCountriesDiv) {
allCountriesDiv.innerHTML = `${Object.keys(idCounts).length} `;
}
}
// Call the function after DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
checkIdOccurrences();
});