跪拜 Guibai
← All articles
GIS · Canvas · JavaScript

A Pure Frontend Toolkit Downloads Offline Map Tiles and Clips Them by Administrative Boundary

By 敲敲敲敲暴你脑袋 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Offline map packaging usually requires server-side tooling or GDAL. This approach keeps everything in the browser and produces a standard tile tree that drops straight into Leaflet or OpenLayers, useful for field apps, intranet deployments, or any environment where a live tile service is unavailable.

Summary

The workflow runs entirely in the browser: it draws tiles onto a Canvas, handles coordinate transforms between WGS84, GCJ02, BD09, and CGCS2000 via proj4 and gcoord, and writes the results into JSZip archives. For large zoom levels that produce thousands of tiles, split-package downloads avoid browser memory blow-up by chunking the ZIP output.

A second mode fetches GeoJSON administrative boundaries from Alibaba’s DataV.GeoAtlas, draws them as a clipping mask over the tiled canvas, and exports only the tiles that intersect the region. The canvas is then sliced back into individual tile-sized images and written to a ZIP with the standard z/y/x directory layout.

The output can be verified by overlaying a grid index or by loading the tiles directly into Leaflet or OpenLayers as a static XYZ layer. The source is open at github.com/xiaolidan00/offline-map-download.

Takeaways
Tile download and rendering happen entirely on a Canvas in the browser, with no server-side processing.
Coordinate transforms cover China’s four main systems: WGS84, GCJ02, BD09, and CGCS2000, using proj4 and gcoord.
Tile images are fetched in batches of six to respect HTTP/1.1 per-domain connection limits, with cached tiles drawn first.
Large tile sets are split into multiple ZIP downloads to avoid memory pressure; the browser must allow automatic multi-file downloads.
Administrative boundary GeoJSON from DataV.GeoAtlas is used as a Canvas clipping mask to export only tiles inside a region.
The clipped canvas is sliced back into individual tiles and written to a ZIP with a standard z/y/x folder structure.
Output tiles can be verified with a grid overlay or by serving them as a static XYZ layer in Leaflet or OpenLayers.
ArcGIS MapServer tileInfo (origin, lods, spatialReference) can be consumed directly to configure the projection.
Conclusions

Batching tile fetches into groups of six is a deliberate workaround for HTTP/1.1 connection limits, not an arbitrary choice — HTTP/2 would change the optimal concurrency.

Using Canvas globalCompositeOperation ‘destination-in’ to clip a full tile canvas by an administrative boundary is a clever, low-dependency alternative to running a spatial intersection on tile indices.

Browser canvas size limits prevent this technique from working at very high zoom levels for large regions, a hard constraint that server-side tile cutting does not face.

Concepts & terms
CGCS2000 (EPSG:4547)
China’s national geodetic coordinate system, used for official mapping. It is a projected coordinate system often encountered in ArcGIS services within China.
GCJ02 (Mars coordinate system)
An obfuscated coordinate system mandated for Chinese map providers. It applies a non-linear offset to WGS84 coordinates, requiring a transform library like gcoord to convert.
BD09
Baidu’s proprietary coordinate system, which applies an additional offset on top of GCJ02. Converting to or from BD09 requires a specific transform chain.
proj4 / proj4leaflet
A JavaScript port of the PROJ library for coordinate transformations. proj4leaflet extends Leaflet to support custom projections defined via PROJ strings.
JSZip
A JavaScript library for creating, reading, and editing ZIP files in the browser. Used here to package downloaded tiles into a single archive for offline use.
From the discussion

The discussion is thin. One comment corrects a coordinate system mislabeling in the article, noting that a PROJ string represents a projected CRS, not a geographic one. The other two comments are a promotional link and a brief compliment.

The PROJ string labeled as the CGCS2000 geographic coordinate system in the article actually defines a Gauss-Krüger projection (3° zone, central meridian 114E), not a geographic CRS. The correct geographic definition uses +proj=longlat.
Featured comments
欲买桂花同载酒

👍, one small issue // CGCS2000 Geographic Coordinate System const cgcs2000 = "+proj=tmerc +lat_0=0 +lon_0=114 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs"; This is not the CGCS2000 geographic coordinate system, but the Gauss-Krüger projection of CGCS2000 under a 3° zone with a central meridian of 114E. The CGCS2000 geographic coordinate system "+proj=longlat +ellps=GRS80 +no_defs +type=crs" is very similar to the WGS84 geographic coordinate system.

See top comments, translated →
Source: juejin.cn ↗ Google Translate ↗ Backup ↗