_mapbox.web.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import { View, Row } from 'app/design/view'
  2. import { useState, useRef, useCallback, lazy, Suspense } from 'react';
  3. import { NeoButton } from 'app/design/controls'
  4. import Loading from 'app/ui/atoms/loading'
  5. import { BlockWrapper } from 'app/components/block-wrapper'
  6. const MapComponent = lazy(() => import('app/components/elements/mapbox-inner'));
  7. export default function ElementMapBox({ data, blockWrapperProps }) {
  8. const mapRef = useRef(null);
  9. const [selectedlayers, setSelectedLayers] = useState(['incarcerees']);
  10. const [popupInfo, setPopupInfo] = useState(null); // Popup content data
  11. const viewport = {
  12. longitude: data.center[0],
  13. latitude: data.center[1],
  14. zoom: data.zoom
  15. }
  16. const dataSources = data.sources;
  17. const clickableLayers = dataSources.filter(source => selectedlayers.includes(source.key)).flatMap(source =>
  18. (source.layers || []).map(layer => ({
  19. ...layer,
  20. key: source.key
  21. }))
  22. )
  23. .filter(layer => layer.clickable === true).map(layer => layer.id);
  24. const onMapClick = useCallback((event) => {
  25. const map = mapRef.current.getMap();
  26. const features = map.queryRenderedFeatures(event.point, { layers: clickableLayers });
  27. if (features.length > 0) {
  28. const feature = features[0];
  29. if (feature.properties.cluster_id) {
  30. const clusterId = feature.properties.cluster_id;
  31. const coordinates = feature.geometry.coordinates;
  32. map.getSource(feature.source).getClusterExpansionZoom(clusterId, (err, zoom) => {
  33. if (err) return;
  34. map.flyTo({
  35. center: coordinates,
  36. zoom: zoom,
  37. essential: true,
  38. speed: 1.2,
  39. curve: 1,
  40. });
  41. });
  42. }
  43. else {
  44. if (feature.geometry.type == "Point") {
  45. const coordinates = feature.geometry.coordinates.slice();
  46. while (Math.abs(event.lngLat.lng - coordinates[0]) > 180) {
  47. coordinates[0] += event.lngLat.lng > coordinates[0] ? 360 : -360;
  48. }
  49. setPopupInfo({
  50. coordinates: coordinates,
  51. object: feature.properties,
  52. });
  53. }
  54. if (feature.geometry.type == "Polygon") {
  55. const coordinates = feature.geometry.coordinates[0][0];
  56. setPopupInfo({
  57. coordinates: coordinates,
  58. object: feature.properties,
  59. });
  60. }
  61. }
  62. } else {
  63. setPopupInfo(null);
  64. }
  65. }, [clickableLayers]);
  66. const infoFields = {
  67. 'num_people_excluded': 'Number of people excluded: ',
  68. 'sos_category': '',
  69. 'location': 'Location: ',
  70. 'camp': 'Camp: ',
  71. 'pe_location': 'Pre-evacuation Location: ',
  72. };
  73. return (
  74. <BlockWrapper {...blockWrapperProps}>
  75. <View className=" items-center">
  76. <Row className="gap-x-4 my-2">
  77. {dataSources.map((layer, index) => (
  78. <NeoButton controlSize="small" key={layer.key} label={layer.name} selected={selectedlayers.includes(layer.key)} onPress={() => selectedlayers.includes(layer.key) ? setSelectedLayers(selectedlayers.filter(name => name !== layer.key)) : setSelectedLayers([...selectedlayers, layer.key])} />
  79. ))}
  80. </Row>
  81. <View className="aspect-square w-full max-w-3xl ">
  82. <Suspense fallback={<Loading className="absolute" />}><MapComponent
  83. mapRef={mapRef}
  84. dataSources={dataSources}
  85. viewport={viewport}
  86. onMapClick={onMapClick}
  87. selectedlayers={selectedlayers}
  88. popupInfo={popupInfo}
  89. infoFields={infoFields}
  90. />
  91. </Suspense>
  92. </View>
  93. </View>
  94. </BlockWrapper>
  95. )
  96. }