ZuloOne
English
Sign in
Menu

📍 The map (GeoMap)

Updated

The shared map control for the SPA: tiles + an overlay, zoom / pan / Fit to data / Default view. Sales agents desk (/field-dispatch, ribbon caption Sales agents desk (Пульт торговых агентов)), the dashboard widget (Пульт торговых агентов), and the settings page all draw it; the next screen with a map does not copy Mercator.

← Developer wiki

What it is#

Not Leaflet and not a second engine. Web Mercator, tile images from a {z}/{x}/{y} template (the optional {s} = a/b/c), and an SVG or any children overlay on top. Pan is pointer + preventDefault / dragstart — otherwise a second drag with the mouse drags the browser's native ghost of the tile over the map. The overlay: pointerEvents: 'none' on the SVG, auto only on the pins. World points and the viewport are computed in frontend/src/kit/map/geoMapMath.ts.

<GeoMap settings={settings} fitPoints={points} fitKey={selected ?? 'all'} controls="full">
  {({ project, width, height }) => (
    <svg width={width} height={height} style={{ position: 'absolute', inset: 0 }}>
      <circle cx={project(lng, lat).x} cy={project(lng, lat).y} r={6} />
    </svg>
  )}
</GeoMap>

fitKey rebuilds the frame (a change of agent). Live points do not move the pan: the Fit to data button takes the current set. follow + followPoint / followKey keep the pin centred without changing the zoom; a pan or the wheel drops the following. controls: full | compact | none.

Zoom in half steps. A wheel notch or a press of + / − changes the zoom by 0.5 (ZOOM_STEP), not by a whole level: a whole level doubles the scale and jumped past the street the user was looking for. Tile servers have only whole levels, so a fractional zoom draws the nearest whole level scaled — at 13.5 the tiles of level 14 at 0.71×.

Where the viewer is. locateViewer (on by default) asks the browser for the position once, with its usual permission prompt, then follows it. The map shows a blue dot with a translucent disc for the accuracy and a My location button that centres on it at street zoom. A map with nothing of its own to fit opens on the viewer instead of the stand's default centre. A refused or unavailable position leaves the dot out and greys the button. Browsers give a position only over HTTPS or on localhost. Pass locateViewer={false} where the viewer's position means nothing, for example a document's static route.

The stand's settings#

Administrator → Map (/map-settings). This is infrastructure, like SMTP, not an object of a model.

MetaSystemSettings key Config Meaning
Map.TileUrl Map:TileUrl The tile template, http(s), {z}{x}{y} are mandatory
Map.Attribution Map:Attribution The credit in the corner
Map.DefaultLat / Lng / Zoom the same through : The empty frame
Map.MinZoom / MaxZoom the same The range 1…22

A database row overrides the config, and the config beats the built-in OSM / Kyiv. The API:

Method Who Path
GET anyone signed in /api/map-settings
PUT Admin /api/map-settings
DELETE Admin /api/map-settings — drop the overrides

A commercial tile service's key inside the URL is visible to everyone who opens the map. Restrict it by referrer at the provider; secrets are not put into MetaSystemSettings.

Where it already sits#

  • Sales agents desk /field-dispatch — page title Sales agents desk (Пульт торговых агентов): KPI strip, the pin, the day's track, the visits
  • The Sales agents desk dashboard widget (Пульт торговых агентов) — the same pins, compact layout without the four KPI tiles
  • The admin preview on the settings page

Where next#

Was this page helpful?