如何使用 turfjs 和 mapbox js select 并突出显示方形网格中的单元格?

How to select and highlight a cell from a square grid using turfjs and mapbox js?

我正在尝试 select 来自我已添加到我的 mapbox js 地图的方形网格层的单元格。

这是我的代码:

import React, { useRef, useEffect, useState } from 'react';
import './App.css';
import mapboxgl from '!mapbox-gl'; // eslint-disable-line import/no-webpack-loader-syntax
import * as turf from '@turf/turf'

mapboxgl.accessToken = 'MY_TOKEN';


function App() {
  const mapContainer = useRef(null);
  const map = useRef(null);
  const [lng, setLng] = useState(-82.659521999370077); // eslint-disable-line no-unused-vars
  const [lat, setLat] = useState(9.628698847753714); // eslint-disable-line no-unused-vars
  const [zoom, setZoom] = useState(17); // eslint-disable-line no-unused-vars

  useEffect(() => {
    if (map.current) return;
    map.current = new mapboxgl.Map({
      container: mapContainer.current,
      style: 'mapbox://styles/USER/MAP_ID',
      center: [lng, lat],
      zoom: zoom,
      scrollZoom: true
    });

    const bounds = map.current.getBounds();

    console.log(`bounds:`, bounds);

    const NE = bounds.getNorthEast();
    const SW = bounds.getSouthWest();

    var cellSide = 0.02;
    var grid = turf.squareGrid([SW.lng, SW.lat, NE.lng, NE.lat], cellSide, 'kilometers');

    console.log(`squareGrid - before:`, grid);

    // Set all features to highlighted == 'No'
    for (let i = 0; i < grid.features.length; i++) {
      grid.features[i].properties.highlighted = 'No';
    }

    console.log(`squareGrid - after:`, grid);

    map.current.on('load', () => {
      console.log(`-- Loaded --`);
      map.current.addSource('grid-source', {
        'type': "geojson",
        'data': grid,
        'generateId': true
      });
      map.current.addLayer(
        {
          'id': 'grid-layer',
          'type': 'fill',
          'source': 'grid-source',
          'paint': {
            'fill-outline-color': 'rgba(0,0,0,0.1)',
            'fill-color': 'rgba(0,0,0,0.1)'
          }
        }
      );
      map.current.addLayer(
        {
          'id': 'grid-layer-highlighted',
          'type': 'fill',
          'source': 'grid-source',
          'paint': {
            'fill-outline-color': '#484896',
            'fill-color': '#6e599f',
            'fill-opacity': 0.75
          },
          'filter': ['==', ['get', 'highlighted'], 'Yes']
        }
      );

      map.current.on('click', 'grid-layer', function (e) {

        e.features[0].properties.highlighted = 'Yes';
        console.log(`feature:`, e.features[0]);

        const filter = ['match', ['get', 'highlighted'], ['Yes', 'No'], true, false];
        map.current.setFilter('grid-layer-highlighted', filter);
      });
    });

    // Clean up on unmount
    return () => map.current.remove();
  });

  return (
    <div>
      <div className="sidebar">
        Longitude: {lng} | Latitude: {lat} | Zoom: {zoom}
      </div>
      <div ref={mapContainer} className="map-container" />
    </div>
  );
}

export default App;

目前,每次我点击一个单元格时,所有层 'grid-layer-highlighted' 都可见,而我只想突出显示我点击的单元格。

请问有什么帮助吗?

试试这个(我使用索引):

import React, { useRef, useEffect, useState } from 'react';
import mapboxgl from 'mapbox-gl'; 
import * as turf from '@turf/turf'

mapboxgl.accessToken = 'TOKEN!';


function Mapbox() {
  const mapContainer = useRef(null);
  const map = useRef(null);
  const [lng, setLng] = useState(-82.659521999370077); // eslint-disable-line no-unused-vars
  const [lat, setLat] = useState(9.628698847753714); // eslint-disable-line no-unused-vars
  const [zoom, setZoom] = useState(17); // eslint-disable-line no-unused-vars
  const [flag, setFlag] = useState(false); // eslint-disable-line no-unused-vars

  useEffect(() => {
    if (map.current) return;
    map.current = new mapboxgl.Map({
      container: mapContainer.current,
      style: 'mapbox://styles/mapbox/outdoors-v11',
      center: [lng, lat],
      zoom: zoom,
      scrollZoom: true
    });

    const bounds = map.current.getBounds();

    console.log(`bounds:`, bounds);

    const NE = bounds.getNorthEast();
    const SW = bounds.getSouthWest();

    var cellSide = 0.01;
    var grid = turf.squareGrid([SW.lng, SW.lat, NE.lng, NE.lat], cellSide, 'kilometers');

    console.log(`squareGrid - before:`, grid);

    // Set all features to highlighted == 'No'
    for (let i = 0; i < grid.features.length; i++) {
      grid.features[i].properties.highlighted = 'No';
      grid.features[i].properties.id = i;
    }

    console.log(`squareGrid - after:`, grid);

    map.current.on('load', () => {
      console.log(`-- Loaded --`);
      map.current.addSource('grid-source', {
        'type': "geojson",
        'data': grid,
        'generateId': true
      });
      map.current.addLayer(
        {
          'id': 'grid-layer',
          'type': 'fill',
          'source': 'grid-source',
          'paint': {
            'fill-outline-color': 'rgba(0,0,0,0.1)',
            'fill-color': 'rgba(0,0,0,0.1)'
          }
        }
      );
      map.current.addLayer(
        {
          'id': 'grid-layer-highlighted',
          'type': 'fill',
          'source': 'grid-source',
          'paint': {
            'fill-outline-color': '#484896',
            'fill-color': '#6e599f',
            'fill-opacity': 0.75
          },
          //'filter': ['==', ['get', 'highlighted'], 'Yes']
          'filter': ['==', ['get', 'id'], -1]
        }
      );

      
      //click action
      map.current.on('click', 'grid-layer', function (e) {
          var selectIndex = e.features[0].id;
          grid.features[e.features[0].id].properties.highlighted = 'Yes';
          console.log(`highlighted before:`, e.features[0].properties.highlighted);
          e.features[0].properties.highlighted = 'Yes';
          console.log(`feature:`, e.features[0]);
          console.log(`selectIndex:`, selectIndex);
          console.log(`highlighted after:`, e.features[0].properties.highlighted);

          //this! 무야호!
          const filter = ['==', ['number', ['get', 'id']], selectIndex];
  
          map.current.setFilter('grid-layer-highlighted', filter);
       
        
      });
    });

    // Clean up on unmount
    return () => map.current.remove();
  });

  return (
    <div>
      <div className="sidebar">
        Longitude: {lng} | Latitude: {lat} | Zoom: {zoom} | click : {flag == true}
      </div>
      <div ref={mapContainer} className="map-container" />
    </div>
  );
}

export default Mapbox;

结果: