跪拜 Guibai
← All articles
Cesium · WebGL · Vue.js

Hollowing Out a Map: Reverse Masking an Administrative Region in Cesium

By Tony费 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Highlighting a single region while visually suppressing the rest of the map is a common GIS requirement for dashboards, election maps, and service-area displays. The polygon-hole approach avoids complex clipping or shader work and works directly with standard GeoJSON files, but the winding-order and coordinate-flattening pitfalls are easy to miss.

Summary

A Cesium map can spotlight a single administrative region by drawing a semi-transparent black polygon over the entire globe and then punching a hole through it using the district's GeoJSON boundary. The technique relies on Cesium's polygon hierarchy and its holes array, which accepts a flattened list of Cartesian coordinates. The result is a map where only the target area is brightly visible and everything outside is dimmed.

The implementation also supports toggling between a vector base map and an imagery base map with road annotations. Switching layers requires a full `removeAll()` call on the imagery collection before adding the new provider; otherwise, transparency artifacts and layer stacking occur. The GeoJSON coordinate arrays must be recursively flattened because Cesium's `fromDegreesArray` cannot parse the standard multi-level nesting that administrative boundaries use.

Three common failures are documented: the hole not appearing due to incorrect coordinate winding order, residual layers after a base map switch, and parsing errors from unflattened GeoJSON arrays. The code is built with Vue 3 and Element Plus, using Amap tile URLs for demonstration.

Takeaways
Draw a globe-spanning rectangle as the mask entity, then supply the district's GeoJSON coordinates as a hole in the polygon hierarchy.
Recursively flatten multi-dimensional GeoJSON coordinate arrays before passing them to Cesium.Cartesian3.fromDegreesArray.
Call imageryLayers.removeAll() before adding new layers when switching base maps to prevent transparency and stacking bugs.
Coordinate ring winding direction matters: a clockwise hole inside a counter-clockwise outer ring (or vice versa) can cause the hollowing to fail silently.
An imagery base map with road labels requires two stacked UrlTemplateImageryProvider layers: one for satellite tiles and one for text annotations.
Conclusions

Using a global polygon with a hole is a simpler and more direct alternative to clipping planes or custom shaders for region highlighting, but it ties the mask to the entity API rather than the primitive level, which could limit performance with many dynamic holes.

The recursive array flattener is a one-liner with reduce, but it's a recurring friction point because GeoJSON's coordinate nesting depth varies by geometry type, and Cesium's API expects a flat list.

Hardcoding Amap tile URLs works for demos but the post explicitly warns against production use without proper licensing, which is a reminder that many Chinese map services require registered keys and compliance checks.

Concepts & terms
Polygon Hierarchy with Holes
A Cesium polygon entity can define an outer boundary and an array of inner hole boundaries. The holes are rendered as transparent cutouts, allowing the base map to show through while the outer polygon remains filled.
GeoJSON Coordinate Flattening
GeoJSON represents polygon coordinates as nested arrays (rings of coordinate pairs). Cesium's fromDegreesArray expects a flat list of [lon, lat, lon, lat, ...], so the nested structure must be recursively collapsed before use.
Imagery Layer Stacking
In Cesium, multiple imagery providers can be added to the same globe. A common pattern is to layer a transparent annotation tile set on top of a satellite imagery tile set so that labels appear over the photos.
From the discussion
Featured comments
THEKILL

Ask how to do reverse selection? [grin]

Tony费

Hello, if you want to implement reverse selection, that is, to mask the inside of an administrative region, first read the GeoJSON coordinates, then generate and draw a normal ground-clamped polygon based on the data, then fill the polygon with a semi-transparent mask. The external map can be displayed normally. You can refer to my newly published article, which has a specific implementation method.

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