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 MapWeaveThe 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:
Network Gsg
Log in to view live examplesNetwork Gsg
Log in to view live examplesFor 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:
Observations Gsg
Log in to view live examplesObservations Gsg
Log in to view live examplesFor 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:
Geojson Gsg
Log in to view live examplesGeojson Gsg
Log in to view live examplesFor more information, see the GeoJSON Layer docs.