MIF_E31221222/sigap-website/app/_components/map/overlay.tsx

96 lines
2.6 KiB
TypeScript

import { IControl, Map } from "mapbox-gl";
import { ControlPosition } from "mapbox-gl";
import { cloneElement, memo, ReactElement, useEffect, useState } from "react";
import { createPortal } from "react-dom";
import { useControl } from "react-map-gl/mapbox";
import { v4 as uuidv4 } from 'uuid';
type OverlayProps = {
position: ControlPosition;
children: ReactElement<{ map?: Map }>;
id?: string;
};
// Definisikan custom control untuk overlay
class OverlayControl implements IControl {
_map: Map | null = null;
_container: HTMLElement | null = null;
_position: ControlPosition;
_id: string;
_redraw?: () => void;
constructor({ position, id, redraw }: { position: ControlPosition; id: string; redraw?: () => void }) {
this._position = position;
this._id = id;
this._redraw = redraw;
}
onAdd(map: Map) {
this._map = map;
this._container = document.createElement('div');
this._container.className = 'mapboxgl-ctrl mapboxgl-ctrl-group';
this._container.id = this._id;
if (this._redraw) {
map.on('move', this._redraw);
this._redraw();
}
return this._container;
}
onRemove() {
if (!this._map || !this._container) return;
if (this._redraw) {
this._map.off('move', this._redraw);
}
this._container.remove();
this._map = null;
}
getDefaultPosition() {
return this._position;
}
getMap() {
return this._map;
}
getElement() {
return this._container;
}
}
// Komponen Overlay yang telah ditingkatkan
function _Overlay({ position, children, id = `overlay-${uuidv4()}` }: OverlayProps) {
const [container, setContainer] = useState<HTMLElement | null>(null);
const [map, setMap] = useState<Map | null>(null)
// Gunakan useControl dengan ID unik untuk menghindari konflik
const ctrl = useControl<OverlayControl>(
() => new OverlayControl({ position, id }),
{ position } // Hanya menggunakan position yang valid dalam ControlOptions
);
// Update container dan map instance ketika control siap
useEffect(() => {
if (ctrl) {
setContainer(ctrl.getElement());
setMap(ctrl.getMap());
}
}, [ctrl]);
// Hanya render jika container sudah siap
if (!container || !map) return null;
// Gunakan createPortal untuk merender children ke container
return createPortal(
cloneElement(children, { map }),
container
);
}
// Export sebagai komponen memoized
export const Overlay = memo(_Overlay);