0

I've created a react component to render a Maplibre map with with satellite raster tiles from Bing Maps as described here. The map renders correctly but markers and GeoJSON, are NOT displayed. I suspect it has to do with the oversimplified style JSON causing my custom layer to display over the top of all other layers(??) I can't seem to find any examples of styles that apply to a simple raster map like I'm trying to render. Below is the react component followed by the app where the Markers and GeoJSON layers are added. Any help is greatly appreciated!

...App.jsx:

 return (
    <>
      <ToolBar reqParams={requestParams} setReqParams={setRequestParams} />
      <BingMap
        initialViewState={{
          longitude: -75.20814109999999,
          latitude: 42.5264569,
          zoom: 18,
        }}
        style={{ width: "100vw", height: "100vh" }}
      >
        <Markers trackerPositions={trackerPositions} />
        <LineOverlay trackerPositions={trackerPositions} />
        <PolygonsFeature />
      </BingMap>
     </>
  );

BingMap.jsx

import { useState, useEffect, useRef} from "react";
import { Source, Layer } from 'react-map-gl';
import { Map } from 'react-map-gl/maplibre';
import "./bingMaps.css"
import 'maplibre-gl/dist/maplibre-gl.css';
import maplibregl from 'maplibre-gl';
import MYSTYLE from './layertest.json'

export default function BingMap ({initialViewState, style}) {
    const [mapStyle, setMapStyle] = useState(null)
    const map = useRef(null);

//    const [style, setStyle] = useState({sProps})
    var BingMapsKey = 'MUMBLYMUMBLY';
    var BingMapsImagerySet = 'AerialWithLabelsOnDemand'; //Alternatively, use 'AerialWithLabelsOnDemand' if you also want labels on the map.
    var BingMapsImageryMetadataUrl = `https://dev.virtualearth.net/REST/V1/Imagery/Metadata/${BingMapsImagerySet}?output=json&include=ImageryProviders&key=${BingMapsKey}`;

    useEffect(() => {
            async function fetchData()
            {
                if (mapStyle) return;
                const response = await fetch(BingMapsImageryMetadataUrl);
                const r = await response.json();
                    
                var tileInfo = r.resourceSets[0].resources[0];
                
                //Bing Maps supports subdoamins which can make tile loading faster. Create a tile URL for each subdomain. 
                var tileUrls = [];
                
                tileInfo.imageUrlSubdomains.forEach(sub => {
                    tileUrls.push(tileInfo.imageUrl.replace('{subdomain}', sub));
                });
                
                //Use the image provider info to create attributions.
                var attributions = tileInfo.imageryProviders.map(p => {
                    return p.attribution;
                }).join(', ');
            
                //Create a style using a raster layer for the Bing Maps tiles.
                var ss = {
                    'version': 8,
                    'sources': {
                        'bing-maps-raster-tiles': {
                            'type': 'raster',
                            'tiles': tileUrls,
                            'tileSize': tileInfo.imageWidth,
                            'attribution': attributions,
                            
                            //Offset set min/max zooms by one as Bign Maps is designed are 256 size tiles, while MapLibre is designed for 512 tiles.
                            'minzoom': 1,
                            'maxzoom': 20
                        }
                    },
                    'layers': [
                        {
                           'id': 'bing-maps-tiles',
                            'type': 'raster',
                            'source': 'bing-maps-raster-tiles',
                            'minzoom': 0,
                             'maxzoom': 23   //Let the imagery be overscaled to support deeper zoom levels.
                        }
                    ]
                    };
 
                    setMapStyle(ss);
            };
            fetchData();
        },[]);

        return (mapStyle ?
            <>
              <Map
                initialViewState={initialViewState}
                style={style}
                mapStyle={mapStyle}
          />
        </>    
        :
        <h1> loading </h1>
    );
}

rbrundritt
  • 16,570
  • 2
  • 21
  • 46
wdawson
  • 1
  • 1

2 Answers2

1

Are you seeing any errors in the console? The code looks correct for the most part, however it's possible that it's something small in the code that's easy to overlook, or a security related issue that is blocking access to the Bing Maps endpoint.

You may also want to consider using Azure Maps, Microsoft's newer enterprise mapping platform. Azure Maps uses MapLibre under the cover and exposes a modified API interface to make it easier to develop with. It also uses vector base maps. There is a react component for Azure Maps here: https://github.com/Azure/react-azure-maps

rbrundritt
  • 16,570
  • 2
  • 21
  • 46
  • Thanks for the response. I'm not seeing any errors in the console, not. Satellite imagery can only be obtained from raster tiles, correct? I'm using Bing maps because they have the latest aerial imagery for the fairly rural area that I'm primarily interested in. Other maps, Amazon / Esri / Here have imagery that is 8 - 10 years old! Could it be that my over-simplified (has only 1 layer) "style" JSON just doesn't provide enough info to render the other layers? I'm having trouble grasping which layers are used for say, or . – wdawson Jul 10 '23 at 21:18
  • Actually I see that the and components add a new and , I assume after the map layer. – wdawson Jul 10 '23 at 21:24
  • Having a single layer shouldn't be an issue. If using satellite/aerial imagery, then Bing Maps or Azure Maps wouldn't matter that much then since they use the same imagery. Are you seeing any network requests for tiles? – rbrundritt Jul 10 '23 at 21:47
0

I've fixed this issue by changing the BingMap function signature from:

const BingMap = ({initialViewState, style}) => {

to

const BingMap = (props) => {

then passing props.initialViewState and props.style to the <Map...> JSX, and changing the return block to:

 return (
        <Map
            initialViewState={props.initialViewState}
            style={props.style}
            mapStyle={mapStyle}
        >
            {props.children}
       </Map>

This has allowed all blocks inside the App.jsx render correctly:

 return (
<>
  <ToolBar reqParams={requestParams} setReqParams={setRequestParams} />
  <BingMap
    initialViewState={{
      longitude: -75.20814109999999,
      latitude: 42.5264569,
      zoom: 18,
    }}
    style={{ width: "100vw", height: "100vh" }}
  
  >
    <Markers trackerPositions={trackerPositions} />
    <LineOverlay trackerPositions={trackerPositions} />
    <PolygonsFeature />
  </BingMap>
 </>

);

wdawson
  • 1
  • 1