Search

Geofence Tracker Nodes

GeoJSON Boundaries

Detect when tracker nodes are inside a GeoJSON region.

Geofence Tracker Nodes
View live example →

Drag the tracker node along its trajectory to see when it enters a region.

Tracker node positions are available from the network layer using the getTrackerNodePositions()getTrackerNodePositions() API and can be used to identify when a ship enters a region defined by GeoJSON.

import { MapWeave } from "mapweave/mapbox";
import { GeoJsonLayer, ObservationsLayer, NetworkLayer } from "mapweave/layers";
import {
  observationsData,
  networkData,
  geojsonData,
  shipColors,
  regions,
} from "./data";

const startTime = new Date(2025, 4, 6);

function isShipInRegion(shipPosition, { south, west, north, east }) {
  const { latitude, longitude } = shipPosition;
  return (
    longitude >= west &&
    longitude <= east &&
    latitude >= south &&
    latitude <= north
  );
}

function formatList(items) {
  return items.length === 0 ? "None" : items.join(", ");
}

function getShipStatus(trackerPositions) {
  const inTrajectory = [];
  const outsideTrajectory = [];

  for (const [shipId, position] of Object.entries(trackerPositions)) {
    (position?.isInTrajectory ? inTrajectory : outsideTrajectory).push(shipId);
  }

  return { inTrajectory, outsideTrajectory };
}

function updateInfobox(shipStatus) {
  const infobox = document.getElementById("infobox-content");
  if (infobox) {
    infobox.textContent = `In trajectory: ${formatList(shipStatus.inTrajectory)}
Out of trajectory: ${formatList(shipStatus.outsideTrajectory)}`;
  }
}

const resetFns = [];

function updateRegionColors() {
  while (resetFns.length > 0) {
    const resetFn = resetFns.pop();
    resetFn();
  }

  const trackerPositions = networkLayer.getTrackerNodePositions();

  // Update ship visibility status
  const shipStatus = getShipStatus(trackerPositions);
  updateInfobox(shipStatus);

  for (const [regionId, region] of Object.entries(regions)) {
    // Find which visible ship (if any) is in this region and color accordingly
    for (const [shipId, position] of Object.entries(trackerPositions)) {
      if (
        position &&
        position.isInTrajectory &&
        isShipInRegion(position, region)
      ) {
        const color = shipColors[shipId]
          .replace("rgb", "rgba")
          .replace(")", ", 0.3)");
        const resetFn = geoJsonLayer.overrideStyle(regionId, { color });
        resetFns.push(resetFn);
        break;
      }
    }
  }
}

const mapweave = new MapWeave({
  container: "mw",
  options: { accessToken: VITE_MAPBOX_API_KEY },
});

const networkLayer = new NetworkLayer({ data: networkData });

const observationsLayerOptions = {
  trajectory: {
    maximumInterval: 60 * 60 * 1000,
  },
  trackerNodes: {
    // These options link the network layer icons to the observed entities
    networkLayerId: networkLayer.id,
    currentTime: startTime,
  },
  individual: {
    autoRange: { min: 0 },
    minimumRadiusMeters: 1000,
  },
};

const observationsLayer = new ObservationsLayer({
  data: observationsData,
  options: observationsLayerOptions,
});

const geoJsonLayer = new GeoJsonLayer({ data: geojsonData });

mapweave.layers([observationsLayer, geoJsonLayer, networkLayer]);

mapweave.fitBounds();

mapweave.on("drag-move", updateRegionColors);
mapweave.on("drag-end", updateRegionColors);

updateRegionColors();
export const shipColors = {
  yellowShip: "rgb(241, 191, 66)",
  redShip: "rgb(216, 81, 64)",
};

export const regions = {
  region1: { south: 49.2, west: -7.5, north: 50.6, east: -4.5 },
  region2: { south: 49.3, west: -2.7, north: 50.9, east: -0.7 },
  region3: { south: 50.6, west: 1.2, north: 52, east: 3.1 },
};

export const networkData = {
  yellowShip: {
    type: "node",
    color: "#101010",
    size: 10,
    border: { width: 2, color: shipColors.yellowShip },
    image: {
      url: "/public/images/icons/ci/yacht.svg",
      color: shipColors.yellowShip,
    },
  },
  redShip: {
    type: "node",
    color: "#101010",
    size: 10,
    border: { width: 2, color: shipColors.redShip },
    image: {
      url: "/public/images/icons/ci/yacht.svg",
      color: shipColors.redShip,
    },
  },
};

