Getting Started

This guide introduces you to the basic principles of building a map and helps you get up and running with MapWeave. We are going to embed MapWeave in an HTML page and add data and layers.

Creating an App

Firstly, you need to create a local app for the MapWeave component. You can create one with Vite which will be shown in this guide, or another build tool of your choice. If you have an existing app, move on to Installing MapWeave.

npm init vite@latest my-mapweave-app -- --template vanilla
yarn create vite my-mapweave-app --template vanilla
pnpm create vite my-mapweave-app --template vanilla
npm init vite@latest my-mapweave-app -- --template react
yarn create vite my-mapweave-app --template react
pnpm create vite my-mapweave-app --template react

Once this process has completed, you can start your app:

cd my-mapweave-app
npm install
npm run dev
cd my-mapweave-app
yarn
yarn dev
cd my-mapweave-app
pnpm install
pnpm run dev

By default, Vite runs a development server at http://localhost:5173.

Installing MapWeave

Download the latest version of MapWeave.

Download MapWeave

The download contains a package.json file referencing external dependencies as well as a pre-built set of bundled dependencies. See the dependencies page for more information.

Move the downloaded file into your project's root folder.

Then install the file from inside your project's root folder:

npm install file:your_downloaded_file_name.tgz
yarn add ./your_downloaded_file_name.tgz
pnpm install file:your_downloaded_file_name.tgz

Now we have a local app and MapWeave is installed.

Making an HTML Page

You need to replace the content in the Vite generated HTML and CSS files to add a <div> for the MapWeave component and style it appropriately.

Replace the content of index.html with the following code. It contains a <div> that has been assigned an id of "mw":

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="src/style.css" />
    <script type="module" src="src/main.js"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>MapWeave App</title>
  </head>
  <body>
    <div id="mw"></div>
  </body>
</html>

Then replace the content of src/style.css with these styles:

#mw {
  height: 100vh;
  position: relative;
  overflow: hidden;
}

body {
  margin: 0;
}

Replace the content of index.html with the following code. It contains a <div> that has been assigned an id of "mw":

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="src/index.css" />
    <script type="module" src="src/main.jsx"></script>
    <title>MapWeave App</title>
  </head>
  <body>
    <div id="mw"></div>
  </body>
</html>

Then replace the content of src/index.css with these styles:

#mw {
  height: 100vh;
  position: relative;
  overflow: hidden;
}

body {
  margin: 0;
}

Now we have an empty page and are ready to add the MapWeave component.

Adding a Map Adapter

MapWeave provides the option to use an adapter for a 3rd party map provider such as Mapbox or MapLibre.

Instructions for each adapter are shown below, you only need to follow the steps for the adapter you are using. Follow these steps exactly if you are creating a new app with Vite.

Ensure you check the terms and conditions of any 3rd party dependency you use.

Mapbox

Mapbox supports vector tiles and requires an access token.

Install the Mapbox package into your project folder as follows:

npm install mapbox-gl
yarn add mapbox-gl
pnpm install mapbox-gl

Next import MapWeave and the relevant css into src/main.js. Use the new MapWeave() constructor to create a new MapWeave instance. Assign it to the mw <div> we created in index.html with the container property and use options to add your Mapbox accessToken and specify a tileset with style. The tileset options can be found in the Mapbox styles API docs.

import { MapWeave } from 'mapweave/mapbox';
import 'mapbox-gl/dist/mapbox-gl.css';

const mapweave = new MapWeave({
  container: 'mw', // this is the id of the div in index.html
  options: {
    accessToken: 'YOUR_ACCESS_TOKEN_GOES_HERE', // add your Mapbox API key here
    style: 'mapbox://styles/mapbox/light-v11', // add your tileset link here
  },
});

Next import MapWeave and the relevant css into src/App.jsx. Create an App function and export it.

The App function must return a MapWeave component with the required Mapbox accessToken. Use the options prop to add your accessToken and specify a tileset with style. The tileset options can be found in the Mapbox styles API docs.

import { MapWeave } from 'mapweave/react/mapbox';
import 'mapbox-gl/dist/mapbox-gl.css';

const options = {
  accessToken: 'YOUR_ACCESS_TOKEN_GOES_HERE', // add your Mapbox API key here
  style: 'mapbox://styles/mapbox/light-v11', // add your tileset link here
};

function App() {
  return <MapWeave options={options} />;
}

export default App;

Import the App into src/main.jsx and render it to the mw div.

import { createRoot } from 'react-dom/client';
import App from './App';

