Mastering Web Maps

This article introduces how to implement a real-world map in the web technology stack and customize its style.

You can visit Chizu to see the actual effect.

Image
Image

Composition of Maps

First, let's clarify: how are maps implemented on the web?

Generally, they include the following entities:

  • Data Source: Provides map information, including place names, water bodies, contour lines, etc. You can use public data sources or host your own. Different rendering engines have different data conventions. Common data sources include:
    • Google Map
    • Maptiler: A commercial map provider
    • OpenStreetMap: Maintained by volunteers, similar to Wikipedia
    • Stadia Map: A commercial map provider
    • Domestic maps like Amap
  • Style: A specification that describes the style of the map. Like data sources, different rendering engines have different data conventions.
  • Rendering Engine: Combines the data source and style source to render them on the screen. Mainstream engines include:
    • Mapbox GL JS: Semi-open source, requires payment to access official data sources
    • MapLibre GL JS: An open-source alternative to Mapbox, which has developed its own open-source styling scheme
    • Leaflet: Open source, provides JS SDK / React SDK, etc.
    • OpenLayers: Open source

Since different rendering engines have different specifications, map data providers often offer SDKs to implement format conversion. For example:

Currently unable to display this content outside of Feishu documents.

To provide map services in mainland China, you must comply with the regulations of the national surveying and mapping geographic information management department, including using encrypted coordinate systems (such as GCJ-02) and obtaining map review numbers and other compliance requirements.

In any location providing map services, it is usually necessary to clearly state the data source.

Rendering Principles

Map data is typically divided into discrete Vector Tiles. Each tile contains data for a specific area and zoom level.

Taking MapLibre as an example, maps can be divided into two components from different perspectives:

  • Tile: From a planar view, the map can be split into individual tiles, similar to tiles in Unity 2D. Tiles are identified by a triplet (z, x, y).
  • Layer: From a vertical perspective, the map can be split into individual layers, such as water bodies as one layer, roads as another layer, and text as another layer. The zoom levels range from 0 (global view) to 20+ (street-level detail). Each increase in zoom level quadruples the number of tiles (doubling in both dimensions).

Data for maps, fonts, etc., is stored in PBF format. PBF stores vector data (points, lines, polygons) rather than pre-rendered images (raster tiles). This means that map rendering engines (like MapLibre GL JS) can use WebGL for hardware-accelerated rendering on the client side.

PBF is a binary format that encodes geospatial data in a more compact way compared to traditional text formats (like XML or JSON). This means that file sizes are significantly reduced; for example, OpenStreetMap's PBF files are typically half the size of their GZIP-compressed XML versions and about 30% smaller than their BZIP2-compressed XML versions.

It is also the core format of the Mapbox vector tile standard, widely adopted (such as OpenStreetMap, Mapbox, Tilezen, etc.), ensuring compatibility and interoperability.

Getting Started

We will take building a map styled like "Red Dead Redemption 2" as an example.

Step 1: Choose Data Source and Rendering Engine

Since this is a real-world map, we need to use real-world data sources. We will use Maptile as an example.

  1. Register for a Maptile account (free).
  2. Apply for an API KEY, which you will need to include in subsequent calls.

Maptile and Stadia both allow free calls during local development. If you cannot afford the fees, you can set up a Proxy to simulate localhost requests for actual production use.

In NextJS, you can create an API to implement this.

Note: This method is for learning purposes only and should not be used for other purposes.

Step 2: Write Map Styles

Maptile relies on a JSON file to describe the map. So the key is this JSON file.

Maptile provides an official map editor called Maputink, which you can use for visual editing. You can open an official configuration and modify it directly or start from scratch. The former is recommended.

Image
Image

You can also edit the JSON file directly. Using AI programming can yield good results as well.

We need to carefully design the map, including color schemes, fonts, display elements, etc. Elements can also be controlled for visibility based on zoom levels. This will not be elaborated on here.

The design language of Red Dead Redemption is as follows:

Image
Image

Here, you need to visually identify the fonts. I am not a professional designer, but I roughly judge as follows:

  • Water Bodies / Attractions: Ephesis
  • State (Province) Names: Merriweather
  • City Names: Outfit
  • Water Bodies: Metal

For water bodies, for example:

  • Set Rotation Alignment to Viewport (landscape text in Red Dead is always upright and not distorted).
  • Set Font to Ephesis.
  • Set Halo to the same color as the font and adjust the font thickness using Halo Width.

Next, we will add contour lines.

Since the default configuration does not support contour lines, but the map in "Red Dead Redemption 2" does have contour lines, we need to add an additional data source to implement the contour layer. You can directly use Maptile's data source:

/api/maptiler/tiles/contours-v2/tiles.json?key=Qnr580YQzLS9WFZBXZYE

You can also use your own setup. First, add a data source named "contours" in the Sources section.

Image
Image

Next, add a contour layer using the Line type. Specify that it uses the newly added data source and set the color, size, and other information.

Image
Image

Once designed, export the JSON file for later use.

Many properties support functions, meaning they are not fixed values but calculated based on conditions. The layer itself also supports conditional rendering. For example, the contour setting above is only displayed at a scale of 10 - 24. It will not display if zoomed out further.

Step 3: Use Custom Fonts

If you do not need custom fonts, you can skip this step.

Unlike CSS, we cannot directly use fonts through TTF files. Like other data layers in the map, we need to convert them into PBF format files first.

Maplibre has also released an open-source FontMaker tool that can convert font files into PBF files. First, upload all the fonts we need.

Image
Image

After conversion, we need to host the generated PBF files in the cloud for client access.

The engine will access the font source through a pre-defined address template, such as:

1https://www.example.com/font-server/{fontstack}/{range}.pbf

Where fontstack is the name of the font, so the file path on the server would look something like this:

Image
Image

Next, load the font in the JSON. Add this line:

1"glyphs": "https://chizu.ygeeker.com/font-server/{fontstack}/{range}.pbf",

You can also set glyphs in Maputnik, which will automatically fill it into the JSON:

Image
Image

Once the font source configuration is complete, you can specify the font name in the Glyph type layer. The name corresponds to the folder name of the font files.

Step 4: Display the Map on the Page

Using React as an example, load the configuration JSON file to display the map. You can then use the API to customize more advanced features. Example usage is as follows:

Image
Image

🎁 Bonus Content

You will notice an interesting phenomenon: at the border between Shenzhen and Hong Kong on Google Maps, the satellite map and roads in the Shenzhen direction do not align, but the Hong Kong direction is normal.

Image
Image

This is because the map coordinates used in China differ from international standards. The map data used in mainland China is usually based on the encrypted GCJ-02 coordinate system (commonly known as the "Mars coordinate system"), while Hong Kong and internationally used Google Maps adopt the WGS-84 coordinate system.

GCJ-02 is a non-public one-way encryption algorithm. In other words, it is difficult to convert GCJ-02 to WGS-84, but WGS-84 can be easily converted to GCJ-02.

Therefore, local map software authorized by China can display the correct satellite map. For services like Google that do not have access to this algorithm, they cannot convert the data provided by the Chinese government into WGS-84 format, and thus cannot match the roads and satellite maps.