简体   繁体   中英

how to different markers for different data set in mapbox

I am using map box api with react, I get 2 kind of data set from backend, one with let's say bike's parking points and another is data set is places where accident happened, I want to display both data set with different markers/icons in mapbox, how should I do that?

currently to display single data set I am using below code.

import React, { useState, useEffect, useRef } from "react";
import { useDispatch, useSelector } from 'react-redux';
import mapboxgl from 'mapbox-gl';
import {getBikeInfo, mapDetails} from  './features/counter/getInfo/getDetails.js'
<link href="https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.css" rel="stylesheet"></link>


function App() {
  const dispatch = useDispatch();
  const [dataLoaded, setDataLoaded] = useState(false);
  const dataToDisplay = useSelector(mapDetails);
  mapboxgl.accessToken = 'pk.eyJ1IjoidmloYW5nMTYiLCJhIjoiY2ttOHowc2ZhMWN2OTJvcXJ0dGpiY21pNyJ9.hK5Wxwby89E7tKWoBoY5bg';
  const mapContainer = useRef(null);
  let styles = {
    'display' : 'none'
  }
  useEffect(() => {
   // dispatch(getBikeInfo())
    var map = new mapboxgl.Map({
      container: mapContainer.current,
      style: 'mapbox://styles/mapbox/light-v10',
      center: [-96, 37.8],
      zoom: 3
    });

    map.on('load', function () {
      // Add an image to use as a custom marker
      map.loadImage(
        'https://docs.mapbox.com/mapbox-gl-js/assets/custom_marker.png',
        function (error, image) {
          if (error) throw error;
          map.addImage('custom-marker', image);
          // Add a GeoJSON source with 2 points
          map.addSource('points', {
            'type': 'geojson',
            'data': {
              'type': 'FeatureCollection',
              'features': dataToDisplay //list of all coordinates along require data 
            }
          });

          // Add a symbol layer
          map.addLayer({
            'id': 'points',
            'type': 'symbol',
            'source': 'points',
            'layout': {
              'icon-image': 'custom-marker',
              // get the title name from the source's "title" property
              'text-field': ['get', 'title'],
              'text-font': [
                'Open Sans Semibold',
                'Arial Unicode MS Bold'
              ],
              'text-offset': [0, 1.25],
              'text-anchor': 'top'
            }
          });
        }
      );
    });
    setDataLoaded(true);
  }, [dataToDisplay]);
  
  useEffect(() => {
    dispatch(getBikeInfo())
  },[])

  return (
    <div className="district-map-wrapper" style={dataLoaded ? undefined : {display: 'none'}}>
            <div id="districtDetailMap" className="map">
                <div style={{ height: "100%" }} ref={mapContainer}>

                </div>
            </div>
        </div>
   
  );
}

export default App;

below is sample data to populate

type: "Feature",
          geometry: {
            type: "Point",
        coordinates: [
           -74.04281705617905,
          40.71458403535893,
         
        ]
      },
      properties: {
        title: 'some field'
      }

Solution: based on @tylerban's answer I have update my code like this:

map.on('load', function () {
      // Add an image to use as a custom marker
      loadDataFromPara( dataToDisplay, 'https://docs.mapbox.com/mapbox-gl-js/assets/custom_marker.png', 'bikeLocation', 'bikePoints', 'bike-marker')
      loadDataFromPara( collisionInfo, marker, 'collisionLocation', 'collisionPoints', 'collision-marker')

    });
    setDataLoaded(true);
  function loadDataFromPara( data, image1, sourceName, layerName, imageMarker ){
      map.loadImage(
        image1,
        function (error, image) {
          if (error) throw error;
          map.addImage(imageMarker, image);
          // Add a GeoJSON source with 2 points
          map.addSource(sourceName, {
            'type': 'geojson',
            'data': {
              'type': 'FeatureCollection',
              'features': data
            }
          });

          // Add a symbol layer
          map.addLayer({
            'id': layerName,
            'type': 'symbol',
            'source': sourceName,
            'icon-allow-overlap': true,
            'layout': {
              'icon-image': imageMarker,
              // get the title name from the source's "title" property
              'text-field': ['get', 'title'],
              'icon-allow-overlap': true,
              'text-font': [
                'Open Sans Semibold',
                'Arial Unicode MS Bold'
              ],
              'text-offset': [0, 1.25],
              'text-anchor': 'top'
            }
          });


         
        }
      );
    }

Are the bike parking points and accident locations contained in the same source (dataset) or are they two different sources and layers that you are adding to the map?

If the bike parking and accidents are contained in the same source, you can use data driven styling in Mapbox to assign an icon based on a field in the data. So if you have a field in the source that can be used to determine if a point represents a bike parking spot or accident you would key off of that.

Here is some pseudo code that illustrates how to do this.

map.addLayer({
  id: 'points',
  type: 'symbol',
  source: 'points',
  layout: {
    'icon-image': [
      'match',
      [ 'get', 'type' ], // type corresponds to the field name you are keying off of
      [ 'bike parking' ],
      'custom-marker',
      [ 'pedestrian' ],
      'custom-marker-2',
      'custom-marker' // fallback icon
    ],
    // get the title name from the source's "title" property
    'text-field': [ 'get', 'title' ],
    'text-font': [
      'Open Sans Semibold',
      'Arial Unicode MS Bold'
    ],
    'text-offset': [ 0, 1.25 ],
    'text-anchor': 'top'
  }
})

If the bike parking and accidents are contained in two separate sources, you will just need to add a layer for each and assign an icon when adding the layer to the map.

Here is some pseudo code

// Add a bike parking layer
map.addLayer({
  'id': 'bike-parking',
  'type': 'symbol',
  'source': 'bike-parking-source',
  'layout': {
    'icon-image': 'custom-marker',
    // get the title name from the source's "title" property
    'text-field': ['get', 'title'],
    'text-font': [
      'Open Sans Semibold',
      'Arial Unicode MS Bold'
    ],
    'text-offset': [0, 1.25],
    'text-anchor': 'top'
  }
});

// Add an accidents layer
map.addLayer({
  'id': 'accidents',
  'type': 'symbol',
  'source': 'accidents-source',
  'layout': {
    'icon-image': 'custom-marker-2',
    // get the title name from the source's "title" property
    'text-field': ['get', 'title'],
    'text-font': [
      'Open Sans Semibold',
      'Arial Unicode MS Bold'
    ],
    'text-offset': [0, 1.25],
    'text-anchor': 'top'
  }
});

I have written a number of in depth posts on working with React and Mapbox and will link to them below in case you find them useful. I am also in the process of writing a Mapbox Developer's Handbook that contains the ins and outs of how to build powerful map driven applications.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM