Leaflet JS Map

Have a question or a suggestion about a 3rd party addon module or plugin?
Let us know here.
Post Reply
howey
Forum Members
Forum Members
Posts: 158
Joined: Fri Sep 14, 2007 1:05 pm

Leaflet JS Map

Post by howey »

Hi

I looked in the forum and found a topic on this, but the topic was over 6 months old and shown as locked.

I have included an OpenStreet map in a website and looked at using Leaflet JS to add the locations etc. As there are over 25 locations and some may need to be added etc I though I would be able to use CGBlog with custom fields to create the information and then pass the data as a variable to the JS script.

My knowledge is limited but I set up a summary template to just output the custom fields with the longitude and latitude information.

Code: Select all

{foreach from=$items item=entry name=maps}

{if isset($entry->fields)}
  {foreach from=$entry->fields item='field'}
  {if $field->name == "location"}
            {capture name=siteloc assign=siteloc}{$field->value}{/capture}
  {/if}
  {/foreach}
{/if}

L.marker([{$siteloc}]).bindPopup("Some text").addTo(cities),

{/foreach}
This "prints" on the page OK using

Code: Select all

{capture name=mapviewx assign=mapview}{strip}{CGBlog summarytemplate=mapcs}{/strip}Variable{/capture}

then 

{$mapview}

This shows I have captured the information. However when I try to pass this variable into the Leaflet JS script the map disappears.

If I text the variable passing with straight text ie

Code: Select all

{content block="maptest" label="Map Test" wysiwyg="false" oneline="true" size="100" assign="maptest"}
and then use the variable within the script it seems to work

Code: Select all

{assign var="mapt" value=$maptest}

{literal}
<__script__>

	var cities = L.layerGroup();
        var maptest = '{/literal}{$mapt}{literal}';
        

	L.marker([55.8278, -4.0496]).bindPopup(maptest).addTo(cities);

This then puts whatever text I have entered into the content field in the pop up on the map.

However, when I switch to using CGBlog there's an error and the map disappears.

If I have a very simple template that renders just text ie

Code: Select all

{foreach from=$items item=entry name=maps}
Test Text
{/foreach}
It seems to work. If I add any Smarty tags to the template it fails.

Code: Select all

{foreach from=$items item=entry name=maps}

{if isset($entry->fields)}
  {foreach from=$entry->fields item='field'}
  {if $field->name == "location"}
            {$field->value}
  {/if}
  {/foreach}
{/if}

{/foreach}
Even though the variable captured renders on the page OK. It will not pass to the js script.

I haven't got as far as how to use the catured variable in the script as the script fails as soon as I try to assign the smarty variable to a js variable.

Sorry if this seems a bit convoluted but any suggestions would be greatfuly received.
User avatar
DIGI3
Dev Team Member
Dev Team Member
Posts: 1629
Joined: Wed Feb 25, 2009 4:25 am
Location: Victoria, BC

Re: Leaflet JS Map

Post by DIGI3 »

I think we'd need to be able to view the source and/or javascript console to be able to diagnose. It's going to be a simple typo or something, there's no magic involved with using Smarty variables within scripts.
Not getting the answer you need? CMSMS support options
howey
Forum Members
Forum Members
Posts: 158
Joined: Fri Sep 14, 2007 1:05 pm

Re: Leaflet JS Map

Post by howey »

Hi

The Leaflet script I am using is

Code: Select all

{assign var="mapt" value=$maptest}

{literal}
<__script__>

	var cities = L.layerGroup();
        var maptest = {/literal}'{$mapt}'{literal};
        

	L.marker([55.8278, -4.0496]).bindPopup(maptest).addTo(cities);



	var mbAttr = 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, ' +
			'<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
			'Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
		mbUrl = 'https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw';

	var grayscale   = L.tileLayer(mbUrl, {id: 'mapbox/light-v9', tileSize: 512, zoomOffset: -1, attribution: mbAttr}),
		streets  = L.tileLayer(mbUrl, {id: 'mapbox/streets-v11', tileSize: 512, zoomOffset: -1, attribution: mbAttr});

	var map = L.map('mapid', {
		center: [53.8, -2.1],
		zoom: 6,
		layers: [grayscale, cities]
	});

	var baseLayers = {
		"Grayscale": grayscale,
	};

	var overlays = {
		"Cities": cities
	};



</__script>
{/literal}
Which works OK when the variable set at the top is just taken from a content block and renders fine in the pop up on the map.

It's when I set the variable to take information from a CGBlog Summary template that the script fails.

