Skip to content

On a map ​

The map entries draw symbols on OpenLayers and MapLibre from one collection, and an editor places and edits them on either. Every renderer draws the same marks: the symbol is rendered once, turned into a glyph and placed at any zoom.

The saved object ​

A symbol on a map is a GeoJSON Point whose properties.military says what it is:

json
{
  "type": "Feature",
  "geometry": {"type": "Point", "coordinates": [-116.68, 35.27]},
  "properties": {
    "military": {
      "name": "130310000012110000000000000000",
      "amplifiers": {"T": "1-66", "M": "2BCT"},
      "size": "medium",
      "direction": 45
    }
  }
}
Property
namethe code: 2525D or 2525E, or a letter code
amplifiersby Table VI letter, as for renderSymbol
size'small', 'medium' or 'large'
directionQ, the direction of movement, in degrees
letterStandardfor a letter code: '2525C', '2525B' or 'APP-6B'

Nothing about the view travels with it. Store it, send it, load it back.

The collection ​

ts
import {MilitaryCollection} from '@zaes/military-symbols/map';

const collection = new MilitaryCollection();
const id = collection.add(feature);
collection.setProperties(id, {amplifiers: {T: '1-67'}});
collection.move(id, 'front');                         // stacking: 'front', 'back', 'forward', 'backward'
const saved = collection.toGeoJSON();                 // a FeatureCollection
const {loaded, skipped} = collection.load(saved, {replace: true});

load takes any GeoJSON and keeps the features it can draw: a single-point code of a standard this library draws. skipped says why each other one was left out.

OpenLayers ​

ts
import {MilitarySymbolsOpenLayers} from '@zaes/military-symbols/openlayers';

const renderer = new MilitarySymbolsOpenLayers(map, collection);

MapLibre ​

ts
import {MilitarySymbolsMapLibre} from '@zaes/military-symbols/maplibre';

const renderer = new MilitarySymbolsMapLibre(map, collection, {pointLeaders: true});

On a tilted map with terrain a symbol lying on the ground is foreshortened, and a ridge can hide it. pointLeaders stands each symbol upright on a leader line; renderer.setLeaderLines(false) lays them down again. Symbols stack in the collection's order, whole, one over another.

The editor ​

ts
import {MilitarySymbolsInteraction, MilitarySymbolsHistory, attachMilitaryEditor} from '@zaes/military-symbols/editor';

const history = new MilitarySymbolsHistory(collection);
const editor = new MilitarySymbolsInteraction(collection, renderer.view);
const detach = attachMilitaryEditor(renderer, editor);

editor.startDrawing('130310000012110000000000000000');   // the next click places it
editor.subscribe((e) => {
    if (e.type === 'drawend') editor.select(e.id);
    if (e.type === 'commit' || e.type === 'drawend') history.checkpoint();
});
history.undo();

A click places a symbol; any part of a symbol (frame, staff, echelon, amplifiers) selects it; a handle steps through the three sizes and another sets the direction of movement. The same editor works on either renderer: switch engines and call editor.setView(newRenderer.view).

How every symbol draws ​

ts
import {configureMilitarySymbols} from '@zaes/military-symbols/map';

configureMilitarySymbols({
    symbolPx: 40,                                      // the octagon's height at medium size
    amplifiers: true,
    display: {fillOpacity: 0.8, textHalo: 3},          // the display options of renderSymbol
    fullSizeScale: 0,                                  // shrink past this map scale (1:N); 0 never
});

It applies to every symbol on every map and redraws them.

Released under the MIT License; the drawings derive from Apache-2.0 work.