Frontend Development 17 min read

Using maplibre-gl with Tianditu Tiles for Large‑Screen Map Development

This article explains how to choose between mapbox‑gl and its open‑source fork maplibre‑gl, obtain free Tianditu tile services, install the library, render 2.5D and vector tiles, customize styles, and overlay business data such as polygons, icons and labels for large‑screen web maps.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Using maplibre-gl with Tianditu Tiles for Large‑Screen Map Development

What You Will Learn

You will understand the differences between mapbox-gl and maplibre-gl , how to obtain free tiles from the authoritative "Tianditu" platform, and how to build a complete large‑screen map with 2.5D view, custom styling, and business data overlays.

Choosing a Map Engine

The article first compares the two engines. mapbox-gl is a widely used vector‑tile engine that supports 2.5D rotation, 3D models, raster and vector layers, but it requires an access token and a credit‑card‑bound account after version 2.0. maplibre-gl is a fork of mapbox-gl that removes the token requirement and remains fully open‑source.

When to Use Each

If you need Mapbox‑provided tile services, stick with mapbox-gl .

If you only need the rendering capabilities and prefer an open source solution, choose maplibre-gl .

Getting Tianditu Tiles

Register on the Tianditu website, create an API key, and use the WMTS URL pattern to request vector, annotation, or imagery tiles. The key is stored in a global variable MY_KEY to avoid accidental exposure.

window.MY_KEY = '88******************2030'

Installing maplibre‑gl

Install via Yarn or include the CDN:

yarn add maplibre-gl@latest
<script src="https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.js"></script>
<link href="https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.css" rel="stylesheet"/>

Rendering a Tianditu Tile Map

Initialize the map with a raster source that points to the Tianditu vector tiles and a layer that displays them. The example also shows how to enable 2.5D perspective.

<template>
  <div ref="mapEl" class="map"></div>
</template>
<script setup>
import mapboxgl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import { onMounted, ref } from 'vue';
const mapEl = ref(null);
const initOption = {
  style: {
    version: 8,
    sources: {
      'tdt-vec': {
        type: 'raster',
        tiles: [`https://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=${MY_KEY}`],
        tileSize: 256
      }
    },
    layers: [{ id: 'tdt-tiles-layer', type: 'raster', source: 'tdt-vec' }]
  }
};
onMounted(() => {
  new mapboxgl.Map({ container: mapEl.value, ...initOption });
});
</script>
<style scoped>
.map { width: 600px; height: 300px; }
</style>

Adding Annotation Tiles

Another raster source for annotation tiles can be added in the same style definition, then referenced by a new layer.

"sources": {
  "tdt-cva": {
    "type": "raster",
    "tiles": [
      `https://t0.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=${MY_KEY}`
    ],
    "tileSize": 256
  }
},
"layers": [
  { "id": "tdt-cva-layer", "type": "raster", "source": "tdt-cva" }
]

Customizing the Style

Adjust raster brightness, hue, and saturation to match a dark‑theme dashboard.

{
  "id": "tdt-tiles-layer",
  "type": "raster",
  "source": "tdt-vec",
  "paint": {
    "raster-brightness-max": 0.7,
    "raster-brightness-min": 0.3,
    "raster-hue-rotate": 20,
    "raster-saturation": 0.7
  }
}

Loading Business Data

Business‑specific layers are added by creating a geojson source and then adding fill , symbol (icons), and symbol (labels) layers. The article provides helper functions to load custom icons and shows the two‑step pattern (add source → add layer).

// Load custom icons
const loadImages = async (imgs) => {
  await Promise.all(Object.entries(imgs).map(([key, url]) =>
    new Promise(resolve => {
      map.loadImage(url, (err, res) => { if (err) throw err; map.addImage(key, res); resolve(res); });
    })
  ));
};

await loadImages(images);

// Add GeoJSON source
map.addSource('boys-source', { type: 'geojson', data: boys });

// Icon layer
map.addLayer({
  id: 'boys-icon-layer',
  type: 'symbol',
  source: 'boys-source',
  layout: {
    'icon-image': '{icon}',
    'icon-size': 0.2,
    'icon-anchor': 'center',
    'icon-rotation-alignment': 'viewport',
    'icon-allow-overlap': true
  }
});

// Name label layer
map.addLayer({
  id: 'boys-name-layer',
  type: 'symbol',
  source: 'boys-source',
  layout: {
    'text-field': '{name}',
    'text-size': 14,
    'text-offset': [0, 2.4],
    'text-allow-overlap': true
  },
  paint: { 'text-color': 'white' }
});

Conclusion

The guide covered the full workflow: selecting a map engine, obtaining free Tianditu tiles, installing maplibre-gl , rendering 2.5D maps, customizing visual style, and overlaying business‑specific polygons, icons, and labels. The next article will explore the "wireframe" style for large‑screen maps.

frontend developmentMap TilesWeb GISTiandituLarge‑Screen Mapsmapbox-glmaplibre-gl
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.