const root = createRoot(document.getElementById('mw')); // this is the id of the div in index.html
root.render(<App />);

MapLibre

To use the MapLibre adapter, install the package into your project folder as follows:

npm install maplibre-gl
yarn add maplibre-gl
pnpm install maplibre-gl

Next, replace the code in src/main.js to import MapWeave and the relevant css. Use the new MapWeave() constructor to create a new MapWeave instance. Assign it to the mw <div> we created in index.html with the container property and specify a tileset with the style option. If no tileset is specified, MapLibre adapter uses default tiles. More information can be found in the MapLibre style spec.

import { MapWeave } from 'mapweave/maplibre';
import 'maplibre-gl/dist/maplibre-gl.css';

const mapweave = new MapWeave({
  container: 'mw', // this is the id of the div in index.html
  options: {
    style: 'https://tiles.openfreemap.org/styles/bright', // add your tileset link here
  },
});

Next import MapWeave and the relevant css into src/App.jsx. Create an App function to return the MapWeave component and export the function. Create an options object and use style to specify a tileset.

import { MapWeave } from 'mapweave/react/maplibre';
import 'maplibre-gl/dist/maplibre-gl.css';

const options = {
  style: 'https://tiles.openfreemap.org/styles/bright', // add your tileset link here
};

function App() {
  return <MapWeave options={options} />;
}

export default App;

Import the App into src/main.jsx and render it to the mw div.

import { createRoot } from 'react-dom/client';
import App from './App';

const root = createRoot(document.getElementById('mw')); // this is the id of the div in index.html
root.render(<App />);

Standalone

MapWeave can be used without any 3rd party basemap library to minimize dependencies. This approach supports raster tiles only.

Replace the code in src/main.js to import MapWeave, the TileLayer and the relevant css. Use the new MapWeave() constructor to create a new MapWeave instance and assign it to the mw <div> we created in index.html with the container property. Then create a new TileLayer() and add the link to your chosen map tiles to the data property. This example uses OpenStreetMap.

import { MapWeave } from 'mapweave/standalone';
import { TileLayer } from 'mapweave/layers';
import 'mapweave/mapweave.css';

const mapweave = new MapWeave({
  container: 'mw', // this is the id of the div in index.html
});

mapweave.addLayer(
  new TileLayer({
    data: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
  }),
);

Import MapWeave and the TileLayer into src/App.jsx. Create an App function to to return the MapWeave component with the TileLayer, including the link to your chosen tileset in the data property, and export the function.

import { MapWeave } from 'mapweave/react/standalone';
import { TileLayer } from 'mapweave/react/layers';
import 'mapweave/mapweave.css';

function App() {
  return (
    <MapWeave>
      <TileLayer data="https://tile.openstreetmap.org/{z}/{x}/{y}.png"></TileLayer>
    </MapWeave>
  );
}

export default App;

Import the App into src/main.jsx and render it to the mw div.

import { createRoot } from 'react-dom/client';
import App from './App';

const root = createRoot(document.getElementById('mw')); // this is the id of the div in index.html
root.render(<App />);

Adding Layers

MapWeave provides layers to add different kinds of data depending on the use case. You can use as many layers as you need. Layers are rendered in the order that they are specified, so the layer that is defined first will be rendered first.

The layers available are:

  • The Network Layer, which allows for the addition of a graph with either linked or unlinked nodes.
  • The Observations Layer, which allows entities to be tracked via locations and time.
  • The GeoJSON Layer, which allows geographical data to be added using the GeoJSON open standard.

By default, MapWeave will fit the map to the bounds of the visible loaded data. This behavior can be controlled with the fitOnFirstLoad option.

Network Layer

In this example car charging stations are fixed nodes (nodes that are at a specific location) and their owners are free nodes (nodes that do not have a location). The links show who owns which charging station.

First, import the NetworkLayer into the src/main.js file.

import { NetworkLayer } from 'mapweave/layers';

First, import the NetworkLayer into the src/App.jsx file.

import { NetworkLayer } from 'mapweave/react/layers';

Add meaning to the graph by defining some simple colors for the fixed and free nodes as well as link, text and label colors.

const linkColor = '#FD9067';
const textColor = '#F4F4F5';
const labelColor = '#6E7379';
const freeNodeColor = '#FD9067';
const fixedNodeColor = '#774299';

Add the charging stations data object.

The data object can be added directly into src/main.js or imported from a separate data file.

The data object can be added directly into src/App.jsx or imported from a separate data file.

