Add Multiple Geometries from One GeoJSON Source in Maptoolkit Maps JS
A single GeoJSON source in Maptoolkit Maps JS can contain a mix of geometry types, and you can add multiple layers that each reference the same source with a different geometry filter. This avoids duplicating data and keeps your source management simple. Use this pattern when your dataset contains related features of different types, such as a network of roads, intersections, and service areas all stored in one file.
const API_KEY = 'YOUR_API_KEY';
const map = new maptoolkit.Map({
container: 'map',
apiKey: API_KEY,
style: `https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=${API_KEY}`,
center: [12.0, 47.5],
zoom: 7,
attributionControl: { compact: false }
});
map.addControl(new maptoolkit.NavigationControl(), 'top-right');
const geojson = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
geometry: { type: 'Polygon', coordinates: [[[10.5, 47.0], [12.5, 47.0], [12.5, 48.0], [10.5, 48.0], [10.5, 47.0]]] },
properties: { type: 'region' }
},
{
type: 'Feature',
geometry: { type: 'LineString', coordinates: [[11.39085, 47.27574], [13.0550, 47.8095], [16.3738, 48.2082]] },
properties: { type: 'route' }
},
{
type: 'Feature',
geometry: { type: 'Point', coordinates: [11.39085, 47.27574] },
properties: { type: 'city', name: 'Innsbruck' }
},
{
type: 'Feature',
geometry: { type: 'Point', coordinates: [16.3738, 48.2082] },
properties: { type: 'city', name: 'Vienna' }
}
]
};
map.on('load', () => {
map.addSource('mixed', { type: 'geojson', data: geojson });
map.addLayer({ id: 'polygon', type: 'fill', source: 'mixed',
filter: ['==', '$type', 'Polygon'],
paint: { 'fill-color': '#3887be', 'fill-opacity': 0.2 }
});
map.addLayer({ id: 'polygon-outline', type: 'line', source: 'mixed',
filter: ['==', '$type', 'Polygon'],
paint: { 'line-color': '#3887be', 'line-width': 2 }
});
map.addLayer({ id: 'line', type: 'line', source: 'mixed',
filter: ['==', '$type', 'LineString'],
paint: { 'line-color': '#ee8a65', 'line-width': 3 }
});
map.addLayer({ id: 'points', type: 'circle', source: 'mixed',
filter: ['==', '$type', 'Point'],
paint: { 'circle-radius': 8, 'circle-color': '#56b881', 'circle-stroke-width': 2, 'circle-stroke-color': '#fff' }
});
});<!DOCTYPE html>
<html lang="en">
<head>
<title>Add Multiple Geometries from One GeoJSON Source - Maptoolkit Maps JS</title>
<meta property="og:description" content="Render points, lines, and polygons from a single GeoJSON source using multiple layers." />
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://unpkg.com/@maptoolkit/maps@11.0.0-beta.3/dist/maptoolkit.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@maptoolkit/maps@11.0.0-beta.3/dist/maptoolkit.css" />
<style>
html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
#map { width: 100%; height: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
const API_KEY = 'YOUR_API_KEY';
const map = new maptoolkit.Map({
container: 'map',
apiKey: API_KEY,
style: `https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=${API_KEY}`,
center: [12.0, 47.5],
zoom: 7,
attributionControl: { compact: false }
});
map.addControl(new maptoolkit.NavigationControl(), 'top-right');
const geojson = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
geometry: { type: 'Polygon', coordinates: [[[10.5, 47.0], [12.5, 47.0], [12.5, 48.0], [10.5, 48.0], [10.5, 47.0]]] },
properties: { type: 'region' }
},
{
type: 'Feature',
geometry: { type: 'LineString', coordinates: [[11.39085, 47.27574], [13.0550, 47.8095], [16.3738, 48.2082]] },
properties: { type: 'route' }
},
{
type: 'Feature',
geometry: { type: 'Point', coordinates: [11.39085, 47.27574] },
properties: { type: 'city', name: 'Innsbruck' }
},
{
type: 'Feature',
geometry: { type: 'Point', coordinates: [16.3738, 48.2082] },
properties: { type: 'city', name: 'Vienna' }
}
]
};
map.on('load', () => {
map.addSource('mixed', { type: 'geojson', data: geojson });
map.addLayer({ id: 'polygon', type: 'fill', source: 'mixed',
filter: ['==', '$type', 'Polygon'],
paint: { 'fill-color': '#3887be', 'fill-opacity': 0.2 }
});
map.addLayer({ id: 'polygon-outline', type: 'line', source: 'mixed',
filter: ['==', '$type', 'Polygon'],
paint: { 'line-color': '#3887be', 'line-width': 2 }
});
map.addLayer({ id: 'line', type: 'line', source: 'mixed',
filter: ['==', '$type', 'LineString'],
paint: { 'line-color': '#ee8a65', 'line-width': 3 }
});
map.addLayer({ id: 'points', type: 'circle', source: 'mixed',
filter: ['==', '$type', 'Point'],
paint: { 'circle-radius': 8, 'circle-color': '#56b881', 'circle-stroke-width': 2, 'circle-stroke-color': '#fff' }
});
});
</script>
</body>
</html>Use the prompt below with any LLM to get the same result. Make sure the Maptoolkit MCP server is connected first — check out AI Integration & MCP to get started.
How it works
One source, several layers. A FeatureCollection can mix polygons, lines and points, but a
layer draws exactly one geometry type, so a mixed collection needs a fill layer, a line
layer and a circle layer all pointing at the same source id.
Each layer uses filter to pick its own features, typically on a property such as type.
Without a filter, a fill layer over mixed data simply ignores the points and lines rather
than erroring, which is why nothing appears to happen.
Sharing one source is worth doing: the data is parsed and uploaded once, and setData
updates every layer at once.
Draw order follows the order you add layers, so add fills before lines before points or the polygons cover everything.
Next steps
With the three layer types up, the next step is usually making them behave as one thing: clicking any part of a feature opening the same popup, or hovering the polygon highlighting it too.
Filtering is the other direction. One source with a filter per layer scales to categories and toggles, which is how most “show me only X” interfaces are built without touching the data.