MIF_E31221222/sigap-website/app/_components/map/controls/layer-control.tsx

127 lines
4.1 KiB
TypeScript

import { Checkbox } from "../../ui/checkbox";
import { Label } from "../../ui/label";
import { RadioGroup, RadioGroupItem } from "../../ui/radio-group";
import { ControlPosition, IControl, Map } from "mapbox-gl"
import { useControl } from "react-map-gl/mapbox"
import React, { useEffect } from "react"
import { createRoot } from "react-dom/client"
interface MapLayerControlProps {
position?: ControlPosition
isFullscreen?: boolean
}
// React component for layer control content
const LayerControlContent = () => {
return (
<div className="space-y-3">
<div className="text-sm font-medium">Lapisan peta</div>
<div className="flex items-center space-x-2">
<Checkbox id="sambaran-petir" />
<Label htmlFor="sambaran-petir" className="text-xs text-white">
Sambaran petir
</Label>
</div>
<div className="flex items-center space-x-2">
<Checkbox id="jalur-badai" defaultChecked />
<Label htmlFor="jalur-badai" className="text-xs text-white">
Jalur badai guntur
</Label>
</div>
<div className="mt-4">
<div className="text-sm font-medium mb-2">Waktu</div>
<RadioGroup defaultValue="4jam">
<div className="flex items-center space-x-2">
<RadioGroupItem value="4jam" id="4jam" />
<Label htmlFor="4jam" className="text-xs text-white">
4 Jam
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="10hari" id="10hari" />
<Label htmlFor="10hari" className="text-xs text-white">
10 Hari
</Label>
</div>
</RadioGroup>
</div>
</div>
)
}
class LayerControlMapboxControl implements IControl {
private container: HTMLElement;
private map?: Map;
private props: MapLayerControlProps;
private root: ReturnType<typeof createRoot> | null = null;
private isUnmounting: boolean = false;
constructor(props: MapLayerControlProps) {
this.props = props;
this.container = document.createElement("div");
this.container.className = "mapboxgl-ctrl";
}
onAdd(map: Map): HTMLElement {
this.map = map;
this.container.className = 'mapboxgl-ctrl mapboxgl-ctrl-layer absolute bottom-36 left-0 z-20 bg-black/70 text-white p-3 rounded-tr-lg';
this.render();
return this.container;
}
onRemove(): void {
if (this.isUnmounting) return;
this.isUnmounting = true;
requestAnimationFrame(() => {
if (this.root) {
this.root.unmount();
this.root = null;
}
if (this.container.parentNode) {
this.container.parentNode.removeChild(this.container);
}
this.map = undefined;
this.isUnmounting = false;
});
}
updateProps(props: MapLayerControlProps): void {
this.props = props;
this.render();
}
render(): void {
if (this.props.isFullscreen === false) {
if (this.container.style.display !== 'none') {
this.container.style.display = 'none';
}
return;
} else {
this.container.style.display = 'block';
}
if (!this.root) {
this.root = createRoot(this.container);
}
this.root.render(<LayerControlContent />);
}
}
export function MapLayerControl({ position = 'bottom-left', isFullscreen }: MapLayerControlProps) {
const control = useControl<LayerControlMapboxControl>(
() => new LayerControlMapboxControl({ position, isFullscreen }),
{ position }
);
useEffect(() => {
control.updateProps({ position, isFullscreen });
}, [control, position, isFullscreen]);
return null;
}