export const observationsData = {
  entities: {
    yellowShip: {
      color: shipColors.yellowShip,
    },
    redShip: {
      color: shipColors.redShip,
    },
  },
  observations: {
    "yellow-0": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 49.742687,
      longitude: -5.517006,
      time: 1746489600000,
    },
    "yellow-1": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 49.77585,
      longitude: -5.174162,
      time: 1746493200000,
    },
    "yellow-2": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 49.859453,
      longitude: -4.812579,
      time: 1746496800000,
    },
    "yellow-3": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 49.887234,
      longitude: -4.482283,
      time: 1746500400000,
    },
    "yellow-4": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 49.969189,
      longitude: -4.153157,
      time: 1746504000000,
    },
    "yellow-5": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 49.996704,
      longitude: -3.79536,
      time: 1746507600000,
    },
    "yellow-6": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.062269,
      longitude: -3.458585,
      time: 1746511200000,
    },
    "yellow-7": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.110711,
      longitude: -3.103859,
      time: 1746514800000,
    },
    "yellow-8": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.177785,
      longitude: -2.747572,
      time: 1746518400000,
    },
    "yellow-9": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.219657,
      longitude: -2.413479,
      time: 1746522000000,
    },
    "yellow-10": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.225445,
      longitude: -2.173332,
      time: 1746525600000,
    },
    "yellow-11": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.27729,
      longitude: -1.883357,
      time: 1746529200000,
    },
    "yellow-12": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.268126,
      longitude: -1.636639,
      time: 1746532800000,
    },
    "yellow-13": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.293733,
      longitude: -1.368887,
      time: 1746536400000,
    },
    "yellow-14": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.309745,
      longitude: -1.121686,
      time: 1746540000000,
    },
    "yellow-15": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.33365,
      longitude: -0.863134,
      time: 1746543600000,
    },
    "yellow-16": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.349588,
      longitude: -0.589228,
      time: 1746547200000,
    },
    "yellow-17": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.376335,
      longitude: -0.357044,
      time: 1746550800000,
    },
    "yellow-18": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.395133,
      longitude: -0.088295,
      time: 1746554400000,
    },
    "yellow-19": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.460482,
      longitude: 0.086023,
      time: 1746558000000,
    },
    "yellow-20": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.550902,
      longitude: 0.238852,
      time: 1746561600000,
    },
    "yellow-21": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.611105,
      longitude: 0.411044,
      time: 1746565200000,
    },
    "yellow-22": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.694637,
      longitude: 0.578058,
      time: 1746568800000,
    },
    "yellow-23": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.77433,
      longitude: 0.737261,
      time: 1746572400000,
    },
    "yellow-24": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.853582,
      longitude: 0.898914,
      time: 1746576000000,
    },
    "yellow-25": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.922793,
      longitude: 1.071283,
      time: 1746579600000,
    },
    "yellow-26": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.997163,
      longitude: 1.246802,
      time: 1746583200000,
    },
    "yellow-27": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.061204,
      longitude: 1.421502,
      time: 1746586800000,
    },
    "yellow-28": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.179615,
      longitude: 1.491568,
      time: 1746590400000,
    },
    "yellow-29": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.331974,
      longitude: 1.535249,
      time: 1746594000000,
    },
    "yellow-30": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.446136,
      longitude: 1.606495,
      time: 1746597600000,
    },
    "yellow-31": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.577289,
      longitude: 1.67907,
      time: 1746601200000,
    },
    "yellow-32": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.712057,
      longitude: 1.730155,
      time: 1746604800000,
    },
    "yellow-33": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.842222,
      longitude: 1.787359,
      time: 1746608400000,
    },
    "yellow-34": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.967187,
      longitude: 1.847835,
      time: 1746612000000,
    },
    "yellow-35": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 52.110784,
      longitude: 1.920065,
      time: 1746615600000,
    },
    "yellow-36": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 52.220649,
      longitude: 1.988451,
      time: 1746619200000,
    },
    "red-0": {
      type: "observation",
      entityId: "redShip",
      latitude: 52.370025,
      longitude: 3.706578,
      time: 1746489600000,
    },
    "red-1": {
      type: "observation",
      entityId: "redShip",
      latitude: 52.215551,
      longitude: 3.465443,
      time: 1746493200000,
    },
    "red-2": {
      type: "observation",
      entityId: "redShip",
      latitude: 52.06524,
      longitude: 3.234558,
      time: 1746496800000,
    },
    "red-3": {
      type: "observation",
      entityId: "redShip",
      latitude: 51.919175,
      longitude: 2.966129,
      time: 1746500400000,
    },
    "red-4": {
      type: "observation",
      entityId: "redShip",
      latitude: 51.736291,
      longitude: 2.750087,
      time: 1746504000000,
    },
    "red-5": {
      type: "observation",
      entityId: "redShip",
      latitude: 51.575317,
      longitude: 2.48578,
      time: 1746507600000,
    },

    "red-15": {
      type: "observation",
      entityId: "redShip",
      latitude: 50.30806,
      longitude: 0.549199,
      time: 1746543600000,
    },
    "red-16": {
      type: "observation",
      entityId: "redShip",
      latitude: 50.196893,
      longitude: 0.41216,
      time: 1746547200000,
    },
    "red-17": {
      type: "observation",
      entityId: "redShip",
      latitude: 50.11447,
      longitude: 0.251521,
      time: 1746550800000,
    },
    "red-18": {
      type: "observation",
      entityId: "redShip",
      latitude: 50.001293,
      longitude: 0.076072,
      time: 1746554400000,
    },
    "red-19": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.976381,
      longitude: -0.224351,
      time: 1746558000000,
    },
    "red-20": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.953019,
      longitude: -0.49948,
      time: 1746561600000,
    },
    "red-21": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.941289,
      longitude: -0.756986,
      time: 1746565200000,
    },
    "red-22": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.922577,
      longitude: -1.06356,
      time: 1746568800000,
    },
    "red-23": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.919638,
      longitude: -1.322502,
      time: 1746572400000,
    },
    "red-24": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.864749,
      longitude: -1.595358,
      time: 1746576000000,
    },
    "red-25": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.843586,
      longitude: -1.889306,
      time: 1746579600000,
    },
    "red-26": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.86042,
      longitude: -2.184169,
      time: 1746583200000,
    },
    "red-27": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.822904,
      longitude: -2.451595,
      time: 1746586800000,
    },
    "red-28": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.717736,
      longitude: -2.732433,
      time: 1746590400000,
    },
    "red-29": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.587322,
      longitude: -3.005417,
      time: 1746594000000,
    },
    "red-30": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.45591,
      longitude: -3.266489,
      time: 1746597600000,
    },
    "red-31": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.319815,
      longitude: -3.515813,
      time: 1746601200000,
    },
    "red-32": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.199566,
      longitude: -3.802024,
      time: 1746604800000,
    },
    "red-33": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.107795,
      longitude: -4.089816,
      time: 1746608400000,
    },
    "red-34": {
      type: "observation",
      entityId: "redShip",
      latitude: 48.968048,
      longitude: -4.332165,
      time: 1746612000000,
    },
    "red-35": {
      type: "observation",
      entityId: "redShip",
      latitude: 48.84175,
      longitude: -4.635675,
      time: 1746615600000,
    },
    "red-36": {
      type: "observation",
      entityId: "redShip",
      latitude: 48.729006,
      longitude: -4.887932,
      time: 1746619200000,
    },
  },
};

