1import { Controller } from "@hotwired/stimulus" 2import mapboxgl from "mapbox-gl" 3import supportsInteractionObserver from "utils/supports_interaction_observer" 4 5// Connects to data-controller="numiko--multi-point-map" 6export default class extends Controller { 7 static values = { token: String, style: String } 8 9 connect () { 10 if (supportsInteractionObserver()) { 11 this.#setupObserver(); 12 } else { 13 this.#loadMapbox(); 14 } 15 } 16 17 disconnect () { 18 if (this.intersectionObserver) { 19 this.intersectionObserver.disconnect(); 20 } 21 } 22 23 #setupObserver () { 24 this.intersectionObserver = new window.IntersectionObserver(([entry]) => { 25 if (entry.isIntersecting) { 26 this.#loadMapbox(); 27 return; 28 } 29 }, { root: null, threshold: 0.1 }) 30 31 this.intersectionObserver.observe(this.element); 32 } 33 34 #loadMapbox () { 35 /* Should make file .js.erb and interpolate via ENV key */ 36 mapboxgl.accessToken = this.tokenValue; 37 let mapData = document.getElementById('multi-point-map').dataset; 38 let center_coords = mapData.mapCenter.split(',').map(function(el) { 39 return parseFloat(el); 40 }); 41 let map = new mapboxgl.Map({ 42 container: 'multi-point-map', 43 style: this.styleValue, 44 center: center_coords, 45 maxBounds: [[-180.0, -80.0], [180.0, 80.0]], 46 zoom: mapData.mapZoom, 47 minZoom: 1, 48 scrollZoom: false, 49 dragRotate: false, 50 renderWorldCopies: false 51 }); 52 let nav = new mapboxgl.NavigationControl(); 53 map.addControl(nav, 'top-right'); 54 return map.on('load', function() { 55 map.addSource('globalimpact', { 56 type: 'geojson', 57 data: mapData.mapDataUrl, 58 cluster: true, 59 clusterMaxZoom: 14, 60 clusterRadius: 50 61 }); 62 map.addLayer({ 63 id: 'clusters', 64 type: 'circle', 65 source: 'globalimpact', 66 filter: ['has', 'point_count'], 67 paint: { 68 'circle-color': ['step', ['get', 'point_count'], '#B33D26', 100, '#B33D26', 750, '#B33D26'], 69 'circle-radius': ['step', ['get', 'point_count'], 20, 10, 30, 20, 40, 30, 60] 70 } 71 }); 72 map.addLayer({ 73 id: 'cluster-count', 74 type: 'symbol', 75 source: 'globalimpact', 76 filter: ['has', 'point_count'], 77 layout: { 78 'text-field': '{point_count_abbreviated}', 79 'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'], 80 'text-size': 14 81 }, 82 paint: { 83 'text-color': '#ffffff' 84 } 85 }); 86 map.addLayer({ 87 id: 'unclustered-point', 88 type: 'circle', 89 source: 'globalimpact', 90 filter: ['!', ['has', 'point_count']], 91 paint: { 92 'circle-color': '#B33D26', 93 'circle-radius': 8, 94 'circle-stroke-width': 1, 95 'circle-stroke-color': '#fff' 96 } 97 }); 98 map.on('click', 'clusters', function(e) { 99 var clusterId, features; 100 features = map.queryRenderedFeatures(e.point, { 101 layers: ['clusters'] 102 }); 103 clusterId = features[0].properties.cluster_id; 104 map.getSource('globalimpact').getClusterExpansionZoom(clusterId, function(err, zoom) { 105 if (err) { 106 return; 107 } 108 map.easeTo({ 109 center: features[0].geometry.coordinates, 110 zoom: zoom 111 }); 112 }); 113 }); 114 map.on('mouseenter', 'clusters', function() { 115 map.getCanvas().style.cursor = 'pointer'; 116 }); 117 map.on('mouseleave', 'clusters', function() { 118 map.getCanvas().style.cursor = ''; 119 }); 120 map.on('click', 'unclustered-point', function(e) { 121 var coordinates, popupHtml, properties; 122 coordinates = e.features[0].geometry.coordinates.slice(); 123 properties = e.features[0].properties; 124 popupHtml = '<div style="width:300px">'; 125 popupHtml += '<h3>' + properties.tribe + '</h3>'; 126 popupHtml += '<p>' + properties.text + '</p>'; 127 popupHtml += '</div>'; 128 while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) { 129 coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360; 130 } 131 (new mapboxgl.Popup).setLngLat(coordinates).setHTML(popupHtml).addTo(map); 132 }); 133 map.on('mouseenter', 'unclustered-point', function() { 134 map.getCanvas().style.cursor = 'pointer'; 135 }); 136 map.on('mouseleave', 'unclustered-point', function() { 137 map.getCanvas().style.cursor = ''; 138 }); 139 }); 140 } 141}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.