Expand to see the charging stations object.
const chargingStations = {
  Hamilton: {
    // fixed node
    type: 'node',
    color: fixedNodeColor,
    latitude: 49.279516,
    longitude: -123.115166,
    label: {
      text: '775 Hamilton St',
      color: textColor,
      backgroundColor: labelColor,
    },
  },
  Easypark: {
    // free node
    type: 'node',
    color: freeNodeColor,
    label: {
      text: 'Easypark',
      color: textColor,
      backgroundColor: labelColor,
    },
  },
  Mainland: {
    // fixed node
    type: 'node',
    color: fixedNodeColor,
    latitude: 49.27684,
    longitude: -123.11887,
    label: {
      text: '959-979 Mainland St',
      color: textColor,
      backgroundColor: labelColor,
    },
  },
  Vancouver: {
    // free node
    type: 'node',
    color: freeNodeColor,
    label: {
      text: 'City of Vancouver',
      color: textColor,
      backgroundColor: labelColor,
    },
  },
  Beach: {
    // fixed node
    type: 'node',
    color: fixedNodeColor,
    latitude: 49.272594,
    longitude: -123.12836,
    label: {
      text: '456 Beach Crescent',
      color: textColor,
      backgroundColor: labelColor,
    },
  },
  Richards: {
    // fixed node
    type: 'node',
    color: fixedNodeColor,
    latitude: 49.279403,
    longitude: -123.118908,
    label: {
      text: '860 Richards St',
      color: textColor,
      backgroundColor: labelColor,
    },
  },
  Georgia: {
    // fixed node
    type: 'node',
    color: fixedNodeColor,
    latitude: 49.283672,
    longitude: -123.1173,
    label: {
      text: '701 W. Georgia St.',
      color: textColor,
      backgroundColor: labelColor,
    },
  },
  Granville: {
    // fixed node
    type: 'node',
    color: fixedNodeColor,
    latitude: 49.277692,
    longitude: -123.124668,
    label: {
      text: '1100 Granville St',
      color: textColor,
      backgroundColor: labelColor,
    },
  },
  BestWestern: {
    // free node
    type: 'node',
    color: freeNodeColor,
    label: {
      text: 'Best Western',
      color: textColor,
      backgroundColor: labelColor,
    },
  },
  link1: {
    type: 'link',
    color: linkColor,
    id1: 'Easypark',
    id2: 'Hamilton',
  },
  link2: {
    type: 'link',
    color: linkColor,
    id1: 'Vancouver',
    id2: 'Mainland',
  },
  link3: {
    type: 'link',
    color: linkColor,
    id1: 'Vancouver',
    id2: 'Beach',
  },
  link4: {
    type: 'link',
    color: linkColor,
    id1: 'Vancouver',
    id2: 'Richards',
  },
  link5: {
    type: 'link',
    color: linkColor,
    id1: 'Easypark',
    id2: 'Georgia',
  },
  link6: {
    type: 'link',
    color: linkColor,
    id1: 'BestWestern',
    id2: 'Granville',
  },
};

Finally, load the data into the NetworkLayer before calling fitBounds() to fit the map to the visible data.

mapweave.addLayer(
  new NetworkLayer({
    data: chargingStations,
  }),
);

mapweave.fitBounds();

Finally, load the data into the NetworkLayer.

function App() {
  return (
    <MapWeave options={options}>
      <NetworkLayer data={chargingStations} />
    </MapWeave>
  );
}

MapWeave with network layer data looks like this:

For more information about graphs, nodes and links, take a look at the Network Layer docs.

Observations Layer

The data passed to this layer takes the form of observations. An observation is a record of an entity, a moving object, being observed in a particular place at a particular time. Once observations have been loaded, MapWeave can generate trajectories showing the path taken by the entity between individual observations.

In this example, we are tracking a vehicle as it moves through the city. The observations record the timestamp and location of the vehicle.

First, import the ObservationsLayer into the src/main.js file.

import { ObservationsLayer } from 'mapweave/layers';

First, import the ObservationsLayer into the src/App.jsx file.

import { ObservationsLayer } from 'mapweave/react/layers';

Next, set a color for the observations.

const observationColor = '#774299';

Add the observations data object. The data object can be added directly into src/main.js or imported from a separate data file.

Add the observations data object. The data object can be added directly into src/App.jsx or imported from a separate data file.

