Skip to content

Latest commit

 

History

History
104 lines (78 loc) · 2.73 KB

plugin-guide.md

File metadata and controls

104 lines (78 loc) · 2.73 KB

Plugin Guide — Developing a New MapPlugin

Overview

Plugins extend map functionality through a unified lifecycle. They integrate with the InteractionBroker for pick event handling and support exclusive groups for mutual exclusion.

Step-by-Step

1. Implement MapPlugin

// src/plugins/myfeature/MyPlugin.ts
import type { MapPlugin, PluginContext } from "@core/map/contracts/PluginContract";
import { DisposeBag } from "@core/map/utils/disposeBag";

export class MyPlugin implements MapPlugin {
  readonly id = "my-plugin";
  readonly priority = 50;               // Higher = first to receive events
  readonly exclusiveGroup = "none";     // "draw" | "measure" | "none"

  private ctx: PluginContext | null = null;
  private disposeBag = new DisposeBag();

  activate(ctx: PluginContext): void {
    this.ctx = ctx;
    const viewer = ctx.runtime.getViewer();

    // Set up event handlers, primitives, etc.
    // Register everything in disposeBag

    this.disposeBag.add(() => {
      // Cleanup
    });
  }

  deactivate(): void {
    // Temporary pause — keep state but stop listening
  }

  dispose(): void {
    this.deactivate();
    this.disposeBag.dispose();
    this.ctx = null;
  }
}

2. Activate via MapApp

import { MyPlugin } from "@plugins/myfeature/MyPlugin";

// In your page component:
const handleReady = (app: MapApp) => {
  const myPlugin = new MyPlugin();
  app.activatePlugin(myPlugin);
};

Exclusive Groups

Plugins with the same exclusiveGroup are mutually exclusive. When one activates, others in the same group are deactivated.

  • "draw": Drawing tools (point, polyline, polygon)
  • "measure": Measurement tools (distance, area)
  • "none": No exclusion — can coexist with any plugin

Pick Event Handling

To consume pick events, implement PickConsumer:

import type { PickConsumer } from "@core/map/contracts/PluginContract";

getPickConsumer(): PickConsumer {
  return {
    pluginId: this.id,
    priority: this.priority,
    onPick: (payload) => {
      // Process the pick
      // Return true to consume (stop propagation)
      // Return false to pass to next consumer
      return true;
    },
  };
}

Register with InteractionBroker:

activate(ctx: PluginContext): void {
  // Access broker via the MapApp
  broker.register(this.getPickConsumer());
}

Mandatory Rules

  1. DisposeBag: Every plugin MUST own a DisposeBag
  2. Symmetric lifecycle: activate() ↔ deactivate(), final dispose()
  3. No wild listeners: All event handlers go through the broker or DisposeBag
  4. requestRender(): Call after visual changes
  5. Use Primitives: Prefer PolylineCollection, PointPrimitiveCollection over Entity for performance