OnlyMapJS Latest release
GitHub Docs

← Gallery / Widgets

Add widgets

Add a legend, zoom controls, a scale bar and a live Vega-Lite chart without writing any script.

Open full screen ↗ View source ↗
<!DOCTYPE html>
<!--
  Widgets example — built-in legend, zoom-controls, scale-bar, and a
  vega-lite chart, all zero-script (spec: "Widget System"). Pan/zoom the
  map and watch the scale-bar and chart update live.
-->
<html>
<head>
  <meta charset="utf-8" />
  <title>OnlyMapJS — Add widgets</title>
  <link rel="stylesheet" href="https://unpkg.com/@nika-js/onlymap/dist/onlymapjs.css" />
  <script type="module" src="https://unpkg.com/@nika-js/onlymap/dist/onlymap.standalone.js"></script>
  <style>
    :root { color-scheme: dark; }
    html, body { margin: 0; height: 100%; font-family: system-ui, sans-serif; }
    /* One --om-widget-* block themes every built-in widget at once. */
    om-map {
      display: block; height: 100vh;
      --om-widget-bg: #14161c;
      --om-widget-fg: #f8fafc;
      --om-widget-muted: #8b93a7;
      --om-widget-border: #2c3040;
      --om-widget-hover-bg: #22262f;
    }
    /* The vega-lite built-in renders a bare chart, so give it a panel. */
    om-widget[type="vega-lite"] {
      background: #14161c; border: 1px solid #2c3040; border-radius: 6px;
      padding: 10px 12px 6px; box-shadow: 0 4px 18px rgba(0,0,0,.45);
    }
  </style>
</head>
<body>

  <om-map center="[-122.42, 37.77]" zoom="12">

    <om-layer id="bikes" type="ScatterplotLayer"
                data="../../data/bikes.json"
                label="Bike racks (radius ~ size)" color="#c084fc"
                get-position="[$lon, $lat]"
                get-radius="scale($size, sqrt, [3, 30], domain=[0, 100])"
                radius-units="pixels" pickable></om-layer>

    <!-- Legend enumerates every layer automatically — no per-layer authoring. -->
    <om-widget type="legend" title="Layers" interactive position="top-right"></om-widget>

    <!-- Zoom in/out — drives RuntimeCore.zoomBy() through the same
         action pipeline a click-to-zoom-to-feature behavior would use. -->
    <om-widget type="zoom-controls" position="bottom-right"></om-widget>

    <!-- Undo/redo over the manifest history — toggle a layer in the legend,
         then step back. Cmd/Ctrl-Z and Shift-Cmd/Ctrl-Z work too. -->
    <om-widget type="undo-redo" position="bottom-right"></om-widget>

    <!-- Compact widgets sharing a slot auto-merge into one control group
         (v0.4.2 clustering); the toggle hides all other chrome. -->
    <om-widget type="widgets-toggle" position="bottom-right"></om-widget>

    <!-- Recomputes its "nice" meter/km label on every pan/zoom. -->
    <om-widget type="scale-bar" position="bottom-left"></om-widget>


    <!-- ctx.dataInViewport("bikes") re-runs on every pan/zoom (Phase 4's
         deliverable: "LLM can write a Vega-Lite histogram that updates on
         pan/zoom") — try panning the racks in/out of view. -->
    <om-widget type="vega-lite" layer="bikes" watch="viewport data:bikes" title="Bike rack size (in view)"
                 position="top-left">
      <script type="application/json">
        {
          "background": "transparent",
          "mark": { "type": "bar", "color": "#c084fc" },
          "encoding": {
            "x": { "field": "size", "type": "quantitative", "bin": true, "title": "size" },
            "y": { "aggregate": "count", "type": "quantitative" }
          },
          "config": {
            "view": { "stroke": null },
            "axis": { "labelColor": "#8b93a7", "titleColor": "#8b93a7",
                      "gridColor": "#2c3040", "domainColor": "#2c3040", "tickColor": "#2c3040" }
          }
        }
      </script>
    </om-widget>

    <!-- No-JS fallback — shown only where scripts never run (chat-app/email
         file previews, iOS QuickLook); the stylesheet hides it the moment
         the map boots. Good practice on any page shared as a file. -->
    <om-fallback>
      <p><strong>This interactive map requires JavaScript.</strong><br />
         If you are seeing this in a file preview, open the file in a web
         browser such as Chrome, Safari, or Firefox.</p>
    </om-fallback>

  </om-map>

</body>
</html>

The snippet above loads the latest release. The demo above it is pinned to v0.5.2, so it keeps working when a new version ships.