I'm working on a map component and I'm running into a strange issue with about a 2s delay when first clicking the zoom button. I'm trying to use scale() to reduce recalculating pin locations on zoom. I've tried reducing the map image size, adjusting the width of the mapBox instead of scale(), scaling the image itself. All result in a delay. However after the first click of zoom in, there's no delay on zoomIn or zoomOut.
I can see the code instantly update in devTools, and if I edit the css in dev tools their is no delay, so I don't think my image size is causing the delay. Removing the pin's reduces the delay slightly but still there.
What am I missing?
import React, { useState, useEffect, useRef, use } from 'react';
import maps from '../data/maps.json';
import styles from './MapBox.module.css';
const MapBox = ({ name }) => {
const [viewportSize, setViewportSize] = useState({ width: 0, height: 0 });
const [mapSize, setMapSize] = useState({ width: 0, height: 0 });
const [zoom, setZoom] = useState(1);
const [position, setPosition] = useState({ x: 0, y: 0 });
const [boundaries, setBoundaries] = useState({ minX: 0, maxX: 0, minY: 0, maxY: 0 });
const [isDragging, setIsDragging] = useState(false);
const mapData = maps.find((map) => map.name === name);
const viewportRef = useRef(null);
function consolLog() {
console.log(Object.values(viewportSize));
console.log(zoom);
};
const handleZoomIn = () => {
setZoom((prevZoom) => Math.min(prevZoom + 1, 10));
console.log('Zoom In');
};
const handleZoomOut = () => {
setZoom((prevZoom) => Math.max(prevZoom - 1, 1));
console.log('Zoom Out');
};
//Handle Map mouse interactivity
useEffect(() => {
const mapViewport = document.getElementById('mapBoxViewport');
const handleMouseDown = () => {
setIsDragging(true);
console.log('Mouse Down');
};
const handleMouseUp = () => {
setIsDragging(false);
};
const handleMouseMove = (event) => {
console.log('Mouse Move');
};
const handleMouseLeave = () => {
setIsDragging(false);
console.log('Mouse Leave');
};
if (!isDragging) {
mapViewport.addEventListener('mousedown', handleMouseDown);
} else {
mapViewport.removeEventListener('mousedown', handleMouseDown);
mapViewport.addEventListener('mouseup', handleMouseUp);
mapViewport.addEventListener('mousemove', handleMouseMove);
mapViewport.addEventListener('mouseleave', handleMouseLeave);
};
return () => {
mapViewport.removeEventListener('mousedown', handleMouseDown);
mapViewport.removeEventListener('mouseup', handleMouseUp);
mapViewport.removeEventListener('mousemove', handleMouseMove);
mapViewport.removeEventListener('mouseleave', handleMouseLeave);
};
}, [isDragging]);
//Handle Map Zoom
useEffect(() => {
const map = document.getElementById('mapBoxMap');
map.style.transform = `scale(${zoom})`;
map.style.transition = 'transform 1000ms ease';
requestAnimationFrame(() => {
map.style.transform = `scale(${zoom})`;
map.style.transition = 'transform 1000ms ease';
});
}, [zoom]);
useEffect(() => {
if(!viewportRef.current) return;
const viewportObserver = new ResizeObserver(() => {
if(viewportRef.current.offsetWidth !== viewportSize.width) {
setViewportSize({
width: viewportRef.current.offsetWidth,
height: viewportRef.current.offsetHeight
});
};
});
viewportObserver.observe(viewportRef.current);
return () => viewportObserver.disconnect();
}, [viewportRef.current]);
//console.log(Object.values(viewportSize));
//console.log(zoom);
return (
<div className={styles.container}>
<div>{viewportSize.width}</div>
<div className={styles.buttons}>
<button className={styles.zoomButton} onClick={handleZoomIn}>+</button>
<button className={styles.zoomButton} onClick={handleZoomOut}>-</button>
</div>
<div id="mapBoxViewport" className={styles.viewport} ref={viewportRef}>
<div id="mapBoxMap" className={styles.contents}>
<img
src={mapData.image}
alt={`${name}`}
className={styles.mapImage}
draggable="false"
/>
{mapData.secretRooms && mapData.secretRooms.map((room, index) => (
<div
key={index}
className={styles.pin2}
style={{ left: room.x, top: room.y }}
/>
))}
</div>
</div>
</div>
);
};
export default MapBox;
useEffect
in this way. So it will take whatever original load time the app takes to originally render, to re-render.