summaryrefslogtreecommitdiff
path: root/static/js/drawmap.js
blob: d4686ec282dfa7e7be86cf14c88b9436b42a4189 (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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
const map = new maplibregl.Map({
  style: 'https://tiles.openfreemap.org/styles/liberty',
  center: [12.55, 55.67],
  zoom: 11,
  container: 'map',
});

const cluster_max_zoom = 14;

const map_element = document.getElementById('map');

fetch('static/js/data.json')
  .then(response => response.json())
  .then(data => {
    const markersData = data;
    var ul = document.getElementById('links');

    // Convert your data to a GeoJSON format
    const geojson = {
      type: 'FeatureCollection',
      features: Object.values(markersData).map(marker => ({
        type: 'Feature',
        geometry: {
          type: 'Point',
          coordinates: [marker.lng, marker.lat], // Ensure lng and lat match your data attributes
        },
        properties: {
          image: marker.image,
          message: marker.message,
        }
      })),
    };

    // Add the GeoJSON data as a source
    map.on('load', () => {
      map.addSource('markers', {
        type: 'geojson',
        data: geojson,
        cluster: true,
        clusterMaxZoom: cluster_max_zoom, // Max zoom to cluster points on
        clusterRadius: 50, // Radius of each cluster when clustering points
      });

      // Layer for clusters
      map.addLayer({
        id: 'clusters',
        type: 'circle',
        source: 'markers',
        filter: ['has', 'point_count'],
        paint: {
          'circle-color': [
            'step',
            ['get', 'point_count'],
            '#51bbd6', // Color for circle based on count
            10,
            '#f1f075',
            30,
            '#f28cb1',
            200,
            '#a275ef',
          ],
          'circle-radius': [
            'step',
            ['get', 'point_count'],
            20,  /* Size */
            20,  /* Count */
            25,  /* Size */
            200, /* Count */
            30,  /* Size */
          ]
        }
      });

      // Layer for cluster count
      map.addLayer({
        id: 'cluster-count',
        type: 'symbol',
        source: 'markers',
        filter: ['has', 'point_count'],
        layout: {
          'text-field': '{point_count_abbreviated}',
          'text-font': ['Noto Sans Regular'],
          'text-size': 12,
        }
      });

      // Layer for individual unclustered points
      map.addLayer({
        id: 'unclustered-point',
        type: 'circle',
        source: 'markers',
        filter: ['!', ['has', 'point_count']],
        paint: {
          'circle-color': '#11b4da',
          'circle-radius': 4,
          'circle-stroke-width': 1,
          'circle-stroke-color': '#fff'
        }
      });

      // Create HTML markers for individual points
      Object.entries(markersData).forEach(([name, markerData]) => {
        // Create a custom DOM element for the marker
        const markerElement = document.createElement('div');
        markerElement.className = 'marker';
        const markerImgElement = document.createElement('img');
        markerImgElement.classList.add('marker-img', 'marker-img-hoverable');
        markerImgElement.src = `/static/thumbnail/${markerData.image}`; // Image path
        markerImgElement.alt = name; // Set alt text for accessibility
        markerImgElement.addEventListener("click", (ev) => {
          close_all_markers([ev.target]);
          open_marker(ev.target)
        });
        markerElement.appendChild(markerImgElement);

        // Add marker to map
        const markerInstance = new maplibregl.Marker({ element: markerElement })
          .setLngLat([markerData.lng, markerData.lat])

        // Manage visibility of custom markers based on zoom level
        map.on('zoom', () => {
          const zoomLevel = map.getZoom();
          if (zoomLevel > cluster_max_zoom) {
            markerInstance.addTo(map); // Show custom markers
          } else {
            markerInstance.remove();     // Hide custom markers
          }
        });
        add_entry_to_list(name, markerInstance);
      });

      // Cluster click events
      map.on('click', 'clusters', async (e) => {
        const features = map.queryRenderedFeatures(e.point, {
          layers: ['clusters']
        });
        const clusterId = features[0].properties.cluster_id;
        const zoom = await map.getSource('markers').getClusterExpansionZoom(clusterId);
        map.easeTo({
          center: features[0].geometry.coordinates,
          zoom: zoom
        });
      });

      // Unclustered point click events
      map.on('click', 'unclustered-point', (e) => {
        const coordinates = e.features[0].geometry.coordinates.slice();
        const message = e.features[0].properties.message;

        /*new maplibregl.Popup()
          .setLngLat(coordinates)
          .setHTML(message)
          .addTo(map);*/
      });

      // Change cursor style on mouse enter/leave
      map.on('mouseenter', 'clusters', () => {
        map.getCanvas().style.cursor = 'pointer';
      });
      map.on('mouseleave', 'clusters', () => {
        map.getCanvas().style.cursor = '';
      });

      // Close markers when zooming out
      map.on('wheel', 'clusters', () => {
        close_all_markers();
      });

      // Close all markers when clicking the map
      map.on('click', (e) => {
        console.log(e.originalEvent.target.classList)
        if (!e.originalEvent.target.classList.contains('marker-img')) {
          close_all_markers();
        }
      });

    });
  });

/* Image resizer hack
 * The marker image elements are placed by map libre, modifying it's height will move it,
 * hence we add a style sheet with javascript to set max dimensions
*/

const image_size = 0.75;

function set_image_size(){
  marker_img_size_stylesheet.replaceSync(
    `.marker-img-open {
      max-height: ${map_element.offsetHeight * image_size}px;
      max-width: ${map_element.offsetWidth * image_size}px;
    }`)
}

const marker_img_size_stylesheet = new CSSStyleSheet()
document.adoptedStyleSheets = [marker_img_size_stylesheet];
set_image_size()

addEventListener("resize", (event) => {
  set_image_size();
})