DEV Community

Cover image for Baidu Map with react-leaflet
Mayar Deeb
Mayar Deeb

Posted on • Updated on

Baidu Map with react-leaflet

- We'll Talk About:

  1. What is react-leaflet ?
  2. How to add Baidu maps tile ?
  3. How to create custom CRS for Baidu maps ?
  4. Demo Link is in the end

1. What is react-leaflet ?

Leaflet is open-source JavaScript library for mobile-friendly interactive maps, it'll let you do what ever you want like adding markers, popups, shapes, etc...

2. How to add Baidu maps tile

1-create new react app
2- Install the required dependencies

npm i leaflet @types/leaflet react-leaflet proj4 @types/proj4 proj4leaflet @types/proj4leaflet
Enter fullscreen mode Exit fullscreen mode

or

yarn add leaflet @types/leaflet react-leaflet proj4 @types/proj4 proj4leaflet @types/proj4leaflet
Enter fullscreen mode Exit fullscreen mode

3- open your app in vscode or whatever is convenient and run the project
4- in App.tsx, import leaflet css file and proj4leaflet (IMPORTATNT).

import "leaflet/dist/leaflet.css";
import "proj4leaflet";
Enter fullscreen mode Exit fullscreen mode

5- import MapContainer, TileLayer from react-leaflet.
Your App.tsx should be like this.

import { MapContainer, TileLayer } from "react-leaflet";

// πŸŽ€πŸŽ€πŸŽ€ don't forget those they are so important πŸŽ€πŸŽ€πŸŽ€
import "leaflet/dist/leaflet.css";
import "proj4leaflet";

function App() {
  return (
    <div>
      <MapContainer
        style={{
          height: "100vh",
          width: "100%",
        }}
        center={[31.432026740690574, 120.8439179532812]}
        zoom={8}
      >
        <TileLayer
          // those two url are the same i just add both in case one of them get out of service
          url="https://maponline{s}.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=pl"
          //url="http://online{s}.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=pl&scaler=1&p=1"
          subdomains={["0", "1", "2", "3"]}
          maxNativeZoom={18}
          minNativeZoom={3}
          tms
        />
      </MapContainer>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

6- the map won't work because you need to pass crs as prop to the MapContainer component

3. How to create custom CRS for Baidu maps

1-create the crs

import { bounds, Proj } from "leaflet";

// create offset incase you want to adjust the map
const offset = { x: 40, y: -210 };

// create custom CRS for Baidu maps
// πŸ’₯πŸ’₯πŸ’₯ important πŸ’₯πŸ’₯πŸ’₯ this CRS only work with Baidu map Tile
//  if you have multi Tiles they'll break
const baiduCRS = new Proj.CRS(
  "EPSG:3395",
  `+proj=merc +lon_0=0 +k=1 +x_0=${offset.x} +y_0=${offset.y} +datum=WGS84 +units=m +no_defs`,
  {
    resolutions: [
      262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, 1024, 512, 256,
      128, 64, 32, 16, 8, 4, 2, 1,
    ],
    origin: [0, 0],
    bounds: bounds([20037508.342789244, 0], [0, 20037508.342789244]),
  }
);
Enter fullscreen mode Exit fullscreen mode

2- Pass it to MapContainer as a prop.
The whole code will be like this.

import { MapContainer, TileLayer } from "react-leaflet";
import { bounds, Proj } from "leaflet";

// πŸŽ€πŸŽ€πŸŽ€ don't forget those they are so important πŸŽ€πŸŽ€πŸŽ€
import "leaflet/dist/leaflet.css";
import "proj4leaflet";

// create offset incase you want to adjust the map
const offset = { x: 40, y: -210 };

// create costume CRS for Baidu maps
// πŸ’₯πŸ’₯πŸ’₯ important πŸ’₯πŸ’₯πŸ’₯ this CRS only work with Baidu map Tile
//  if you have multi Tiles they'll break
const baiduCRS = new Proj.CRS(
  "EPSG:3395",
  `+proj=merc +lon_0=0 +k=1 +x_0=${offset.x} +y_0=${offset.y} +datum=WGS84 +units=m +no_defs`,
  {
    resolutions: [
      262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, 1024, 512, 256,
      128, 64, 32, 16, 8, 4, 2, 1,
    ],
    origin: [0, 0],
    bounds: bounds([20037508.342789244, 0], [0, 20037508.342789244]),
  }
);

function App() {
  return (
    <div>
      <MapContainer
        style={{
          height: "100vh",
          width: "100%",
        }}
        // add the CRS here
        crs={baiduCRS}
        center={[31.432026740690574, 120.8439179532812]}
        zoom={8}
      >
        <TileLayer
          // those two url are the same i just add both in case one of them get out of service
          url="https://maponline{s}.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=pl"
          //url="http://online{s}.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=pl&scaler=1&p=1"
          subdomains={["0", "1", "2", "3"]}
          maxNativeZoom={18}
          minNativeZoom={3}
          tms
        />
      </MapContainer>
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

And now congratulations, πŸ₯³πŸ₯³ that's it.

In the application that I’m working on, I use Baidu for china and google for other countries by just replacing the tile and removing the crs prop from MapContainer. I explained how to do it in a previous article.

Demo Link πŸ”—

https://codesandbox.io/s/react-leaflet-baidu-maps-dyfi0j?file=/src/App.tsx

Another Chinese map providers

https://codesandbox.io/s/react-leaflet-chinese-providers-4c8fgx?file=/src/App.tsx

Image description

Top comments (0)