I tested by setting the variable as below, but not using the variable within the script, just assigning it to a javascript variable.

Code: Select all

{capture name=mapviewx assign=maptest}{strip}{CGBlog summarytemplate=mapcs}{/strip}{/capture}
the CGBlog template I set up to test is:

Code: Select all

{foreach from=$items item=entry name=maps}
{$entry->title|escape:htmlall}
{/foreach}
This used the same Script as above, just capturing the variable from the CGBlog template. The weird thing is that if I edit the CGBlog template to

Code: Select all

{foreach from=$items item=entry name=maps}Sample text{/foreach}
It works passing the variable through and I can use this to add to the pop up. However, if I put line breaks in:

Code: Select all

{foreach from=$items item=entry name=maps}
Sample text
{/foreach}
it fails?

Having done another test I can create the following CGBlog template

Code: Select all

{foreach from=$items item=entry name=maps}{if isset($entry->fields)}{foreach from=$entry->fields item='field'}{if $field->name == "location"}{$field->value}{/if}{/foreach}{/if}{/foreach}
Where there are no line breaks and it works! Now I have re tested and got the code to pass the variable OK. As long as he CGBlog Template doesn't have any line breaks, I just need to figure out how to set this so I can use the information genmerated to replace the

Code: Select all

L.marker([55.8278, -4.0496]).bindPopup(maptest).addTo(cities);
As I should be able to get the template to loop through creating an L.marker for each location. They just need to be without line breaks?

As I say my knowledge is pretty limited and I stumble my way through things.

Any hints or tips?

Thanks
User avatar
velden
Dev Team Member
Dev Team Member
Posts: 3484
Joined: Mon Nov 28, 2011 9:29 am
Location: The Netherlands

Re: Leaflet JS Map

Post by velden »

Not the issue but replace this:

Code: Select all

{if isset($entry->fields)}
  {foreach from=$entry->fields item='field'}
  {if $field->name == "location"}
            {capture name=siteloc assign=siteloc}{$field->value}{/capture}
  {/if}
  {/foreach}
{/if}
with this:

Code: Select all

{$siteloc=$entry->fields.location->value}


Further:

