A Pure Frontend Toolkit Downloads Offline Map Tiles and Clips Them by Administrative Boundary
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.
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.
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.
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.
👍, 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.