Expand to see the vehicle observations object.
const vehicleObservations = {
  entities: { vehicle1: { color: observationColor } },
  observations: {
    vehicle1_1: {
      type: 'observation',
      entityId: 'vehicle1',
      latitude: 49.2827,
      longitude: -123.1207,
      time: new Date('2024-12-16T08:00:00'),
    },
    vehicle1_2: {
      type: 'observation',
      entityId: 'vehicle1',
      latitude: 49.2835,
      longitude: -123.1167,
      time: new Date('2024-12-16T08:05:00'),
    },
    vehicle1_3: {
      type: 'observation',
      entityId: 'vehicle1',
      latitude: 49.284,
      longitude: -123.1123,
      time: new Date('2024-12-16T08:10:00'),
    },
    vehicle1_4: {
      type: 'observation',
      entityId: 'vehicle1',
      latitude: 49.2832,
      longitude: -123.1085,
      time: new Date('2024-12-16T08:15:00'),
    },
    vehicle1_5: {
      type: 'observation',
      entityId: 'vehicle1',
      latitude: 49.2808,
      longitude: -123.106,
      time: new Date('2024-12-16T08:20:00'),
    },
  },
};

Load the observations data into a new ObservationsLayer and configure the ObservationsLayerOptions. Then call fitBounds() to fit the map to the visible data.

By default, MapWeave will connect any observations that are equal to or less than one minute apart into a trajectory. The observations in the data are five minutes apart so we need to set the trajectory maximumInterval to five minutes in milliseconds. Set radiusPixels to adjust the size of the dots for each observation.

mapweave.addLayer(
  new ObservationsLayer({
    data: vehicleObservations,
    options: {
      individual: { radiusPixels: 5 },
      trajectory: {
        maximumInterval: 60 * 5 * 1000,
      },
    },
  }),
);

mapweave.fitBounds();

Load the observations data into the ObservationsLayer and configure the ObservationsLayerOptions.

By default, MapWeave will connect any observations that are equal to or less than one minute apart into a trajectory. The observations in the data are five minutes apart so we need to set the trajectory maximumInterval to five minutes in milliseconds. Set radiusPixels to adjust the size of the dots for each observation.

const observationsOptions = {
  individual: { radiusPixels: 5 },
  trajectory: {
    maximumInterval: 60 * 5 * 1000,
  },
};

function App() {
  return (
    <MapWeave options={options}>
      <ObservationsLayer data={vehicleObservations} options={observationsOptions} />
    </MapWeave>
  );
}

The map then looks like this:

For more information, see the Observations Layer docs.

GeoJSON Layer

In this example, GeoJSON is used to highlight the downtown area of the city.

First, import the GeoJsonLayer into the src/main.js file.

import { GeoJsonLayer } from 'mapweave/layers';

First, import the GeoJsonLayer into the src/App.jsx file.

import { GeoJsonLayer } from 'mapweave/react/layers';

Set a color for the GeoJSON layer. Here an rgba value is used so the shaded area can be transparent.

const geoColor = 'rgba(253, 144, 103, 0.3)';

Create the GeoJSON data object.

The data object can be added directly into src/main.js or imported from a separate data file.

The data object can be added directly into src/App.jsx or imported from a separate data file.

Expand to see the Vancouver downtown object.
const vancouverDowntown = {
 type: "FeatureCollection",
 features: [
   {
     type: "Feature",
     geometry: {
       coordinates: [
         [
           [-123.112266, 49.290164],
           [-123.104240, 49.288166],
           [-123.099288, 49.289272],
           [-123.099998, 49.272750],
           [-123.101699, 49.272972],
           [-123.111076, 49.272926],
           [-123.114448, 49.271774],
           [-123.121162, 49.269538],
           [-123.129280, 49.269531],
           [-123.137680, 49.275318],
           [-123.132331, 49.276931],
           [-123.121093, 49.284366],
           [-123.136680, 49.294456],
           [-123.134689, 49.295810],
           [-123.122711, 49.291500],
           [-123.112266, 49.290164],
         ],
       ],
       type: "Polygon",
     },
     properties: { color: geoColor },
   },
 ],
};

Load that data into a new GeoJsonLayer and call fitBounds() to fit the map to the visible data.

mapweave.addLayer(
  new GeoJsonLayer({
    data: vancouverDowntown,
  }),
);

mapweave.fitBounds();

Load that data into the GeoJsonLayer.

function App() {
  return (
    <MapWeave options={options}>
      <GeoJsonLayer data={vancouverDowntown} />
    </MapWeave>
  );
}

MapWeave with GeoJSON layer data looks like this:

For more information, see the GeoJSON Layer docs.

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.