Skip to content

Map of Areas ​

Show every zone, region or delivery area on a single map, each in its own colour with its name in a popup.

Three collection zones on one map in blue, green and orange, with a legend; Zone C has a hole cut out

The template ​

twig
{% set zones = craft.entries()
  .section('binZones')
  .zoneArea(':notempty:')
  .all() %}

{% set colours = ['#2563eb', '#16a34a', '#f59e0b', '#db2777', '#7c3aed'] %}

{# Merge each entry's shapes into one FeatureCollection, tagged with the entry's name and a colour #}
{% set features = [] %}
{% for zone in zones %}
  {% set colour = colours[loop.index0 % colours|length] %}
  {% set data = zone.zoneArea.getGeoJsonData() ?? {} %}
  {# Shapes can be a FeatureCollection, a single Feature or a bare geometry #}
  {% set zoneFeatures = data.type is not defined ? []
    : (data.type == 'FeatureCollection' ? data.features
    : (data.type == 'Feature' ? [data]
    : [{ type: 'Feature', geometry: data, properties: {} }])) %}
  {% for feature in zoneFeatures %}
    {% set features = features|merge([feature|merge({
      properties: (feature.properties ?? {})|merge({ name: zone.title, color: colour }),
    })]) %}
  {% endfor %}
{% endfor %}

{{ craft.geomaps.embed({
  id: 'zones-map',
  width: 900,
  height: 500,
  marker: false,
  geoJson: { type: 'FeatureCollection', features: features },
}) }}

<ul class="legend">
  {% for zone in zones %}
    <li>
      <span style="background: {{ colours[loop.index0 % colours|length] }}"></span>
      {{ zone.title }}
    </li>
  {% endfor %}
</ul>

The map zooms to fit all the shapes. marker: false hides the centre pin, because the map has no single location.

Styling shapes ​

Embedded maps style each shape from its properties, so authors can also set them in the field’s shape panel:

PropertyEffect
colorOutline and fill colour
strokeOutline colour (overrides color)
fillFill colour (overrides color)
weightLine width in pixels (default 2 for areas, 4 for lines)
name or titleShown in a popup when the shape is clicked

These work on both OpenStreetMap (Leaflet) and Google maps.

Using your own map library ​

For full control, pass the GeoJSON to Leaflet, MapLibre or OpenLayers yourself:

twig
<div id="areas" style="height: 500px"></div>

<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<script>
  const map = L.map('areas');
  L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '&copy; OpenStreetMap contributors',
  }).addTo(map);

  const layer = L.geoJSON({{ { type: 'FeatureCollection', features: features }|json_encode|raw }}, {
    style: (f) => ({ color: f.properties.color, weight: 2, fillOpacity: 0.25 }),
    onEachFeature: (f, l) => l.bindPopup(f.properties.name),
  }).addTo(map);

  map.fitBounds(layer.getBounds());
</script>

features is the list built in the template above.