Documentation

Pro handbook

Extensions

The editor has a socket for extensions and does nothing different while it is empty. vectorstream Pro is such an extension; you can write your own. The interface is experimental: it can change before the first release, and it is the part of the API that changes first.

An extension is an object with a name and an installiere(api) function. The editor calls it once, while it is being built, and hands it api:

Member of api What it registers
api.regelarten.register(definition) A kind of rule. A name that is registered twice, by any extension, is an error.
api.setzeElementfilter(fabrik) How a condition on a rule selects the elements it checks. Without one, a rule with a condition is not checked.
api.setzePruefstrategie(strategie) How the findings of a rule are computed from the last state: the full check (the default) or an incremental one.
api.setzeVorschau(fabrik) The red preview of the tools. Without one, no tool probes the rules while you draw.
api.rastquellen(quelle) Another source of snap targets besides the active layer.
api.nachRender(fn) A function that runs after every redraw.
api.container() The element the map draws into, or null where there is none.
api.editor The editor itself, public API only. It can be used once the editor is built, that is inside the functions an extension registered, not inside installiere.

The three slots with one occupant (the filter, the strategy and the preview) take one extension each; a second call is an error. installiere may return a function, which editor.destroy() calls once. After the editor is built, the registries are closed: no kind can be added later.

Plugging an extension in#

new Editor(layers, adapter, { erweiterungen: [meineErweiterung] });

or for every editor that is built afterwards, with a side effect on purpose:

erweiterungGlobalAnmelden(meineErweiterung);

OHNE_GLOBALE in the list of erweiterungen makes one editor ignore the announced extensions. editor.regelarten() lists the kinds an editor knows, with their properties.

A kind of rule of your own#

A kind of rule is a definition with three parts: its art (the stored name) and eigenschaften (does it take a target layer, a measure, does it snap onto the target); a plan that says which elements are judged and gives the verdict on each; and a meldung that words the refusal. The example is the kind "this layer holds points only". It takes no target layer and no measure.

import type { EbenenId } from '@vectorstream/core';
import type { Editor, Erweiterung, Regelart, Regelartdefinition } from '@vectorstream/editor';

/**
 * A kind of rule of one's own: "this layer holds points only". It takes no target layer and no
 * measure. The plan says which elements the rule judges (faces and line chains) and what the
 * verdict on each is; a verdict is a finding, or `null` for fine.
 */
export const NUR_PUNKTE: Regelartdefinition = {
  art: 'nurPunkte',
  eigenschaften: { ziel: false, mass: null, einrasten: false },
  plan: (_angabe, x, _ziel, _laengenmass, filter) => ({
    gruppen: [
      {
        seite: 'x', // the findings belong to the rule's own layer
        el: x,
        filter,
        arten: { flaechen: true, linien: true, punkte: false }, // points are never judged
        flaeche: (f) => ({ element: { art: 'flaeche', id: f }, ebene: 'x', zielflaechen: [], ordnung: { x: 0, y: 0 } }),
        linienzug: (zug) => ({ element: { art: 'linienzug', kanten: zug.kanten }, ebene: 'x', zielflaechen: [], ordnung: { x: 0, y: 0 } }),
        punkt: () => null,
      },
    ],
  }),
  // The sentence of a refusal names the layer, never an element.
  meldung: (_regel, x) => ({ detail: `“${x.name}” may hold points only`, code: 'example.pointsOnly' }),
};

/** The extension: one registration. Hand it to `new Editor(…, adapter, { erweiterungen: [nurPunkte] })`. */
export const nurPunkte: Erweiterung = {
  name: 'points-only',
  installiere: (api) => api.regelarten.register(NUR_PUNKTE),
};

/** Adds the rule to a layer. Returns its id, or `undefined` if the editor does not know the kind (no extension). */
export function nurPunkteRegel(editor: Editor, ebene: EbenenId): string | undefined {
  return editor.regelHinzufuegen(ebene, { art: NUR_PUNKTE.art as Regelart });
}

What the example shows, and the test next to it checks:

  • With the extension the rule is accepted, and an existing face in the layer is a violation; points are not.
  • Without the extension regelHinzufuegen refuses the kind, since the editor does not know it.
  • A document that holds such a rule keeps it in an editor without the extension: the rule is listed with the status benoetigtErweiterung and not checked (see Compatibility).

As for every rule, existing data never blocks adding it: what already violates it is counted as legacy, and later edits may not make things worse (see Counted, not blocked).

The building blocks#

@vectorstream/editor/erweiterung exports what a definition is made of: the types Regelartdefinition, Pruefplan, Gruppe and Befund; the views onto the geometry of a layer used by the checks of the two free kinds; the verdict functions that the full and the incremental check share; and the length measure of the map. The example above uses none of them, since "points only" needs no geometry. They are listed in the API reference. Because the interface is experimental, so are they.

See it on a map.