summaryrefslogtreecommitdiff
path: root/src/components/Map.tsx
blob: 070dc5ceeeb1801caa4fedd1c763d5c116cc8f07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import React, { useState, useEffect, useRef } from "react";
import mapboxgl from 'mapbox-gl';

import {
  MAPBOX_ACCESS_TOKEN,
  IMAGE_COORDINATES,
  IMAGES_BASE_URL
} from "../config";

import "mapbox-gl/dist/mapbox-gl.css";

interface MapProps {
  slider: number;
  images: string[];
}

export function Map({ slider, images }: MapProps) {
  const mapContainer = useRef<HTMLDivElement>(null);
  const map = useRef<mapboxgl.Map | null>(null);

  const [lng] = useState(35);
  const [lat] = useState(31.9);
  const [zoom] = useState(6.3);
  const [loaded, setLoaded] = useState(false);

  const prevImages = useRef(images).current;

  useEffect(() => {
    if (map.current || !mapContainer.current) return;

    map.current = new mapboxgl.Map({
      accessToken: MAPBOX_ACCESS_TOKEN,
      container: mapContainer.current,
      style: "mapbox://styles/mapbox/dark-v9",
      center: [lng, lat],
      zoom: zoom,
      minZoom: 5,
      maxZoom: 10,
      hash: false,
    });

    map.current.on("style.load", () => {
      setLoaded(true);
    });
  }, [lng, lat, zoom]);

  useEffect(() => {
    if (!loaded || !map.current) return;

    // remove old layers
    prevImages.forEach((img) => {
      if (!images.includes(img)) {
        if (map.current?.getLayer(`layer-${img}`)) {
          map.current.removeLayer(`layer-${img}`);
        }
        if (map.current?.getSource(`source-${img}`)) {
          map.current.removeSource(`source-${img}`);
        }
      }
    });

    // add new layers
    images.forEach((img, i) => {
      if (!prevImages.includes(img) && !map.current?.getSource(`source-${img}`)) {
        map.current?.addSource(`source-${img}`, {
          type: "image",
          url: `${IMAGES_BASE_URL}/${img}`,
          coordinates: IMAGE_COORDINATES
        });
        map.current?.addLayer({
          id: `layer-${img}`,
          source: `source-${img}`,
          type: "raster",
          paint: {
            "raster-opacity": 0,
            "raster-opacity-transition": {
              duration: 0
            }
          }
        });
      }
    });
  }, [loaded, prevImages, images]);

  useEffect(() => {
    if (!loaded || !images.length || !map.current) return;

    if (images[slider]) {
      map.current.setPaintProperty(`layer-${images[slider]}`, "raster-opacity", 0.85);
    }

    return () => {
      // callback will hide the previous layer with the previous slider value
      if (images[slider] && map.current?.getLayer(`layer-${images[slider]}`)) {
        map.current.setPaintProperty(`layer-${images[slider]}`, "raster-opacity", 0);
      }
    };
  }, [loaded, slider, images]);

  return (
    <div>
      <div ref={mapContainer} className="map-container h-screen w-screen" />
    </div>
  );
}