Add a Comparison tool: swipe-compare two layers or two dates
Motivation
Users want to compare map content side by side — either two different layers, or the same layers at two different points in time — by dragging a divider and swiping between the two states. Today MMGIS can only toggle layers on and off; there's no way to put two states next to each other and reveal one against the other. A self-contained Comparison tool gives mission users this directly.
The tool supports two ways to compare, matching the prototype (https://visualization-tool-prototype.netlify.app/):
Compare layers
- The user starts from a layer in the layers list: opening that layer's three-dots (kebab) menu and choosing "Compare layer". The layer they acted on becomes one side of the comparison.
- The user then chooses a second layer for the other side.
- A draggable divider appears on the map: one layer renders on the left, the other on the right. Dragging the divider swipes between them.
- Changing the timeline date updates both layers normally — they keep following the timeline.
Compare dates
- The user picks two time periods using a date-range / timeline selector that spans both periods (the prototype shows two adjacent months with day markers).
- A draggable divider appears on the map; every active layer is shown on both sides, but each side reflects its own date. Dragging swipes between the two dates.
Throughout
- Changing the comparison selection updates the map's comparison view live. Ending the comparison restores the normal single view.
- The tool is a completely independent unit: it talks to the rest of MMGIS only through the plugin event bus. The "Compare layer" menu entry hands off to the tool by emitting an event the tool listens for; the tool drives the map's comparison/swipe capability and reads the current layers, dates, and timeline state purely through events and requests — never by reaching into the map or other tools directly.
Done when
Out of scope
- The core map swipe/split rendering capability this tool depends on — that's a separate issue; this tool consumes it rather than implementing it.
- A standalone floating panel. Comparison is entered contextually from the layer's three-dots menu (and the date selector), not from a floating panel opened by a button. Any docked surface the tool needs follows the normal tool docking; opening a panel on demand isn't supported by the current modern UI.
- 3D / globe comparison — tied to the core capability's scope.
Dependencies
Draft implementation plan — written as of abef1d7 on 2026-06-15. Rough guide; re-verify against latest code.
Current behavior
- The plugin event bus (
on / off / emit / request / provide, plus a forPlugin namespacing wrapper) is implemented and is the integration surface. The communication model — tools stay independent and talk only through the bus — is described in the ADR referenced below.
- The modern UI auto-docks tools and calls each tool's
make() once at startup; there is no open-on-demand or floating-panel host. There is one existing tool already built to the project's monorepo tool conventions (portable lib/ + adapters/ split) that serves as a structural reference, and it is also the tool that renders the per-layer rows in the layers list — the natural host for a "Compare layer" three-dots-menu entry.
Where the change lands & rough plan
- Build the tool to the project's established monorepo tool conventions: a portable
lib/ (TypeScript, one directory per component, BEM class names with the blocks- prefix, USWDS theme tokens, React 19 createRoot mounting) with zero MMGIS globals; an adapters/ layer holding all MMGIS coupling; an adapter component owning state; a thin tool wrapper using the modern tool pattern; and a config.json carrying the modern-layout metadata.
- All MMGIS interaction goes through the event bus (
request / provide / on / emit), ideally via the forPlugin namespacing helper. The tool drives the core swipe capability (set each side, enable/disable) and subscribes to timeline and layer events to stay in sync.
- Two entry points: (a) a "Compare layer" item in the per-layer three-dots menu of the layers list, which seeds the comparison with that layer; (b) a date-range/timeline selector for compare-dates. Either way, selections translate into a "left side config" and a "right side config" handed to the core capability.
- The "Compare layer" menu item lives in whatever renders the layers list, and hands off by emitting a namespaced event the Comparison tool subscribes to (keeping the tool independent). Confirm where that menu item is added and what event carries the layer.
⚠️ Gotcha: the modern UI docks and make()s tools once at startup with no floating/open-on-demand host. The prototype's contextual menu entry avoids needing a floating panel, but don't build show/hide machinery that assumes one — any tool surface follows normal docking.
⚠️ Gotcha: keep the swipe/clip rendering out of the plugin. It's tempting to reach into the map to clip panes from the tool, but that breaks the independence the architecture requires — the rendering belongs in the core capability, and the tool only configures it through events. The tool's portable library must not import map, layers, timeline, tool-controller, jQuery, or other tools directly.
References
Understood to be snapshot-accurate only:
docs/adr/20260209-plugin-communication-model.md — the plugin communication model (event bus, namespaces, why tools stay decoupled).
src/essence/mmgisAPI/mmgisAPI.js — event bus and the forPlugin namespacing wrapper.
src/essence/Tools/MODERN_TOOL_PATTERN.md — the modern tool pattern (docking, targetId/made, config metadata).
src/essence/Tools/LayerManager/ — an existing tool built to the lib/ + adapters/ conventions; use as a structural reference.
Add a Comparison tool: swipe-compare two layers or two dates
Motivation
Users want to compare map content side by side — either two different layers, or the same layers at two different points in time — by dragging a divider and swiping between the two states. Today MMGIS can only toggle layers on and off; there's no way to put two states next to each other and reveal one against the other. A self-contained Comparison tool gives mission users this directly.
The tool supports two ways to compare, matching the prototype (https://visualization-tool-prototype.netlify.app/):
Compare layers
Compare dates
Throughout
Done when
Out of scope
Dependencies
Draft implementation plan — written as of abef1d7 on 2026-06-15. Rough guide; re-verify against latest code.
Current behavior
on/off/emit/request/provide, plus aforPluginnamespacing wrapper) is implemented and is the integration surface. The communication model — tools stay independent and talk only through the bus — is described in the ADR referenced below.make()once at startup; there is no open-on-demand or floating-panel host. There is one existing tool already built to the project's monorepo tool conventions (portablelib/+adapters/split) that serves as a structural reference, and it is also the tool that renders the per-layer rows in the layers list — the natural host for a "Compare layer" three-dots-menu entry.Where the change lands & rough plan
lib/(TypeScript, one directory per component, BEM class names with theblocks-prefix, USWDS theme tokens, React 19createRootmounting) with zero MMGIS globals; anadapters/layer holding all MMGIS coupling; an adapter component owning state; a thin tool wrapper using the modern tool pattern; and aconfig.jsoncarrying the modern-layout metadata.request/provide/on/emit), ideally via theforPluginnamespacing helper. The tool drives the core swipe capability (set each side, enable/disable) and subscribes to timeline and layer events to stay in sync.References
Understood to be snapshot-accurate only:
docs/adr/20260209-plugin-communication-model.md— the plugin communication model (event bus, namespaces, why tools stay decoupled).src/essence/mmgisAPI/mmgisAPI.js— event bus and theforPluginnamespacing wrapper.src/essence/Tools/MODERN_TOOL_PATTERN.md— the modern tool pattern (docking,targetId/made, config metadata).src/essence/Tools/LayerManager/— an existing tool built to thelib/+adapters/conventions; use as a structural reference.