mapwhizz
Version:
A reusable and customizable SVG map component for visualizing country-based data.
135 lines (113 loc) • 3.81 kB
JavaScript
// Start Class MapWhizz
export default class MapWhizz {
constructor(container, data) {
this.container = container;
this.data = data;
}
mount() {
console.log('MapWhizz mounted', this.container, this.data);
}
mount() {
try {
const parser = new DOMParser();
const svgDoc = parser.parseFromString(this.mapData, 'image/svg+xml');
this.svgElement = svgDoc.documentElement;
this.container.innerHTML = ''; // Clear previous content
this.container.appendChild(this.svgElement);
this.calculateValueRange();
this.addStyles();
this.applyColorsAndInteractions();
} catch (error) {
console.error('Error loading SVG:', error);
}
}
calculateValueRange() {
this.minValue = Infinity;
this.maxValue = -Infinity;
this.data.forEach(({ value }) => {
this.minValue = Math.min(this.minValue, value);
this.maxValue = Math.max(this.maxValue, value);
});
}
getColorForValue(value) {
const percentage =
(value - this.minValue) / (this.maxValue - this.minValue);
const startColor = [240, 249, 255]; // Light blue
const endColor = [24, 72, 176]; // Dark blue
const r = Math.round(
startColor[0] + percentage * (endColor[0] - startColor[0])
);
const g = Math.round(
startColor[1] + percentage * (endColor[1] - startColor[1])
);
const b = Math.round(
startColor[2] + percentage * (endColor[2] - startColor[2])
);
return `rgb(${r}, ${g}, ${b})`;
}
addStyles() {
const style = document.createElement('style');
style.textContent = `
path {
transition: all 0.3s ease;
stroke: #fff;
stroke-width: 1;
fill: #ccc;
}
path:hover {
fill: rgb(0, 0, 255) !important;
stroke-width: 2;
cursor: pointer;
}
`;
document.head.appendChild(style);
}
applyColorsAndInteractions() {
const countryDataMap = new Map(
this.data.map((item) => [item.country, item])
);
this.svgElement.querySelectorAll('path').forEach((path) => {
const country = path.getAttribute('title');
const countryData = countryDataMap.get(country);
if (countryData) {
path.style.fill = this.getColorForValue(countryData.value);
this.addHoverInteraction(path, country, countryData);
}
});
}
addHoverInteraction(path, country, countryData) {
path.addEventListener('mouseover', (event) => {
const tooltip = this.createTooltip(`${country}: ${countryData.value}`);
document.body.appendChild(tooltip);
const moveTooltip = (e) => {
tooltip.style.left = `${e.pageX + 10}px`;
tooltip.style.top = `${e.pageY + 10}px`;
};
document.addEventListener('mousemove', moveTooltip);
path.addEventListener('mouseout', () => {
tooltip.remove();
document.removeEventListener('mousemove', moveTooltip);
});
});
}
createTooltip(text) {
const tooltip = document.createElement('div');
tooltip.style.position = 'absolute';
tooltip.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
tooltip.style.color = '#fff';
tooltip.style.padding = '5px 10px';
tooltip.style.borderRadius = '4px';
tooltip.style.pointerEvents = 'none';
tooltip.style.fontSize = '12px';
tooltip.style.zIndex = '1000';
tooltip.textContent = text;
return tooltip;
}
}
// UMD Export (Works with ES6, CommonJS, and <script> tag)
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = MapWhizz;
} else {
window.MapWhizz = MapWhizz;
}
// export default MapWhizz;