export const geojsonData = {
  type: "FeatureCollection",
  features: Object.entries(regions).map(
    ([id, { south, west, north, east }]) => {
      return {
        type: "Feature",
        id,
        properties: {
          color: "rgba(125, 125, 125, 0.3)",
        },
        geometry: {
          type: "Polygon",
          coordinates: [
            [
              [west, south],
              [west, north],
              [east, north],
              [east, south],
              [west, south],
            ],
          ],
        },
      };
    },
  ),
};
<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="@ci/theme/mw/css/examples.css" />
  </head>
  <body>
    <div id="mw">
      <div class="example__infobox" style="position: absolute; margin: 5px">
        <pre id="infobox-content"></pre>
      </div>
    </div>
    <script type="module" src="./code.js"></script>
  </body>
</html>
import React, {
  useState,
  useRef,
  useEffect,
  useCallback,
  useMemo,
} from "react";
import { createRoot } from "react-dom/client";
import { MapWeave } from "mapweave/react/mapbox";
import {
  GeoJsonLayer,
  ObservationsLayer,
  NetworkLayer,
} from "mapweave/react/layers";
import {
  observationsData,
  networkData,
  geojsonData,
  shipColors,
  regions,
} from "./data";

const startTime = new Date(2025, 4, 6);
const networkLayerId = "trackerNodes";

const mapWeaveOptions = { accessToken: VITE_MAPBOX_API_KEY };

const observationsLayerOptions = {
  trajectory: {
    maximumInterval: 60 * 60 * 1000,
  },
  trackerNodes: {
    currentTime: startTime,
    networkLayerId,
  },
  individual: {
    autoRange: { min: 0 },
    minimumRadiusMeters: 1000,
  },
};

const infoboxStyle = { position: "absolute", margin: 5 };

function isShipInRegion(shipPosition, { south, west, north, east }) {
  const { latitude, longitude } = shipPosition;
  return (
    longitude >= west &&
    longitude <= east &&
    latitude >= south &&
    latitude <= north
  );
}

function formatList(items) {
  return items.length === 0 ? "None" : items.join(", ");
}

function getShipStatus(trackerPositions) {
  const inTrajectory = [];
  const outsideTrajectory = [];

  for (const [shipId, position] of Object.entries(trackerPositions)) {
    (position?.isInTrajectory ? inTrajectory : outsideTrajectory).push(shipId);
  }

  return { inTrajectory, outsideTrajectory };
}

function Demo() {
  const [overrideStyles, setOverrideStyles] = useState([]);
  const [shipStatus, setShipStatus] = useState({
    inTrajectory: [],
    outsideTrajectory: [],
  });
  const networkLayerRef = useRef(null);

  const updateRegionColors = useCallback(() => {
    if (!networkLayerRef.current) return;

    const trackerPositions = networkLayerRef.current.getTrackerNodePositions();

    // Update ship visibility status
    setShipStatus(getShipStatus(trackerPositions));

    const newOverrideStyles = [];

    for (const [regionId, region] of Object.entries(regions)) {
      // Find which visible ship (if any) is in this region and color accordingly
      for (const [shipId, position] of Object.entries(trackerPositions)) {
        if (
          position &&
          position.isInTrajectory &&
          isShipInRegion(position, region)
        ) {
          const color = shipColors[shipId]
            .replace("rgb", "rgba")
            .replace(")", ", 0.3)");
          newOverrideStyles.push({ ids: regionId, overrideStyle: { color } });
          break;
        }
      }
    }

    setOverrideStyles(newOverrideStyles);
  }, []);

  // Update region colors when network layer is ready
  useEffect(() => {
    if (networkLayerRef.current) {
      updateRegionColors();
    }
  }, [updateRegionColors]);

  return (
    <>
      <div className="example__infobox" style={infoboxStyle}>
        <pre>
          {`In trajectory: ${formatList(shipStatus.inTrajectory)}
Out of trajectory: ${formatList(shipStatus.outsideTrajectory)}`}
        </pre>
      </div>
      <MapWeave
        options={mapWeaveOptions}
        onDragMove={updateRegionColors}
        onDragEnd={updateRegionColors}
      >
        <ObservationsLayer
          data={observationsData}
          options={observationsLayerOptions}
        />
        <GeoJsonLayer data={geojsonData} overrideStyles={overrideStyles} />
        <NetworkLayer
          ref={networkLayerRef}
          id={networkLayerId}
          data={networkData}
        />
      </MapWeave>
    </>
  );
}

const root = createRoot(document.getElementById("mw"));
root.render(<Demo />);
export const shipColors = {
  yellowShip: "rgb(241, 191, 66)",
  redShip: "rgb(216, 81, 64)",
};

export const regions = {
  region1: { south: 49.2, west: -7.5, north: 50.6, east: -4.5 },
  region2: { south: 49.3, west: -2.7, north: 50.9, east: -0.7 },
  region3: { south: 50.6, west: 1.2, north: 52, east: 3.1 },
};

export const networkData = {
  yellowShip: {
    type: "node",
    color: "#101010",
    size: 10,
    border: { width: 2, color: shipColors.yellowShip },
    image: {
      url: "/public/images/icons/ci/yacht.svg",
      color: shipColors.yellowShip,
    },
  },
  redShip: {
    type: "node",
    color: "#101010",
    size: 10,
    border: { width: 2, color: shipColors.redShip },
    image: {
      url: "/public/images/icons/ci/yacht.svg",
      color: shipColors.redShip,
    },
  },
};

