Interact with the map to see the event object in the Event Details tab. Use the Filter Events tab to stop listening for specific events.
You can add event handlers to MapWeave to respond to user interactions. MapWeave will pass an object with details about the event to these event handlers.
import { MapWeave } from "mapweave/mapbox";
import { GeoJsonLayer, NetworkLayer, ObservationsLayer } from "mapweave/layers";
import { networkData, geojsonData, observationsData } from "./data";
const startTime = new Date(2025, 4, 6);
function setupTabPanels() {
const tabNames = ["last-event", "history", "filter-events"];
const tabs = tabNames.map((tabName) => byId(`${tabName}-tab`));
const panels = tabNames.map((tabName) => byId(`${tabName}-panel`));
for (const [index, tab] of Object.entries(tabs)) {
const panel = panels[index];
tab.addEventListener("click", () => {
for (const tabElement of tabs) {
tabElement.classList.remove("tab--active");
}
for (const panelElement of panels) {
panelElement.classList.remove("tab-panel--active");
}
panel.classList.add("tab-panel--active");
tab.classList.add("tab--active");
});
}
}
function populateDetailsPanel({ name, details }) {
eventNameHeader.innerHTML = name;
eventDetailsElement.innerText = details;
}
function stringifyDetails(eventDetails) {
function replacer(key, value) {
// Hide private fields
if (key.startsWith("_")) {
return undefined;
}
// Show the layer id instead of the full layer object
if (key === "layer" && value && value.id !== undefined) {
return { id: value.id };
}
return value;
}
return eventDetails ? JSON.stringify(eventDetails, replacer, 2) : "";
}
function selectListElement(listElement) {
previousDisplayedListElement = displayedListElement;
displayedListElement = listElement;
displayedListElement.classList.add("list-item--active");
if (previousDisplayedListElement !== undefined) {
previousDisplayedListElement.classList.remove("list-item--active");
}
const { type: eventName, info: eventDetails } = JSON.parse(
displayedListElement.getAttribute("data-event-details")
);
populateDetailsPanel({
name: eventName,
details: stringifyDetails(eventDetails),
});
}
function addEvent(event) {
const listElement = document.createElement("li");
listElement.classList.add("list-item");
listElement.innerText = event.type;
listElement.setAttribute("data-event-details", stringifyDetails(event));
eventListElement.insertBefore(listElement, eventListElement.querySelector("li"));
return listElement;
}
function setActiveModifiers(modifierKeys) {
Object.entries(modifierKeys).forEach(([modifierKey, isActive]) => {
const span = modifiersContainer.querySelector(`[data-event-name="${modifierKey}"]`);
if (isActive) {
span.classList.add("modifier-key--active");
} else {
span.classList.remove("modifier-key--active");
}
});
}
function genericEventHandler(eventName, event) {
if (selectedEvents[eventName]) {
const newListElement = addEvent({ type: eventName, info: event });
// display the details for the new event
selectListElement(newListElement);
// show which modifier keys are down
if (event && event.modifierKeys) {
setActiveModifiers(event.modifierKeys);
}
}
}
const byId = document.getElementById.bind(document);
const modifiersContainer = byId("modifiers");
const eventListElement = byId("event-list");
const clearEventsListButton = byId("clear-event-list");
const eventNameHeader = document.querySelector(".header--plain");
const eventDetailsElement = document.querySelector(".json-block");
const eventCheckboxes = [...document.querySelectorAll('.event-filter-list input[type="checkbox"]')];
const selectAll = byId("select-all");
const deselectAll = byId("deselect-all");
const eventMap = {
click: true,
"drag-start": true,
"drag-move": true,
"drag-end": true,
hover: true,
load: true,
"view-change": true,
};
const initialSelectedEvents = {
...eventMap,
};
let selectedEvents = initialSelectedEvents;
let displayedListElement;
let previousDisplayedListElement;
setupTabPanels();
clearEventsListButton.addEventListener("click", () => {
eventListElement.innerHTML = "";
populateDetailsPanel({ name: " ", details: "{}" });
});
eventListElement.addEventListener("click", (evt) => {
if (evt.target instanceof HTMLLIElement) {
selectListElement(evt.target);
}
});
selectAll.addEventListener("click", () => {
eventCheckboxes.forEach((checkbox) => {
checkbox.checked = true;
});
selectedEvents = eventMap;
});
deselectAll.addEventListener("click", () => {
eventCheckboxes.forEach((checkbox) => {
checkbox.checked = false;
});
selectedEvents = {};
});
eventCheckboxes.forEach((inputElement) => {
inputElement.addEventListener("change", (evt) => {
const eventName = evt.target.getAttribute("data-event-name");
selectedEvents = { ...selectedEvents, [eventName]: evt.target.checked };
});
});
const mapweave = new MapWeave({
container: "mw",
options: { accessToken: VITE_MAPBOX_API_KEY },
});
const geojsonLayer = new GeoJsonLayer({
data: geojsonData,
});
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,
});
mapweave.layers([geojsonLayer, observationsLayer, networkLayer]);
mapweave.fitBounds();
// register event handlers
Object.keys(eventMap).forEach((eventName) => {
mapweave.on(eventName, (event) => genericEventHandler(eventName, event));
}); export const observationsData = {
entities: {
blueShip: {
color: "rgb(83, 131, 236)",
},
redShip: {
color: "rgb(216, 81, 64)",
},
yellowShip: {
color: "rgb(241, 191, 66)",
},
greenShip: {
color: "rgb(88, 166, 92)",
},
},
observations: {
"blue-0": {
type: "observation",
entityId: "blueShip",
latitude: 54.578355,
longitude: -5.197542,
time: 1746489600000,
},
"blue-1": {
type: "observation",
entityId: "blueShip",
latitude: 54.406994,
longitude: -5.210292,
time: 1746493200000,
},
"blue-2": {
type: "observation",
entityId: "blueShip",
latitude: 54.272794,
longitude: -5.208974,
time: 1746496800000,
},
"blue-3": {
type: "observation",
entityId: "blueShip",
latitude: 54.142754,
longitude: -5.184721,
time: 1746500400000,
},
"blue-4": {
type: "observation",
entityId: "blueShip",
latitude: 53.97328,
longitude: -5.185769,
time: 1746504000000,
},
"blue-5": {
type: "observation",
entityId: "blueShip",
latitude: 53.837737,
longitude: -5.164967,
time: 1746507600000,
},
"blue-6": {
type: "observation",
entityId: "blueShip",
latitude: 53.670558,
longitude: -5.192878,
time: 1746511200000,
},
"blue-7": {
type: "observation",
entityId: "blueShip",
latitude: 53.504643,
longitude: -5.186715,
time: 1746514800000,
},
"blue-8": {
type: "observation",
entityId: "blueShip",
latitude: 53.365212,
longitude: -5.17317,
time: 1746518400000,
},
"blue-9": {
type: "observation",
entityId: "blueShip",
latitude: 53.2161,
longitude: -5.162903,
time: 1746522000000,
},
"blue-10": {
type: "observation",
entityId: "blueShip",
latitude: 53.052743,
longitude: -5.226897,
time: 1746525600000,
},
"blue-11": {
type: "observation",
entityId: "blueShip",
latitude: 52.892953,
longitude: -5.333351,
time: 1746529200000,
},
"blue-12": {
type: "observation",
entityId: "blueShip",
latitude: 52.711297,
longitude: -5.375885,
time: 1746532800000,
},
"blue-13": {
type: "observation",
entityId: "blueShip",
latitude: 52.568214,
longitude: -5.457204,
time: 1746536400000,
},
"blue-14": {
type: "observation",
entityId: "blueShip",
latitude: 52.409118,
longitude: -5.529224,
time: 1746540000000,
},
"blue-15": {
type: "observation",
entityId: "blueShip",
latitude: 52.242918,
longitude: -5.60549,
time: 1746543600000,
},
"blue-16": {
type: "observation",
entityId: "blueShip",
latitude: 52.071092,
longitude: -5.692136,
time: 1746547200000,
},
"blue-17": {
type: "observation",
entityId: "blueShip",
latitude: 51.899728,
longitude: -5.787732,
time: 1746550800000,
},
"blue-18": {
type: "observation",
entityId: "blueShip",
latitude: 51.739952,
longitude: -5.85027,
time: 1746554400000,
},
"blue-19": {
type: "observation",
entityId: "blueShip",
latitude: 51.602765,
longitude: -5.974733,
time: 1746558000000,
},
"blue-20": {
type: "observation",
entityId: "blueShip",
latitude: 51.474164,
longitude: -6.114349,
time: 1746561600000,
},
"blue-21": {
type: "observation",
entityId: "blueShip",
latitude: 51.362769,
longitude: -6.264626,
time: 1746565200000,
},
"blue-22": {
type: "observation",
entityId: "blueShip",
latitude: 51.204582,
longitude: -6.360486,
time: 1746568800000,
},
"blue-23": {
type: "observation",
entityId: "blueShip",
latitude: 51.084279,
longitude: -6.526525,
time: 1746572400000,
},
"blue-24": {
type: "observation",
entityId: "blueShip",
latitude: 50.941434,
longitude: -6.627714,
time: 1746576000000,
},
"blue-25": {
type: "observation",
entityId: "blueShip",
latitude: 50.815822,
longitude: -6.768253,
time: 1746579600000,
},
"blue-26": {
type: "observation",
entityId: "blueShip",
latitude: 50.68009,
longitude: -6.922329,
time: 1746583200000,
},
"blue-27": {
type: "observation",
entityId: "blueShip",
latitude: 50.56413,
longitude: -7.037884,
time: 1746586800000,
},
"blue-28": {
type: "observation",
entityId: "blueShip",
latitude: 50.406445,
longitude: -7.036782,
time: 1746590400000,
},
"blue-29": {
type: "observation",
entityId: "blueShip",
latitude: 50.247185,
longitude: -7.004507,
time: 1746594000000,
},
"blue-30": {
type: "observation",
entityId: "blueShip",
latitude: 50.08487,
longitude: -7.014869,
time: 1746597600000,
},
"blue-31": {
type: "observation",
entityId: "blueShip",
latitude: 49.937541,
longitude: -6.993953,
time: 1746601200000,
},
"blue-32": {
type: "observation",
entityId: "blueShip",
latitude: 49.784533,
longitude: -6.984443,
time: 1746604800000,
},
"blue-33": {
type: "observation",
entityId: "blueShip",
latitude: 49.639579,
longitude: -6.960981,
time: 1746608400000,
},
"blue-34": {
type: "observation",
entityId: "blueShip",
latitude: 49.467846,
longitude: -6.961437,
time: 1746612000000,
},
"blue-35": {
type: "observation",
entityId: "blueShip",
latitude: 49.32475,
longitude: -6.92981,
time: 1746615600000,
},
"blue-36": {
type: "observation",
entityId: "blueShip",
latitude: 49.152295,
longitude: -6.93082,
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-6": {
type: "observation",
entityId: "redShip",
latitude: 51.418045,
longitude: 2.244322,
time: 1746511200000,
},
"red-7": {
type: "observation",
entityId: "redShip",
latitude: 51.263755,
longitude: 1.993267,
time: 1746514800000,
},
"red-8": {
type: "observation",
entityId: "redShip",
latitude: 51.140054,
longitude: 1.762104,
time: 1746518400000,
},
"red-9": {
type: "observation",
entityId: "redShip",
latitude: 50.971223,
longitude: 1.516238,
time: 1746522000000,
},
"red-10": {
type: "observation",
entityId: "redShip",
latitude: 50.852823,
longitude: 1.357977,
time: 1746525600000,
},
"red-11": {
type: "observation",
entityId: "redShip",
latitude: 50.741735,
longitude: 1.215997,
time: 1746529200000,
},
"red-12": {
type: "observation",
entityId: "redShip",
latitude: 50.631068,
longitude: 1.037502,
time: 1746532800000,
},
"red-13": {
type: "observation",
entityId: "redShip",
latitude: 50.53398,
longitude: 0.888554,
time: 1746536400000,
},
"red-14": {
type: "observation",
entityId: "redShip",
latitude: 50.428207,
longitude: 0.717581,
time: 1746540000000,
},
"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,
},
"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,
},
"green-0": {
type: "observation",
entityId: "greenShip",
latitude: 49.642166,
longitude: -0.206432,
time: 1746489600000,
},
"green-1": {
type: "observation",
entityId: "greenShip",
latitude: 49.72148,
longitude: -0.045392,
time: 1746493200000,
},
"green-2": {
type: "observation",
entityId: "greenShip",
latitude: 49.773523,
longitude: 0.094019,
time: 1746496800000,
},
"green-3": {
type: "observation",
entityId: "greenShip",
latitude: 49.812568,
longitude: 0.246296,
time: 1746500400000,
},
"green-4": {
type: "observation",
entityId: "greenShip",
latitude: 49.89297,
longitude: 0.393587,
time: 1746504000000,
},
"green-5": {
type: "observation",
entityId: "greenShip",
latitude: 49.922868,
longitude: 0.517232,
time: 1746507600000,
},
"green-6": {
type: "observation",
entityId: "greenShip",
latitude: 50.015095,
longitude: 0.678897,
time: 1746511200000,
},
"green-7": {
type: "observation",
entityId: "greenShip",
latitude: 50.0724,
longitude: 0.813281,
time: 1746514800000,
},
"green-8": {
type: "observation",
entityId: "greenShip",
latitude: 50.130035,
longitude: 0.976137,
time: 1746518400000,
},
"green-9": {
type: "observation",
entityId: "greenShip",
latitude: 50.177675,
longitude: 1.110818,
time: 1746522000000,
},
"green-10": {
type: "observation",
entityId: "greenShip",
latitude: 50.242837,
longitude: 1.146687,
time: 1746525600000,
},
"green-11": {
type: "observation",
entityId: "greenShip",
latitude: 50.336519,
longitude: 1.199466,
time: 1746529200000,
},
"green-12": {
type: "observation",
entityId: "greenShip",
latitude: 50.396971,
longitude: 1.248527,
time: 1746532800000,
},
"green-13": {
type: "observation",
entityId: "greenShip",
latitude: 50.493277,
longitude: 1.311625,
time: 1746536400000,
},
"green-14": {
type: "observation",
entityId: "greenShip",
latitude: 50.589783,
longitude: 1.326871,
time: 1746540000000,
},
"green-15": {
type: "observation",
entityId: "greenShip",
latitude: 50.668123,
longitude: 1.401063,
time: 1746543600000,
},
"green-16": {
type: "observation",
entityId: "greenShip",
latitude: 50.746436,
longitude: 1.422752,
time: 1746547200000,
},
"green-17": {
type: "observation",
entityId: "greenShip",
latitude: 50.826394,
longitude: 1.484131,
time: 1746550800000,
},
"green-18": {
type: "observation",
entityId: "greenShip",
latitude: 50.893871,
longitude: 1.529005,
time: 1746554400000,
},
"green-19": {
type: "observation",
entityId: "greenShip",
latitude: 50.967241,
longitude: 1.67732,
time: 1746558000000,
},
"green-20": {
type: "observation",
entityId: "greenShip",
latitude: 51.013555,
longitude: 1.84518,
time: 1746561600000,
},
"green-21": {
type: "observation",
entityId: "greenShip",
latitude: 51.086254,
longitude: 2.040142,
time: 1746565200000,
},
"green-22": {
type: "observation",
entityId: "greenShip",
latitude: 51.174896,
longitude: 2.184954,
time: 1746568800000,
},
"green-23": {
type: "observation",
entityId: "greenShip",
latitude: 51.239722,
longitude: 2.367642,
time: 1746572400000,
},
"green-24": {
type: "observation",
entityId: "greenShip",
latitude: 51.291813,
longitude: 2.526876,
time: 1746576000000,
},
"green-25": {
type: "observation",
entityId: "greenShip",
latitude: 51.368212,
longitude: 2.66567,
time: 1746579600000,
},
"green-26": {
type: "observation",
entityId: "greenShip",
latitude: 51.438635,
longitude: 2.857788,
time: 1746583200000,
},
"green-27": {
type: "observation",
entityId: "greenShip",
latitude: 51.511591,
longitude: 3.003932,
time: 1746586800000,
},
"green-28": {
type: "observation",
entityId: "greenShip",
latitude: 51.573699,
longitude: 3.11906,
time: 1746590400000,
},
"green-29": {
type: "observation",
entityId: "greenShip",
latitude: 51.660869,
longitude: 3.197849,
time: 1746594000000,
},
"green-30": {
type: "observation",
entityId: "greenShip",
latitude: 51.728586,
longitude: 3.320669,
time: 1746597600000,
},
"green-31": {
type: "observation",
entityId: "greenShip",
latitude: 51.828897,
longitude: 3.432333,
time: 1746601200000,
},
"green-32": {
type: "observation",
entityId: "greenShip",
latitude: 51.902916,
longitude: 3.548628,
time: 1746604800000,
},
"green-33": {
type: "observation",
entityId: "greenShip",
latitude: 51.965803,
longitude: 3.648003,
time: 1746608400000,
},
"green-34": {
type: "observation",
entityId: "greenShip",
latitude: 52.045515,
longitude: 3.761248,
time: 1746612000000,
},
"green-35": {
type: "observation",
entityId: "greenShip",
latitude: 52.135806,
longitude: 3.87378,
time: 1746615600000,
},
"green-36": {
type: "observation",
entityId: "greenShip",
latitude: 52.215531,
longitude: 3.963111,
time: 1746619200000,
},
},
};
function makePolygon(y, x, dx) {
const dy = Math.cos((y * Math.PI) / 180) * dx;
return [
[x + dx, y],
[x, y + dy],
[x - dx, y],
[x, y - dy],
[x + dx, y],
];
}
const londonCoordinates = makePolygon(51.5, -0.13, 0.7);
const cambridgeCoordinates = makePolygon(52.2, 0.12, 0.4);
const oxfordCoordinates = makePolygon(51.75, -1.26, 0.4);
export const geojsonData = {
type: "FeatureCollection",
features: [
{
type: "Feature",
id: "London",
geometry: {
type: "Polygon",
coordinates: [londonCoordinates],
},
properties: {
color: "rgba(255,0,0,0.6)",
},
},
{
type: "Feature",
id: "Cambridge",
geometry: {
type: "Polygon",
coordinates: [cambridgeCoordinates],
},
properties: {
color: "rgba(0,255,0,0.6)",
},
},
{
type: "Feature",
id: "Oxford",
geometry: {
type: "Polygon",
coordinates: [oxfordCoordinates],
},
properties: {
color: "rgba(0,255,255,0.6)",
},
},
],
};
const shipsNetworkData = Object.fromEntries(
Object.entries(observationsData.entities).map(([shipId, { color }]) => [
shipId,
{
type: "node",
color: "#101010",
size: 10,
border: { width: 2, color },
image: { url: "/public/images/icons/ci/yacht.svg", color },
},
])
);
export const networkData = {
...shipsNetworkData,
cardiff: {
type: "node",
latitude: 51.48,
longitude: -3.17,
color: "#2471a3",
label: [
{
text: "Cardiff",
backgroundColor: "#566573",
},
],
},
edinburgh: {
type: "node",
latitude: 55.95,
longitude: -3.19,
color: "#2471a3",
label: [
{
text: "Edinburgh",
backgroundColor: "#566573",
},
],
},
alice: {
type: "node",
color: "#2471a3",
label: [
{
text: "Alice",
backgroundColor: "#566573",
},
],
},
bob: {
type: "node",
color: "#2471a3",
label: [
{
text: "Bob",
backgroundColor: "#566573",
},
],
},
link1: {
type: "link",
id1: "edinburgh",
id2: "cardiff",
color: "#2471a3",
},
link2: {
type: "link",
id1: "alice",
id2: "edinburgh",
color: "#2471a3",
},
link3: {
type: "link",
id1: "bob",
id2: "cardiff",
color: "#2471a3",
},
}; <!doctype html>
<html>
<body>
<div style="height: 100%; display: flex; flex-direction: column; max-height: 100%">
<div style="display: flex; flex: 1 0 auto; box-sizing: border-box; max-height: 100%">
<div id="mw" style="flex: 2 0 50%"></div>
<div class="tab-panel-container">
<div style="display: flex">
<button id="last-event-tab" class="tab tab--active">Event Details</button>
<button id="history-tab" class="tab">History</button>
<button id="filter-events-tab" class="tab">Filter Events</button>
</div>
<div id="last-event-panel" class="tab-panel tab-panel--active">
<h3 class="header--plain"> </h3>
<pre class="json-block">{}</pre>
</div>
<div id="history-panel" class="tab-panel" style="flex-wrap: nowrap; align-items: center">
<button id="clear-event-list" class="button button--small" style="flex: 0 0 auto">
clear
</button>
<ul id="event-list" class="event-list"></ul>
</div>
<div id="filter-events-panel" class="tab-panel" style="flex-wrap: nowrap">
<div class="filter-buttons">
<button id="select-all" class="button button--small">select all</button>
<button id="deselect-all" class="button button--small">deselect all</button>
</div>
<div class="event-filter-list">
<label class="event-label">
<input checked="true" type="checkbox" data-event-name="click" />click
</label>
<label class="event-label">
<input checked="true" type="checkbox" data-event-name="drag-start" />drag-start
</label>
<label class="event-label">
<input checked="true" type="checkbox" data-event-name="drag-move" />drag-move
</label>
<label class="event-label">
<input checked="true" type="checkbox" data-event-name="drag-end" />drag-end
</label>
<label class="event-label">
<input checked="true" type="checkbox" data-event-name="hover" />hover
</label>
<label class="event-label">
<input checked="true" type="checkbox" data-event-name="load" />load
</label>
<label class="event-label">
<input checked="true" type="checkbox" data-event-name="view-change" />view-change
</label>
</div>
</div>
</div>
</div>
</div>
<script type="module" src="./code.js"></script>
</body>
</html> import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import { MapWeave } from "mapweave/react/mapbox";
import { GeoJsonLayer, NetworkLayer, ObservationsLayer } from "mapweave/react/layers";
import { networkData, geojsonData, observationsData } 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: {
// These options link the network layer icons to the observed entities
networkLayerId,
currentTime: startTime,
},
individual: {
autoRange: { min: 0 },
minimumRadiusMeters: 1000,
},
};
function FilterEvents({ changeHandler, selectedEvents }) {
return (
<div className="event-filter-list">
{Object.keys(eventMap).map((propName) => (
<label className="event-label" style={{ width: "265px" }} key={propName}>
<input
onChange={() => changeHandler(propName)}
checked={selectedEvents[propName]}
type="checkbox"
/>
{propName}
</label>
))}
</div>
);
}
function EventList({ events, handleClick, displayedEventIndex }) {
return (
<ul className="event-list">
{events.map((event, eventIdx) => (
<li
key={eventIdx}
className={`list-item${displayedEventIndex === eventIdx ? "list-item--active" : ""}`}
onClick={() => handleClick(eventIdx)}
>
{event.type}
</li>
))}
</ul>
);
}
function TabPanels({ tabs, setSelectedTab, selectedTab }) {
return (
<div className="tab-panel-container">
<div style={{ display: "flex" }}>
{tabs.map((tab) => (
<button
onClick={() => setSelectedTab(tab.id)}
className={`tab${selectedTab === tab.id ? "tab--active" : ""}`}
key={tab.id}
>
{tab.title}
</button>
))}
</div>
{tabs.map((tab) => (
<div
key={tab.id}
style={tab.panelStyle}
className={`tab-panel${selectedTab === tab.id ? "tab-panel--active" : ""}`}
>
{tab.panel}
</div>
))}
</div>
);
}
const eventMap = {
onClick: true,
onDragEnd: true,
onDragMove: true,
onDragStart: true,
onHover: true,
onLoad: true,
onViewChange: true,
};
function stringifyDetails(eventDetails) {
function replacer(key, value) {
// Hide private fields
if (key.startsWith("_")) {
return undefined;
}
// Show the layer id instead of the full layer object
if (key === "layer" && value && value.id !== undefined) {
return { id: value.id };
}
return value;
}
return eventDetails ? JSON.stringify(eventDetails, replacer, 2) : "";
}
function Demo() {
const [eventList, setEventList] = useState([]);
const [selectedTab, setSelectedTab] = useState("event-details");
const [selectedEvents, setSelectedEvents] = useState({
...eventMap,
});
const [displayedEventIndex, setDisplayedEventIndex] = useState(0);
const displayedEvent = eventList[displayedEventIndex];
function genericEventHandler(propName, event) {
if (selectedEvents[propName]) {
setDisplayedEventIndex(0);
setEventList((prevEventList) => [{ type: propName, info: event }, ...prevEventList]);
}
}
const eventDetailsPanel = (
<>
<h3 className="header--plain">{displayedEvent ? displayedEvent.type : <br />}</h3>
<pre className="json-block">{}</pre>
</>
);
const historyPanel = (
<>
<button
className="button button--small"
style={{ flex: "0 0 auto" }}
onClick={() => setEventList([])}
>
clear
</button>
<EventList
events={eventList}
handleClick={(idx) => setDisplayedEventIndex(idx)}
displayedEventIndex={displayedEventIndex}
/>
</>
);
const filterEventsPanel = (
<>
<div className="filter-buttons">
<button className="button button--small" onClick={() => setSelectedEvents(eventMap)}>
select all
</button>
<button className="button button--small" onClick={() => setSelectedEvents({})}>
deselect all
</button>
</div>
<FilterEvents
changeHandler={(propName) => {
setSelectedEvents({
...selectedEvents,
[propName]: !selectedEvents[propName],
});
}}
selectedEvents={selectedEvents}
/>
</>
);
return (
<div style={{ height: "100%", display: "flex", flexDirection: "column", maxHeight: "100%" }}>
<div
style={{
display: "flex",
flex: "1 0 auto",
boxSizing: "border-box",
maxHeight: "100%",
}}
>
<MapWeave
options={mapWeaveOptions}
style={{ flex: "2 0 50%" }}
onClick={(event) => genericEventHandler("onClick", event)}
onDragEnd={(event) => genericEventHandler("onDragEnd", event)}
onDragMove={(event) => genericEventHandler("onDragMove", event)}
onDragStart={(event) => genericEventHandler("onDragStart", event)}
onHover={(event) => genericEventHandler("onHover", event)}
onLoad={(event) => genericEventHandler("onLoad", event)}
onViewChange={(event) => genericEventHandler("onViewChange", event)}
>
<GeoJsonLayer data={geojsonData} />
<ObservationsLayer data={observationsData} options={observationsLayerOptions} />
<NetworkLayer data={networkData} id={networkLayerId} />
</MapWeave>
<TabPanels
tabs={[
{
title: "Event Details",
id: "event-details",
panel: eventDetailsPanel,
},
{
title: "History",
id: "event-history",
panelStyle: { flexWrap: "nowrap", alignItems: "center" },
panel: historyPanel,
},
{
title: "Filter Events",
id: "filter-events",
panelStyle: { flexWrap: "nowrap" },
panel: filterEventsPanel,
},
]}
setSelectedTab={setSelectedTab}
selectedTab={selectedTab}
/>
</div>
</div>
);
}
const root = createRoot(document.getElementById("mw"));
root.render(<Demo />); export const observationsData = {
entities: {
blueShip: {
color: "rgb(83, 131, 236)",
},
redShip: {
color: "rgb(216, 81, 64)",
},
yellowShip: {
color: "rgb(241, 191, 66)",
},
greenShip: {
color: "rgb(88, 166, 92)",
},
},
observations: {
"blue-0": {
type: "observation",
entityId: "blueShip",
latitude: 54.578355,
longitude: -5.197542,
time: 1746489600000,
},
"blue-1": {
type: "observation",
entityId: "blueShip",
latitude: 54.406994,
longitude: -5.210292,
time: 1746493200000,
},
"blue-2": {
type: "observation",
entityId: "blueShip",
latitude: 54.272794,
longitude: -5.208974,
time: 1746496800000,
},
"blue-3": {
type: "observation",
entityId: "blueShip",
latitude: 54.142754,
longitude: -5.184721,
time: 1746500400000,
},
"blue-4": {
type: "observation",
entityId: "blueShip",
latitude: 53.97328,
longitude: -5.185769,
time: 1746504000000,
},
"blue-5": {
type: "observation",
entityId: "blueShip",
latitude: 53.837737,
longitude: -5.164967,
time: 1746507600000,
},
"blue-6": {
type: "observation",
entityId: "blueShip",
latitude: 53.670558,
longitude: -5.192878,
time: 1746511200000,
},
"blue-7": {
type: "observation",
entityId: "blueShip",
latitude: 53.504643,
longitude: -5.186715,
time: 1746514800000,
},
"blue-8": {
type: "observation",
entityId: "blueShip",
latitude: 53.365212,
longitude: -5.17317,
time: 1746518400000,
},
"blue-9": {
type: "observation",
entityId: "blueShip",
latitude: 53.2161,
longitude: -5.162903,
time: 1746522000000,
},
"blue-10": {
type: "observation",
entityId: "blueShip",
latitude: 53.052743,
longitude: -5.226897,
time: 1746525600000,
},
"blue-11": {
type: "observation",
entityId: "blueShip",
latitude: 52.892953,
longitude: -5.333351,
time: 1746529200000,
},
"blue-12": {
type: "observation",
entityId: "blueShip",
latitude: 52.711297,
longitude: -5.375885,
time: 1746532800000,
},
"blue-13": {
type: "observation",
entityId: "blueShip",
latitude: 52.568214,
longitude: -5.457204,
time: 1746536400000,
},
"blue-14": {
type: "observation",
entityId: "blueShip",
latitude: 52.409118,
longitude: -5.529224,
time: 1746540000000,
},
"blue-15": {
type: "observation",
entityId: "blueShip",
latitude: 52.242918,
longitude: -5.60549,
time: 1746543600000,
},
"blue-16": {
type: "observation",
entityId: "blueShip",
latitude: 52.071092,
longitude: -5.692136,
time: 1746547200000,
},
"blue-17": {
type: "observation",
entityId: "blueShip",
latitude: 51.899728,
longitude: -5.787732,
time: 1746550800000,
},
"blue-18": {
type: "observation",
entityId: "blueShip",
latitude: 51.739952,
longitude: -5.85027,
time: 1746554400000,
},
"blue-19": {
type: "observation",
entityId: "blueShip",
latitude: 51.602765,
longitude: -5.974733,
time: 1746558000000,
},
"blue-20": {
type: "observation",
entityId: "blueShip",
latitude: 51.474164,
longitude: -6.114349,
time: 1746561600000,
},
"blue-21": {
type: "observation",
entityId: "blueShip",
latitude: 51.362769,
longitude: -6.264626,
time: 1746565200000,
},
"blue-22": {
type: "observation",
entityId: "blueShip",
latitude: 51.204582,
longitude: -6.360486,
time: 1746568800000,
},
"blue-23": {
type: "observation",
entityId: "blueShip",
latitude: 51.084279,
longitude: -6.526525,
time: 1746572400000,
},
"blue-24": {
type: "observation",
entityId: "blueShip",
latitude: 50.941434,
longitude: -6.627714,
time: 1746576000000,
},
"blue-25": {
type: "observation",
entityId: "blueShip",
latitude: 50.815822,
longitude: -6.768253,
time: 1746579600000,
},
"blue-26": {
type: "observation",
entityId: "blueShip",
latitude: 50.68009,
longitude: -6.922329,
time: 1746583200000,
},
"blue-27": {
type: "observation",
entityId: "blueShip",
latitude: 50.56413,
longitude: -7.037884,
time: 1746586800000,
},
"blue-28": {
type: "observation",
entityId: "blueShip",
latitude: 50.406445,
longitude: -7.036782,
time: 1746590400000,
},
"blue-29": {
type: "observation",
entityId: "blueShip",
latitude: 50.247185,
longitude: -7.004507,
time: 1746594000000,
},
"blue-30": {
type: "observation",
entityId: "blueShip",
latitude: 50.08487,
longitude: -7.014869,
time: 1746597600000,
},
"blue-31": {
type: "observation",
entityId: "blueShip",
latitude: 49.937541,
longitude: -6.993953,
time: 1746601200000,
},
"blue-32": {
type: "observation",
entityId: "blueShip",
latitude: 49.784533,
longitude: -6.984443,
time: 1746604800000,
},
"blue-33": {
type: "observation",
entityId: "blueShip",
latitude: 49.639579,
longitude: -6.960981,
time: 1746608400000,
},
"blue-34": {
type: "observation",
entityId: "blueShip",
latitude: 49.467846,
longitude: -6.961437,
time: 1746612000000,
},
"blue-35": {
type: "observation",
entityId: "blueShip",
latitude: 49.32475,
longitude: -6.92981,
time: 1746615600000,
},
"blue-36": {
type: "observation",
entityId: "blueShip",
latitude: 49.152295,
longitude: -6.93082,
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-6": {
type: "observation",
entityId: "redShip",
latitude: 51.418045,
longitude: 2.244322,
time: 1746511200000,
},
"red-7": {
type: "observation",
entityId: "redShip",
latitude: 51.263755,
longitude: 1.993267,
time: 1746514800000,
},
"red-8": {
type: "observation",
entityId: "redShip",
latitude: 51.140054,
longitude: 1.762104,
time: 1746518400000,
},
"red-9": {
type: "observation",
entityId: "redShip",
latitude: 50.971223,
longitude: 1.516238,
time: 1746522000000,
},
"red-10": {
type: "observation",
entityId: "redShip",
latitude: 50.852823,
longitude: 1.357977,
time: 1746525600000,
},
"red-11": {
type: "observation",
entityId: "redShip",
latitude: 50.741735,
longitude: 1.215997,
time: 1746529200000,
},
"red-12": {
type: "observation",
entityId: "redShip",
latitude: 50.631068,
longitude: 1.037502,
time: 1746532800000,
},
"red-13": {
type: "observation",
entityId: "redShip",
latitude: 50.53398,
longitude: 0.888554,
time: 1746536400000,
},
"red-14": {
type: "observation",
entityId: "redShip",
latitude: 50.428207,
longitude: 0.717581,
time: 1746540000000,
},
"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,
},
"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,
},
"green-0": {
type: "observation",
entityId: "greenShip",
latitude: 49.642166,
longitude: -0.206432,
time: 1746489600000,
},
"green-1": {
type: "observation",
entityId: "greenShip",
latitude: 49.72148,
longitude: -0.045392,
time: 1746493200000,
},
"green-2": {
type: "observation",
entityId: "greenShip",
latitude: 49.773523,
longitude: 0.094019,
time: 1746496800000,
},
"green-3": {
type: "observation",
entityId: "greenShip",
latitude: 49.812568,
longitude: 0.246296,
time: 1746500400000,
},
"green-4": {
type: "observation",
entityId: "greenShip",
latitude: 49.89297,
longitude: 0.393587,
time: 1746504000000,
},
"green-5": {
type: "observation",
entityId: "greenShip",
latitude: 49.922868,
longitude: 0.517232,
time: 1746507600000,
},
"green-6": {
type: "observation",
entityId: "greenShip",
latitude: 50.015095,
longitude: 0.678897,
time: 1746511200000,
},
"green-7": {
type: "observation",
entityId: "greenShip",
latitude: 50.0724,
longitude: 0.813281,
time: 1746514800000,
},
"green-8": {
type: "observation",
entityId: "greenShip",
latitude: 50.130035,
longitude: 0.976137,
time: 1746518400000,
},
"green-9": {
type: "observation",
entityId: "greenShip",
latitude: 50.177675,
longitude: 1.110818,
time: 1746522000000,
},
"green-10": {
type: "observation",
entityId: "greenShip",
latitude: 50.242837,
longitude: 1.146687,
time: 1746525600000,
},
"green-11": {
type: "observation",
entityId: "greenShip",
latitude: 50.336519,
longitude: 1.199466,
time: 1746529200000,
},
"green-12": {
type: "observation",
entityId: "greenShip",
latitude: 50.396971,
longitude: 1.248527,
time: 1746532800000,
},
"green-13": {
type: "observation",
entityId: "greenShip",
latitude: 50.493277,
longitude: 1.311625,
time: 1746536400000,
},
"green-14": {
type: "observation",
entityId: "greenShip",
latitude: 50.589783,
longitude: 1.326871,
time: 1746540000000,
},
"green-15": {
type: "observation",
entityId: "greenShip",
latitude: 50.668123,
longitude: 1.401063,
time: 1746543600000,
},
"green-16": {
type: "observation",
entityId: "greenShip",
latitude: 50.746436,
longitude: 1.422752,
time: 1746547200000,
},
"green-17": {
type: "observation",
entityId: "greenShip",
latitude: 50.826394,
longitude: 1.484131,
time: 1746550800000,
},
"green-18": {
type: "observation",
entityId: "greenShip",
latitude: 50.893871,
longitude: 1.529005,
time: 1746554400000,
},
"green-19": {
type: "observation",
entityId: "greenShip",
latitude: 50.967241,
longitude: 1.67732,
time: 1746558000000,
},
"green-20": {
type: "observation",
entityId: "greenShip",
latitude: 51.013555,
longitude: 1.84518,
time: 1746561600000,
},
"green-21": {
type: "observation",
entityId: "greenShip",
latitude: 51.086254,
longitude: 2.040142,
time: 1746565200000,
},
"green-22": {
type: "observation",
entityId: "greenShip",
latitude: 51.174896,
longitude: 2.184954,
time: 1746568800000,
},
"green-23": {
type: "observation",
entityId: "greenShip",
latitude: 51.239722,
longitude: 2.367642,
time: 1746572400000,
},
"green-24": {
type: "observation",
entityId: "greenShip",
latitude: 51.291813,
longitude: 2.526876,
time: 1746576000000,
},
"green-25": {
type: "observation",
entityId: "greenShip",
latitude: 51.368212,
longitude: 2.66567,
time: 1746579600000,
},
"green-26": {
type: "observation",
entityId: "greenShip",
latitude: 51.438635,
longitude: 2.857788,
time: 1746583200000,
},
"green-27": {
type: "observation",
entityId: "greenShip",
latitude: 51.511591,
longitude: 3.003932,
time: 1746586800000,
},
"green-28": {
type: "observation",
entityId: "greenShip",
latitude: 51.573699,
longitude: 3.11906,
time: 1746590400000,
},
"green-29": {
type: "observation",
entityId: "greenShip",
latitude: 51.660869,
longitude: 3.197849,
time: 1746594000000,
},
"green-30": {
type: "observation",
entityId: "greenShip",
latitude: 51.728586,
longitude: 3.320669,
time: 1746597600000,
},
"green-31": {
type: "observation",
entityId: "greenShip",
latitude: 51.828897,
longitude: 3.432333,
time: 1746601200000,
},
"green-32": {
type: "observation",
entityId: "greenShip",
latitude: 51.902916,
longitude: 3.548628,
time: 1746604800000,
},
"green-33": {
type: "observation",
entityId: "greenShip",
latitude: 51.965803,
longitude: 3.648003,
time: 1746608400000,
},
"green-34": {
type: "observation",
entityId: "greenShip",
latitude: 52.045515,
longitude: 3.761248,
time: 1746612000000,
},
"green-35": {
type: "observation",
entityId: "greenShip",
latitude: 52.135806,
longitude: 3.87378,
time: 1746615600000,
},
"green-36": {
type: "observation",
entityId: "greenShip",
latitude: 52.215531,
longitude: 3.963111,
time: 1746619200000,
},
},
};
function makePolygon(y, x, dx) {
const dy = Math.cos((y * Math.PI) / 180) * dx;
return [
[x + dx, y],
[x, y + dy],
[x - dx, y],
[x, y - dy],
[x + dx, y],
];
}
const londonCoordinates = makePolygon(51.5, -0.13, 0.7);
const cambridgeCoordinates = makePolygon(52.2, 0.12, 0.4);
const oxfordCoordinates = makePolygon(51.75, -1.26, 0.4);
export const geojsonData = {
type: "FeatureCollection",
features: [
{
type: "Feature",
id: "London",
geometry: {
type: "Polygon",
coordinates: [londonCoordinates],
},
properties: {
color: "rgba(255,0,0,0.6)",
},
},
{
type: "Feature",
id: "Cambridge",
geometry: {
type: "Polygon",
coordinates: [cambridgeCoordinates],
},
properties: {
color: "rgba(0,255,0,0.6)",
},
},
{
type: "Feature",
id: "Oxford",
geometry: {
type: "Polygon",
coordinates: [oxfordCoordinates],
},
properties: {
color: "rgba(0,255,255,0.6)",
},
},
],
};
const shipsNetworkData = Object.fromEntries(
Object.entries(observationsData.entities).map(([shipId, { color }]) => [
shipId,
{
type: "node",
color: "#101010",
size: 10,
border: { width: 2, color },
image: { url: "/public/images/icons/ci/yacht.svg", color },
},
])
);
export const networkData = {
...shipsNetworkData,
cardiff: {
type: "node",
latitude: 51.48,
longitude: -3.17,
color: "#2471a3",
label: [
{
text: "Cardiff",
backgroundColor: "#566573",
},
],
},
edinburgh: {
type: "node",
latitude: 55.95,
longitude: -3.19,
color: "#2471a3",
label: [
{
text: "Edinburgh",
backgroundColor: "#566573",
},
],
},
alice: {
type: "node",
color: "#2471a3",
label: [
{
text: "Alice",
backgroundColor: "#566573",
},
],
},
bob: {
type: "node",
color: "#2471a3",
label: [
{
text: "Bob",
backgroundColor: "#566573",
},
],
},
link1: {
type: "link",
id1: "edinburgh",
id2: "cardiff",
color: "#2471a3",
},
link2: {
type: "link",
id1: "alice",
id2: "edinburgh",
color: "#2471a3",
},
link3: {
type: "link",
id1: "bob",
id2: "cardiff",
color: "#2471a3",
},
}; <!doctype html>
<html>
<body>
<div id="mw"></div>
<script type="module" src="./code.jsx"></script>
</body>
</html>