Skip to content

[143] Expose share-link and map-screenshot as plugin API capabilities#167

Draft
CarsonDavis wants to merge 5 commits into
developmentfrom
feature/143-share-screenshot-api
Draft

[143] Expose share-link and map-screenshot as plugin API capabilities#167
CarsonDavis wants to merge 5 commits into
developmentfrom
feature/143-share-screenshot-api

Conversation

@CarsonDavis

Copy link
Copy Markdown

Closes #143

Exposes two capabilities as first-class, supported parts of the public plugin API (mmgisAPI), with no backend dependency.

What

  • Share linkwriteCoordinateURL() returns the complete, self-contained view URL synchronously, formalized as the supported share-link entry point. The frontend dependency on the server-side link shortener is removed.
  • Map screenshotgetMapScreenshot() returns a PNG data URL, made engine-aware: capture is delegated to the active IMapEngine adapter. Leaflet uses the existing html2canvas path; the modern deck.gl / Mapbox-GL engine captures the GL canvas (with preserveDrawingBuffer: true, overlay and standalone modes). The existing screenshot button is re-pointed at the shared method so its behavior is unchanged.

Why engine-aware

The original html2canvas approach only works on the classic Leaflet DOM and produces a blank image on the modern deck.gl/WebGL map. Adding captureScreenshot() to IMapEngine makes screenshots work across both engines.

Verification

  • Live on the modern deck.gl map: getMapScreenshot() returns a non-blank PNG (real basemap, verified by pixel variance + visual check).
  • tsc --noEmit clean; deck.gl adapter unit tests pass.

Notes

  • Pre-existing (unrelated) test-env issue: several Leaflet-importing unit specs fail at module load with window is not defined on the baseline too; the new LeafletAdapter contract test does not execute until that's addressed (needs a jsdom/window shim in test setup).
  • preserveDrawingBuffer: true carries a small per-frame GL cost on the modern map (required for canvas capture).
  • E2E not run; unit tests + live verification only.

CarsonDavis and others added 5 commits June 25, 2026 11:42
Extract the inline html2canvas screenshot logic from the BottomBar camera
button into a reusable ScreenshotUtils.getMapScreenshot() that resolves to a
PNG data URL, and expose it publicly as mmgisAPI.getMapScreenshot(). The
onclone SVG/z-index fixups are preserved verbatim. The camera button shows its
spinner, downloads the capture via an object URL (blob) to avoid base64 bloat
on large captures, and hides the spinner on failure.

Make mmgisAPI.writeCoordinateURL() the canonical share-link method by removing
the frontend link-shortener dependency: drop the shortenURL branch/param from
QueryURL.writeCoordinateURL so it returns the full URL synchronously with no
backend call, update the BottomBar copy-link button accordingly, and remove the
now-dead shortener_shorten frontend registry entries. The backend shortener
endpoint/route/table and the shortener_expand path (for loading existing short
links) are left untouched.

Also fix a latent restore bug carried into the shared util (#mapToolBar bottom
was reset to a string literal instead of its saved value) and add behavioral
unit tests that drive getMapScreenshot() against injected jQuery/html2canvas
fakes.
writeCoordinateURL() called UserInterface_.getPanelPercents(), which only
exists on the classic/mobile UI controllers, throwing in the modern layout.
getMapScreenshot() targeted #mapScreen, absent in the modern layout. Guard
the panel-percents call (fall back to a map-only split) and fall back to the
#map container so both capabilities work in the modern layout that plugins run in.
The public mmgisAPI.getMapScreenshot() returned a blank image on the
modern deck.gl/GL map because it always went through html2canvas, which
cannot rasterize a WebGL canvas. Make screenshot capture a responsibility
of the active map engine.

- IMapEngine: add captureScreenshot(): Promise<string> to the contract.
- LeafletAdapter: implement it by delegating to the existing html2canvas
  helper (getMapScreenshot in ScreenshotUtils) — unchanged Leaflet logic.
- DeckGLAdapter: set preserveDrawingBuffer: true at GL-map creation (both
  mapbox-gl and maplibre-gl paths) so the canvas can be read back, and
  implement captureScreenshot() that forces a repaint then reads the GL
  canvas via toDataURL. Overlay mode is interleaved, so the base map's
  single canvas already holds basemap + deck layers.
- mmgisAPI.getMapScreenshot(): delegate to the active engine's
  captureScreenshot(), falling back to the html2canvas helper.
- BottomBar camera button: route through mmgisAPI.getMapScreenshot() so it
  shares the engine-aware path.

Tests: add deck.gl capture coverage (overlay redraw, triggerRepaint+rAF
fallback, standalone, no-map rejection) and a LeafletAdapter contract
check. Import MAP_ENGINE in the deck.gl spec from types/engine to avoid a
leaflet transitive import that breaks module load in the Node test env.
Standalone Deck (no basemap) omitted preserveDrawingBuffer, so
captureScreenshot() would read a cleared buffer and return a blank image
there. Match the overlay path so capture works in standalone mode too.
@github-actions

Copy link
Copy Markdown

🤖 Version Auto-Bumped

The version has been automatically incremented to 4.2.12-20260630

This commit was added to your PR branch. When you merge this PR, the new version will be included.


If you want a different version, update package.json manually and push to this PR.

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.

Core: expose the share-link and map-screenshot as first-class plugin API capabilities

1 participant