export const observationsData = {
  entities: {
    yellowShip: {
      color: shipColors.yellowShip,
    },
    redShip: {
      color: shipColors.redShip,
    },
  },
  observations: {
    "yellow-0": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 49.742687,
      longitude: -5.517006,
      time: 1746489600000,
    },
    "yellow-1": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 49.77585,
      longitude: -5.174162,
      time: 1746493200000,
    },
    "yellow-2": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 49.859453,
      longitude: -4.812579,
      time: 1746496800000,
    },
    "yellow-3": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 49.887234,
      longitude: -4.482283,
      time: 1746500400000,
    },
    "yellow-4": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 49.969189,
      longitude: -4.153157,
      time: 1746504000000,
    },
    "yellow-5": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 49.996704,
      longitude: -3.79536,
      time: 1746507600000,
    },
    "yellow-6": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.062269,
      longitude: -3.458585,
      time: 1746511200000,
    },
    "yellow-7": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.110711,
      longitude: -3.103859,
      time: 1746514800000,
    },
    "yellow-8": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.177785,
      longitude: -2.747572,
      time: 1746518400000,
    },
    "yellow-9": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.219657,
      longitude: -2.413479,
      time: 1746522000000,
    },
    "yellow-10": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.225445,
      longitude: -2.173332,
      time: 1746525600000,
    },
    "yellow-11": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.27729,
      longitude: -1.883357,
      time: 1746529200000,
    },
    "yellow-12": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.268126,
      longitude: -1.636639,
      time: 1746532800000,
    },
    "yellow-13": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.293733,
      longitude: -1.368887,
      time: 1746536400000,
    },
    "yellow-14": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.309745,
      longitude: -1.121686,
      time: 1746540000000,
    },
    "yellow-15": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.33365,
      longitude: -0.863134,
      time: 1746543600000,
    },
    "yellow-16": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.349588,
      longitude: -0.589228,
      time: 1746547200000,
    },
    "yellow-17": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.376335,
      longitude: -0.357044,
      time: 1746550800000,
    },
    "yellow-18": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.395133,
      longitude: -0.088295,
      time: 1746554400000,
    },
    "yellow-19": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.460482,
      longitude: 0.086023,
      time: 1746558000000,
    },
    "yellow-20": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.550902,
      longitude: 0.238852,
      time: 1746561600000,
    },
    "yellow-21": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.611105,
      longitude: 0.411044,
      time: 1746565200000,
    },
    "yellow-22": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.694637,
      longitude: 0.578058,
      time: 1746568800000,
    },
    "yellow-23": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.77433,
      longitude: 0.737261,
      time: 1746572400000,
    },
    "yellow-24": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.853582,
      longitude: 0.898914,
      time: 1746576000000,
    },
    "yellow-25": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.922793,
      longitude: 1.071283,
      time: 1746579600000,
    },
    "yellow-26": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 50.997163,
      longitude: 1.246802,
      time: 1746583200000,
    },
    "yellow-27": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.061204,
      longitude: 1.421502,
      time: 1746586800000,
    },
    "yellow-28": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.179615,
      longitude: 1.491568,
      time: 1746590400000,
    },
    "yellow-29": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.331974,
      longitude: 1.535249,
      time: 1746594000000,
    },
    "yellow-30": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.446136,
      longitude: 1.606495,
      time: 1746597600000,
    },
    "yellow-31": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.577289,
      longitude: 1.67907,
      time: 1746601200000,
    },
    "yellow-32": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.712057,
      longitude: 1.730155,
      time: 1746604800000,
    },
    "yellow-33": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.842222,
      longitude: 1.787359,
      time: 1746608400000,
    },
    "yellow-34": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 51.967187,
      longitude: 1.847835,
      time: 1746612000000,
    },
    "yellow-35": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 52.110784,
      longitude: 1.920065,
      time: 1746615600000,
    },
    "yellow-36": {
      type: "observation",
      entityId: "yellowShip",
      latitude: 52.220649,
      longitude: 1.988451,
      time: 1746619200000,
    },
    "red-0": {
      type: "observation",
      entityId: "redShip",
      latitude: 52.370025,
      longitude: 3.706578,
      time: 1746489600000,
    },
    "red-1": {
      type: "observation",
      entityId: "redShip",
      latitude: 52.215551,
      longitude: 3.465443,
      time: 1746493200000,
    },
    "red-2": {
      type: "observation",
      entityId: "redShip",
      latitude: 52.06524,
      longitude: 3.234558,
      time: 1746496800000,
    },
    "red-3": {
      type: "observation",
      entityId: "redShip",
      latitude: 51.919175,
      longitude: 2.966129,
      time: 1746500400000,
    },
    "red-4": {
      type: "observation",
      entityId: "redShip",
      latitude: 51.736291,
      longitude: 2.750087,
      time: 1746504000000,
    },
    "red-5": {
      type: "observation",
      entityId: "redShip",
      latitude: 51.575317,
      longitude: 2.48578,
      time: 1746507600000,
    },

    "red-15": {
      type: "observation",
      entityId: "redShip",
      latitude: 50.30806,
      longitude: 0.549199,
      time: 1746543600000,
    },
    "red-16": {
      type: "observation",
      entityId: "redShip",
      latitude: 50.196893,
      longitude: 0.41216,
      time: 1746547200000,
    },
    "red-17": {
      type: "observation",
      entityId: "redShip",
      latitude: 50.11447,
      longitude: 0.251521,
      time: 1746550800000,
    },
    "red-18": {
      type: "observation",
      entityId: "redShip",
      latitude: 50.001293,
      longitude: 0.076072,
      time: 1746554400000,
    },
    "red-19": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.976381,
      longitude: -0.224351,
      time: 1746558000000,
    },
    "red-20": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.953019,
      longitude: -0.49948,
      time: 1746561600000,
    },
    "red-21": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.941289,
      longitude: -0.756986,
      time: 1746565200000,
    },
    "red-22": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.922577,
      longitude: -1.06356,
      time: 1746568800000,
    },
    "red-23": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.919638,
      longitude: -1.322502,
      time: 1746572400000,
    },
    "red-24": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.864749,
      longitude: -1.595358,
      time: 1746576000000,
    },
    "red-25": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.843586,
      longitude: -1.889306,
      time: 1746579600000,
    },
    "red-26": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.86042,
      longitude: -2.184169,
      time: 1746583200000,
    },
    "red-27": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.822904,
      longitude: -2.451595,
      time: 1746586800000,
    },
    "red-28": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.717736,
      longitude: -2.732433,
      time: 1746590400000,
    },
    "red-29": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.587322,
      longitude: -3.005417,
      time: 1746594000000,
    },
    "red-30": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.45591,
      longitude: -3.266489,
      time: 1746597600000,
    },
    "red-31": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.319815,
      longitude: -3.515813,
      time: 1746601200000,
    },
    "red-32": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.199566,
      longitude: -3.802024,
      time: 1746604800000,
    },
    "red-33": {
      type: "observation",
      entityId: "redShip",
      latitude: 49.107795,
      longitude: -4.089816,
      time: 1746608400000,
    },
    "red-34": {
      type: "observation",
      entityId: "redShip",
      latitude: 48.968048,
      longitude: -4.332165,
      time: 1746612000000,
    },
    "red-35": {
      type: "observation",
      entityId: "redShip",
      latitude: 48.84175,
      longitude: -4.635675,
      time: 1746615600000,
    },
    "red-36": {
      type: "observation",
      entityId: "redShip",
      latitude: 48.729006,
      longitude: -4.887932,
      time: 1746619200000,
    },
  },
};

