Skip to content

Add GeoJSON layer overlay type replacing KmlLayer - #38

Open
rabauss wants to merge 3 commits into
heimrichhannot:v3from
rabauss:feature/geojson-layer
Open

rabauss wants to merge 3 commits into
heimrichhannot:v3from
rabauss:feature/geojson-layer

Conversation

@rabauss

@rabauss rabauss commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Google deprecated the KmlLayer class of the Maps JavaScript API. It becomes unavailable in version 3.66 (August 2026) and stops working entirely in May 2027.

This adds a GeoJSON layer overlay type built on google.maps.Data as the replacement path, plus a command to convert existing KML files. The KML type is left in place so existing maps keep rendering until they are migrated.

Note on scope: this branch builds on #37 (Unlock symfony 7), which is still open. The first commit here is that PR's; once #37 is merged, this diff reduces to the GeoJSON work. The second commit is a pure ECS run over existing files, which had been failing independently of this change. The actual feature is the third commit (13 files).

What's in it

  • new overlay type with DCA fields, subpalettes for file/URL source, and DE/EN labels
  • prepareGeoJsonLayer() using Ivory's existing GeoJsonLayer — the library needs no changes
  • frontend script applying styling and info windows
  • huh:google-maps:convert-kml command plus a reusable KmlConverter

Why the frontend script is needed

GeoJsonLayer renders map.data.loadGeoJson() and nothing else. Unlike KML, GeoJSON carries no styling of its own, so a layer loaded that way draws in Google's default blue with no info windows.

The script applies both: styling via Data.setStyle(), reading each feature's simplestyle properties with the overlay's configured style as fallback, and info windows built from the remaining properties. Its markup uses BEM classes and ships no presentation of its own, so projects style it themselves.

Two non-obvious bits

Both look like they could be simplified, and both break silently if they are:

  • The initialization is registered as a map event. Ivory renders events inside the map's own init callback; the rendered JavaScript block runs before the async API callback assigns the map variable.
  • The script is registered from the replaceDynamicScriptTags hook. Maps render inside the body, by which point the head has been assembled — a TL_JAVASCRIPT entry added during rendering is dropped without warning.

Conversion

The common KML converters drop the styling, since GeoJSON has no place to put <Style> definitions and every route ends up the same colour. KmlConverter flattens them into simplestyle properties instead, resolves <StyleMap> indirections via their normal branch, converts KML's AABBGGRR colours (alpha first, then reversed RGB — read naively, red and blue swap), closes linear rings as GeoJSON requires, and keeps ExtendedData. Icon URLs can optionally be rewritten to local paths.

Usage is documented in the README.

Notes

  • No unit tests yet. kmlColorToHex() and the StyleMap resolution would be the ones worth covering; happy to add them if you want this merged.
  • CI: ECS and phpstan pass. rector fails on DoctrineSetList::DOCTRINE_ORM_214, which newer rector-doctrine versions no longer define — it fails to load its config before analysing anything, and does so on the base branch too. Since contao/contao-rector is required as dev-main, this appeared without any code change. Left untouched here as it seems out of scope for this PR.

rabauss added 3 commits March 23, 2026 20:15
Formatting only, no behaviour change.
Google deprecated the KmlLayer class of the Maps JavaScript API: it
becomes unavailable in version 3.66 (August 2026) and stops working
entirely in May 2027. This adds a GeoJSON overlay type built on
google.maps.Data as the replacement path, along with a command to
convert existing KML files.

Ivory already ships GeoJsonLayer, so the library needs no changes. It
renders map.data.loadGeoJson() and nothing else, though, and unlike KML
GeoJSON carries no styling of its own -- a layer loaded that way draws
in Google's default blue with no info windows. The frontend script
applies both: styling via Data.setStyle(), reading each feature's
simplestyle properties with the overlay's configured style as fallback,
and info windows built from the remaining properties. Its markup uses
BEM classes and ships no presentation, so projects style it themselves.

Two things are easy to get wrong here and are worth stating:

- The initialization is registered as a map event, because Ivory renders
  those inside the map's own init callback. The rendered JavaScript
  block runs before the async API callback assigns the map variable.
- The script is registered from the replaceDynamicScriptTags hook. Maps
  render inside the body, by which point the head has been assembled and
  a TL_JAVASCRIPT entry added during rendering is dropped without
  warning.

KmlConverter flattens <Style> and <StyleMap> definitions into
simplestyle properties, which is what the layer reads back -- the common
converters drop them and every route ends up the same colour. It
resolves StyleMap indirections via their "normal" branch, converts KML's
AABBGGRR colours (alpha first, then reversed RGB; read naively, red and
blue swap), closes linear rings as GeoJSON requires, and keeps
ExtendedData. Icon URLs can optionally be rewritten to local paths,
since KML tends to reference them absolutely and a HTTPS page blocks
http:// ones.

The KML overlay type is left in place so existing maps keep rendering
until they are migrated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant