{{craftSnippets}}
Home Articles Plugins Starter theme Components on Github Gists About
  • Home
  • Articles
  • Creating map-based navigation for Craft CMS
Posted on Mar 29, 2020 by Piotr Pogorzelski

Creating map-based navigation for Craft CMS

SVG-based navigation on github gists
Using an SVG map divided by regions, you can create navigation, where each region is a link to an entry.
Table of contents:
  • SVG map
  • Control panel interface
  • Templating
  • How does it work?

In this article, I will describe how to create navigation using SVG map where each map region links to a specific entry. Links won't be hardcoded - the map will have an interface in the control panel that will allow admins to assign entries to specific regions.

SVG map #

We will use this map of USA as an example. You can find many SVG maps on wikipedia, and even more on amcharts website. Keep in mind however that these from amcharts are free for non-commercial projects only.

Each region of the SVG map is represented by path HTML element. It's important that these paths have some kind of HTML attribute representing their region - our example map uses id for that. For example, Texas path element has id TX, which corresponds to Texas ISO code - US-TX.

Control panel interface #

We will add links to the map using matrix field. Create a matrix field with handle mapLinks and define a single block. It will have two sub-fields, both set to required:

  • Entry field with handle linkEntry. Map region will link to this entry.
  • Text field with handle linkRegion. This field will hold map region code.

Using a text field for setting region code is the easiest solution. As an alternative, we might use dropdown field with regions list, or even Country select Field - if we are dealing with a map of the whole world.

We might also use another strategy. Instead of keeping all links in one place (within matrix field assigned to some entry or global), we can assign a field that will hold region code to specific entries. In our example, we will however use a matrix field approach.

Templating #

To add links to SVG map, we need to manipulate its HTML code - wrap path elements with links. We can achieve this by using Retcon plugin.

Here's Twig code that generates our map. Remember to also place map.svg file in proper directory so it can be included within our Twig component.

{# settings #}
{% set map = include('usa.svg') %}
{% set mapLinks = entry.mapLinks.all() %}

{# logic #}
{% set map = map|retconRemove('style') %}
{% set regionsUsed = [] %}
{% for link in mapLinks %}
	{% if link.linkRegion is not empty and link.linkEntry.exists() and link.linkRegion not in regionsUsed %}
		{% set regionsUsed = regionsUsed|merge([link.linkRegion]) %}
	    {% set linkRegion = link.linkRegion|upper %}
	    {% set linkUrl = link.linkEntry.one().url %}
	    {% set map = map|retconWrap( 'path#'~linkRegion, 'a#link-'~linkRegion ) %}
	    {% set map = map|retconAttr( 'a#link-'~linkRegion, { 'href' : linkUrl } ) %}
    {% endif %}
{% endfor %}

{# output #}
{{map|raw}}

How does it work? #

First, we load SVG file using include. SVG is just markup instead of a "real" image, so it can be treated like a template file. I decided to use include instead of svg funcition, because svg() namespaces all ID and class attributes within the markup, which could pose problems if we wanted to style our map. After loading map, we also set a collection of links defined in the control panel to mapLinks variable.

Most SVGs have their own styles defined within their own style tag. I decided to remove them using Retcon retconRemove filter - because I would rather keep all styles in the separate CSS file. Example CSS that would let us distinguish paths that are links from others, might look like this:

svg a path{
	fill: red;
}

After that, we define regionsUsed array and loop through the matrix blocks holding our map links. For each link, we wrap path element that has ID matching linkRegion region code set in the control panel. Region code is transformed into uppercase using upper filter, because IDs in our map are in capital letters. This might however not be the case for other maps.

For each for loop, we check if region code is defined, is entry that region is supposed to link to exists, and most importantly - if a region wasn't already used. If it wasn't, we insert region code into regionsUsed array, to make sure it won't be used again. It's important to perform this check - with duplicate regions, we would end up with links wrapped in other links. We cannot easily block usage of duplicate regions in the control panel, so make sure to add a warning in matrix field description: that in case of duplicate regions, only the first occurrence of the region will be used to create link.

Wrapping path with links is done using Retcon Wrap filter. Each link will have its own ID - the second param of Wrap filter is set to a#link-'~linkRegion, which generates a link with ID like link-TX. This ID of a link is used as a selector in the second Retcon filter, retconAttr - which adds proper href attribute to our generated link.

Finally, SVG map is passed through raw filter and outputted into the template. Without this filter, HTML code would be escaped and displayed as regular text. Using Retcon filters also works like using raw, but in case if matrix field being empty (and if you decided to not use retconRemove filter to remove styles), code inside for loop would not run and no Retcon filter would be used on SVG. That's why I decided to use raw filter - to ensure that even map without links would display correctly.


TAGS:
#twig component
If you want to get latest updates on Craft CMS tutorials and components, follow me on Twitter or subscribe to RSS feed.
Quick links for this article:
SVG-based navigation on github gists
Articles on blog:
  • Frontend testing for Craft CMS websites with Codeception and Cypress
  • Building reactive Craft Commerce product page with Sprig plugin
  • Dynamically generated PDF attachments for Freeform submissions
  • Using template hooks in Craft CMS
  • Alpine JS modal component for Craft CMS
  • Using template UI elements to extend Craft CMS control panel
  • Matrix within a Matrix - possible solutions for Craft CMS
  • Universal email template for Craft CMS
  • Creating attributes table from entry fields in Craft CMS
  • Namespacing forms in Craft CMS
  • Creating map-based navigation for Craft CMS
  • Placeholder image macro for Craft CMS
  • Building AJAX contact form with Craft CMS
  • Using incognito field plugin for Craft CMS
  • Email footer creator made with Craft CMS
  • Infinite scrolling and lazy loading with Craft CMS
  • Using Javascript in Twig templates with Craft CMS
  • Twig templating tips and tricks for Craft CMS
  • Basic SEO functionality for Craft CMS
  • Working with dates in Craft CMS templates
  • Working with SVG images in Craft CMS templates
  • Responsive and lazy-loaded youtube videos with Craft CMS
  • Debugging and inspecting Twig templates in Craft CMS
  • Creating article excerpts with Twig component in Craft CMS
  • Adding favicons to Craft CMS website
  • Truncating text with Twig macros in Craft CMS
  • Universal language switcher for Craft CMS
  • Read time macro for Craft CMS
  • Using attr() function to render HTML attributes in Craft CMS
  • Building dynamic, AJAX based pagination for Craft CMS
  • How to add Disqus comments to Craft CMS website
  • Ellipsis pagination component for Craft CMS
  • Converting email addresses into links using Twig macro
  • Breadcrumb created from URL for Craft CMS
  • Best developer-oriented Craft CMS plugins
  • Search autocomplete component for Craft CMS
  • RSS feed - template component for Craft CMS
  • Testing emails sent by Craft CMS using Mailtrap
  • Quick edit link - Twig component for Craft CMS
  • Filtering entries in control panel using Searchit plugin
  • Fetching routes into Twig templates in Craft CMS


Frontend testing for Craft CMS websites with Codeception and Cypress

Building reactive Craft Commerce product page with Sprig plugin

Dynamically generated PDF attachments for Freeform submissions

Using template hooks in Craft CMS

Alpine JS modal component for Craft CMS

Using template UI elements to extend Craft CMS control panel

Matrix within a Matrix - possible solutions for Craft CMS

Universal email template for Craft CMS

Copyright ©2023 Piotr Pogorzelski