{literal} tags are not needed per se. They make your code less readable. Just make sure you use a space after every opening { bracket when it's for Javascript and everything should be fine.


{*assign var="mapt" value=$maptest //--> why assigning it to another variable? *}

Code: Select all

<__script__>

   var cities = L.layerGroup();
        var maptest = '{$maptest}';

   L.marker([55.8278, -4.0496]).bindPopup(maptest).addTo(cities);
Then what DIGI3 says.
howey
Forum Members
Forum Members
Posts: 158
Joined: Fri Sep 14, 2007 1:05 pm

Re: Leaflet JS Map

Post by howey »

Hi

Thanks for the help. The template code will be tidier.

I set the variable again so it was visible in the same window when I was working on the code, so I could try different things. I tend to use a lot of generic content blocks in my pages as I can break down the code and I find it easier to trouble shoot if I am only looking at small blocks of code.

My main page looks like this – try not to laugh!

Code: Select all

{strip}{process_pagedata}{/strip}
<!doctype html>
<__html lang="{cms_get_language}">
<head>
	<title>{title} - {sitename}</title>
	{metadata}
	{cms_stylesheet}
</head>

</__body>
{* Variables *}
{content block="pageheadline" label="Page Headline" wysiwyg="false" oneline="true" size="100" assign="pageheadline"}
{content assign="gencontent" label="Page Intro Content"}

{content block="pagesec01" label="Page Section One Text" assign="pagesec01" tab="Page Sections"}
{content_image block='pagesec01img' dir='images/page-img' assign="pagesec01img" label="Section One Image" tab="Page Sections"}
{content block="pagesec02" label="Page Section Two Text" assign="pagesec02" tab="Page Sections"}
{content_image block='pagesec02img' dir='images/page-img' assign="pagesec02img" label="Section Two Image" tab="Page Sections"}
{content block="pagesec03" label="Page Section Three Text" assign="pagesec03" tab="Page Sections"}
{content_image block='pagesec03img' dir='images/page-img' assign="pagesec03img" label="Section Three Image" tab="Page Sections"}
{content block="pagesec04" label="Page Section Four Text" assign="pagesec04" tab="Page Sections"}
{content_image block='pagesec04img' dir='images/page-img' assign="pagesec04img" label="Section Four Image" tab="Page Sections"}

{content block="pagelink" label="Page Link - call to action" wysiwyg="false" oneline="true" size="100" assign="pagelink"}
{content_module module=CGContentUtils block="link-pos" label="Call to action position" assign="linkpos"}
{content_image block='pagebg' dir='images/page-bg' urlonly="1" assign="pagebg" label="Large background image" tab="Page Images"}
{content block="imagepadding" label="Space Required for image - number only" wysiwyg="false" oneline="true" size="50" assign="imgpadding" tab="Page Images"}
{capture name=mapviewx assign=maptest}{strip}{CGBlog summarytemplate=mapcs}{/strip}{/capture}
{content block="maptest" label="Map Test" wysiwyg="false" oneline="true" size="100" assign="maptest3"}


{* Content Blocks *}
{strip}{include file='cms_template:00_navoverlay'}{/strip}
{strip}{include file='cms_template:01_navigation'}{/strip}
{strip}{include file='cms_template:01_topbar'}{/strip}
{strip}{include file='cms_template:01_header'}{/strip}
{* Page Content Start *}
{strip}{include file='cms_template:01_pageheadline'}{/strip}
{strip}{include file='cms_template:01_pagewideintro'}{/strip}
{$maptest2}
{strip}{include file='cms_template:01_map'}{/strip}
{strip}{include file='cms_template:01_pagesectionone'}{/strip}
{* Page Content End *}
{strip}{include file='cms_template:01_home_services'}{/strip}
{strip}{include file='cms_template:01_footer'}{/strip}

<!-- Javascript -->
{include file='cms_template:01_mapincludejs'}
{include file='cms_template:01_navigationjav'}
<__body>

</__html>
This also allows me to re use code for various templates easily. As I can now pass the variable without any obvious problems. I just need to take out the line breaks in the template code. I will try your suggestion for using the variables in the script.

Just a quick question that may help short cut things. Now I've got the L.market information in a variable, how do I get this to be useable in the script? So that the information can be used to add the markers?

:-[

Thanks for the help.
User avatar
velden
Dev Team Member
Dev Team Member
Posts: 3484
Joined: Mon Nov 28, 2011 9:29 am
Location: The Netherlands

Re: Leaflet JS Map

Post by velden »

Like DIGI3 suggested I'd have a look at the page source and console.

Don't confuse Smarty variables with Javascript variables.

To use a Smarty variable inside your javascript, it should be just 'printed'. You already did that in your example.

Code: Select all

<__script__>
   var cities = L.layerGroup();
        var maptest = '{$mapt}'; // now the Smarty variable $mapt is assigned to Javascript variable 'maptest'.
I'm not familiar with leaflet.js but there must be some error somewhere. Look at the page source and see if the code is like you'd expect. Further the console will give hints as where to look for errors.
User avatar
DIGI3
Dev Team Member
Dev Team Member
Posts: 1629
Joined: Wed Feb 25, 2009 4:25 am
Location: Victoria, BC

Re: Leaflet JS Map

Post by DIGI3 »

I'm happy to look at the site, but using your shared code to set up a similar site to test on is asking a bit much. Can you not share the url to the dev site so we can look at the rendered code and javascript console?
Not getting the answer you need? CMSMS support options
howey
Forum Members
Forum Members
Posts: 158
Joined: Fri Sep 14, 2007 1:05 pm

Re: Leaflet JS Map

Post by howey »

Hi, I'm working on a local MAMP server at the moment. I can upload the latest rendition to my "working" version and give you access to that.

I'm just testing another way of adding the markers and then I'll upload.

Thanks
howey
Forum Members
Forum Members
Posts: 158
Joined: Fri Sep 14, 2007 1:05 pm

Re: Leaflet JS Map

Post by howey »

Hi DIGI3

I have got the Leaflet JS working, passing the CGBlog information as a variable to the script. It still fails if I leave any line breaks in the CGBlog template.

The working code is below:

CGBlog template

Code: Select all

{foreach from=$items item=entry name=maps}{if $smarty.foreach.maps.last}L.marker([{$entry->fields.location->value}], {if $entry->fields.type->value == "Diesel"}{literal}{icon: diesel}{/literal}{else}{literal}{icon: gas}{/literal}{/if}).bindPopup('<strong>Category:</strong> {$entry->fields.type->value}<br><strong>Location:</strong> {$entry->title|escape:htmlall}<br><strong>Capacity:</strong> {$entry->fields.capacity->value}').addTo(cities);{else}L.marker([{$entry->fields.location->value}], {if $entry->fields.type->value == "Diesel"}{literal}{icon: diesel}{/literal}{else}{literal}{icon: gas}{/literal}{/if}).bindPopup('<strong>Category:</strong> {$entry->fields.type->value}<br><strong>Location:</strong> {$entry->title|escape:htmlall}<br><strong>Capacity:</strong> {$entry->fields.capacity->value}').addTo(cities),{/if}{/foreach}
Leaflet Script for map

Code: Select all

{assign var="mapt" value=$maptest}

{literal}
<__script__>

var diesel = L.icon({
    iconUrl: 'site-icons/diesel.png',
    iconSize: [20, 30],
    iconAnchor: [20, 30],
    popupAnchor: [-3, -76],
    shadowUrl: 'site-icons/shadow.png',
    shadowSize: [20, 30],
    shadowAnchor: [10, 30]
});
var gas = L.icon({
    iconUrl: 'site-icons/gas.png',
    iconSize: [20, 30],
    iconAnchor: [20, 30],
    popupAnchor: [-3, -76],
    shadowUrl: 'site-icons/shadow.png',
    shadowSize: [20, 30],
    shadowAnchor: [10, 30]
});

	var cities = L.layerGroup();

	{/literal}{$mapt}{literal}


	var mbAttr = 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, ' +
			'<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
			'Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
		mbUrl = 'https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw';

	var grayscale   = L.tileLayer(mbUrl, {id: 'mapbox/light-v9', tileSize: 512, zoomOffset: -1, attribution: mbAttr}),
		streets  = L.tileLayer(mbUrl, {id: 'mapbox/streets-v11', tileSize: 512, zoomOffset: -1, attribution: mbAttr});

	var map = L.map('mapid', {
		center: [53.3, -2.2],
		zoom: 7,
		layers: [grayscale, cities]
	});

	var baseLayers = {
		"Grayscale": grayscale,
		"Streets": streets
	};

	var overlays = {
		"Cities": cities
	};


</__script>
{/literal}
I'm using custom fields to add the location co-ordinates and other detail for the pop ups on the markers.

http://www.designforsuccess.co.uk/gen-d ... e-studies

Shows it working. If you want to delve deeper and have a look at the code I can PM you with a link etc.

Thanks for your help along the way, it nudged me in the right direction to get it working. If a bit clumsy from me.
deactivated010521

Re: Leaflet JS Map

Post by deactivated010521 »

You can not pass Smarty map data to JavaScript directly. To create popup's you have to create a marker for every place/location you have stored (JavaScript, for loop).

The cleanest way is to seperate Smarty templates from Javascript. I would write an UDT that takes your Smarty maps data and convert that into universal JSON. Load that into your Leaflet JavaScript file. Both Smarty/PHP and JavaScript can work with JSON.

Code: Select all

https://www.php.net/manual/en/function.json-encode.php
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON
It seems you mix a Smarty (foreach loop) with JavaScript it can work but is a bit messy. If you don't go the JSON route I would place map data in a JavaScript array of objects, (cont places).

**pseudo smarty code mixed with js code**

Code: Select all

<!-- js -->
{literal}
// const places is a JavaScript array
const places = []; 
{/literal}

<!-- smarty [literal / literal] / js -->
// $obj is a Smarty obj
// let place is a JavaScript obj
{foreach from=$mapObj item=obj name=loop}
let place = {};
place.id = $smarty.foreach.loop;
place.name = $obj.name;
place.lat = $obj.lat;
place.lng = $obj.lng;
places.push(place);
{/foreach}
This will give you something like this JavaScript array of objects:

Code: Select all

      
<!-- js -->
places: [
        {id: '1',
          name: 'Amsterdam Office',
          lat: '52.370216',
          lng: '4.895168'},
        {id: '2',
          name: 'Rotterdam Office',
          lat: '51.924420',
          lng: '4.477733'},
        {id: '3',
          name: 'Utrecht Office',
          lat: '52.090737',
          lng: '5.121420'},
      ],
Later on you can create a Popup for every place, the popup shows the place name.

** pseudo es6 js code **

Code: Select all

import L from 'leaflet';
import 'leaflet.markercluster';

    addPlaces(places) {
      if (!this.map) return;
      const map = this.map;
      const markers = L.markerClusterGroup();

      places.forEach( (place) => {
        const marker = L.marker([place.lat, place.lng])
          .on('click', (el) => {
          })
          .bindPopup(`<strong>${place.name}</strong>`);
        markers.addLayer(marker);
      });

      map.addLayer(markers);
      this.markers = markers;
    },
Just a random es5 js example:
http://bl.ocks.org/d3noob/9150014
Post Reply

Return to “Modules/Add-Ons”