export const geojsonData = {
  type: "FeatureCollection",
  features: Object.entries(regions).map(
    ([id, { south, west, north, east }]) => {
      return {
        type: "Feature",
        id,
        properties: {
          color: "rgba(125, 125, 125, 0.3)",
        },
        geometry: {
          type: "Polygon",
          coordinates: [
            [
              [west, south],
              [west, north],
              [east, north],
              [east, south],
              [west, south],
            ],
          ],
        },
      };
    },
  ),
};
<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="@ci/theme/mw/css/examples.css" />
  </head>
  <body>
    <div id="mw"></div>
    <script type="module" src="./code.jsx"></script>
  </body>
</html>

Terms of use

These terms do not alter or supersede any existing agreements between you (or your employer) and us.

By accessing or using any Content you agree to be bound by these Terms of Use. Please review these terms carefully before using the website.

The contents of this website, including but not limited to any text, code samples, API references, schemas, interactive tools, and other materials (collectively, the 'Content'), are made available for informational and internal evaluation purposes only. All intellectual property rights in the Content are reserved. No licence is granted to use the Content for any commercial purpose, or to copy, distribute, modify, reverse-engineer, or incorporate any part of the Content into any product or service, without our prior written consent.

This Content is provided “as is” and “as available,” without any representations, warranties, or guarantees of any kind, whether express or implied, including but not limited to implied warranties of merchantability, fitness for a particular purpose, non-infringement, or accuracy. To the fullest extent permitted by applicable law, we expressly exclude and disclaim all implied warranties, conditions, and other terms that might otherwise be implied.

We disclaim all liability for any loss or damage, whether direct, indirect, incidental, consequential, or otherwise, arising from any reliance placed on the Content or from your use of it, to the fullest extent permitted by applicable law. By continuing to access or use the Content, you acknowledge and agree to these terms.