Google Charts Only Render when Browser Zoom At 100% - google-chrome

Webpage contains five tabs of contents; initial tab has an account/profile form on it, three others are records for the account and the fifth one contains Google Charts with Google Analytic data in it.
The google charts are nothing complicated; a line chart, a pie chart, and two geo charts. Using Google Chart code and standard JavaScript and PHP. The only complicated thing was building/persisting the chart strings in a MySQL database so they could be retrieved without having the overhead of the Google Analytic call.
When first coded up the tab page, noticed the chart tab was not rendering, and that turned out to be problem where the charts would not render in a DIV where display:none. The initial tab was display:block, but the others were display:none. Was able to solve this by moving the DrawChart() call into the 'activate tab' code vs using the google.charts.setOnLoadCallback(drawChart) within the chart code.
This seems to work fine EXCEPT when the browser is other than 100%.
Firefox at 100%
If you render the page at 100% and zoom the page in and out, all is fine. However, if you set the page to other than 100%, reload the tab page, then select the metrics tab, you get a variety of results, none of which are desired.
Chrome produces the following:
Chrome at 80%
Firefox is similar:
Firefox at 80%
Have found one post talking about finding min/max values of each axis which I can understand if the chart boundaries are changing like zooming ONLY the chart, but with page zoom, the relative canvas is still the same size.
Here is the starting code for the GA METRIC tab and the first linechart. Again, the drawChart() call is in tab control code so the normal callback is commented out. This was due to the timing problem mentioned earlier.
<div id="GA_Metrics" class="tabcontent">
<div id="header"><span style="font-size:10px;font-weight: bold;">Record No: 007101</span></div>
<div id="postings_gametric_container_linechart" class="container"></div>
<div id="postings_gametric_container_piechart" class="container"></div>
<div id="postings_gametric_container_geoworld" class="container"></div>
<div id="postings_gametric_container_geousa" class="container"></div>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages': ['corechart','geochart','table'],'mapsApiKey': 'keygoeshere'});
//google.charts.setOnLoadCallback(drawChart);
function drawLineChart()
{
var data = google.visualization.arrayToDataTable([[{type: 'date', label: 'Date'},
{type: 'number', label: 'SIA49775'},
{type: 'number', label: 'SIA51972'},
{type: 'number', label: 'SIA52931'},
{type: 'number', label: 'SIA53349'},
{type: 'number', label: 'SIA53350'}],
[new Date(2019,11,18),0,1,2,1,7],
[new Date(2019,11,19),0,0,0,1,0],
[new Date(2019,11,20),2,2,2,1,2],
[new Date(2019,11,21),2,4,3,6,1],
[new Date(2019,11,22),0,3,3,1,2],
[new Date(2019,11,23),2,2,5,1,7],
[new Date(2019,11,24),0,1,1,2,1],
[new Date(2019,11,25),2,2,4,0,4],
[new Date(2019,11,26),1,0,1,4,1],
[new Date(2019,11,27),1,0,2,0,1],
[new Date(2019,11,28),3,2,4,0,8],
[new Date(2019,11,29),2,1,2,3,1],
[new Date(2019,11,30),1,3,3,5,5],
[new Date(2019,11,31),2,1,0,2,0],
[new Date(2020,00,01),6,4,7,3,8],
[new Date(2020,00,02),2,3,4,0,6],
[new Date(2020,00,03),2,1,5,7,4],
[new Date(2020,00,04),0,0,0,1,0],
[new Date(2020,00,05),2,1,2,0,1],
[new Date(2020,00,06),1,2,3,2,7],
[new Date(2020,00,07),0,1,0,3,2],
[new Date(2020,00,08),1,1,4,0,4],
[new Date(2020,00,09),1,1,2,1,4],
[new Date(2020,00,10),3,2,4,2,9],
[new Date(2020,00,11),2,5,2,2,6],
[new Date(2020,00,12),0,0,1,1,1],
[new Date(2020,00,13),2,2,3,0,6],
[new Date(2020,00,14),4,4,2,3,8],
[new Date(2020,00,15),3,3,3,2,3],
[new Date(2020,00,16),0,3,2,1,1]]);
var options = {
title: 'Active Posting(s) PageViews (Last 30 Days)',
hAxis: {
format: 'M/d',
gridlines: {color: '#000080'}
},
vAxis: {
title: 'Page Views',
gridlines: {color: '#000080'}
},
pointSize: 3,
backgroundColor: '#cfcfcf',
chartArea:{width:'62%'}
};
/* Create instance of "Classic" Visualization Line Chart */
var chart = new google.visualization.LineChart(document.getElementById('postings_gametric_container_linechart'));
chart.draw(data, options);
Here is the code further down on the page that controls the tabs. This is where the drawChart() call had to go to avoid the display:none issue mentioned above.
<script>
function openPage(pageName,elmnt,color) {
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tablink");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].style.backgroundColor = "";
}
document.getElementById(pageName).style.display = "block";
elmnt.style.backgroundColor = color;
//Moved the drawChart() call to this location so the call to render the chart comes AFTER the
//DIV is visible, otherwise, the chart does not render properly. See DECLARATION for explanation.
if(pageName == "GA_Metrics")
{
drawLineChart();
drawPieChart();
drawGeoWorldMap();
drawGeoUSAMap();
}
}
Googled the error messages in red for Chrome and Firefox which provided some details but nothing seemed to fit this problem. When the page is zoomed in or out and then reloaded, the drawChart() call happens again when you select the GA METRICS tab, so thought it would render appropriately, but alas not.
Thank you in advance for any possible solutions.
LarryG
UPDATE 20200211_1220C
Another interesting tidbit, using the Firefox Web Developer Tool, the DIV with the chart has a height of 1px. However, if you click on the GA METRIC tab (page not reloaded, but the openPage() call occurs passing in the GA METRIC tab), each time the height grows 1px. Therefore, after 40 clicks you can begin to see the charts form, so they are there ... the DIV height is just getting overridden when the zoom is not at 100%. See graphic link.
Firefox at 80% after 40 clicks of GA METRIC tab
20200214 UPDATE - Added code from affected page, cutting out all that was not necessary. This shows the relative placement of the tab control vs the openPage() and the metric charts. The openPage() is below the tab controls. Only thing below it is the footers and such.
<!-- DIV STARTS HERE -->
<button class="tablink" onclick="openPage('Account_Info', this, '#000080')" id="defaultOpen">Account Info</button>
<button class="tablink" onclick="openPage('Posts_Active', this, '#000080')">ACTIVE</button>
<button class="tablink" style="opacity:1.0;" onclick="openPage('Posts_SOLD', this, '#000080')">SOLD</button>
<button class="tablink" style="opacity:1.0;" onclick="openPage('Posts_NotSOLD', this, '#000080')">NOT SOLD</button>
<button class="tablink" style="opacity:1.0;" onclick="openPage('GA_Metrics', this, '#000080')">GA Metrics</button>
<div id="Account_Info" class="tabcontent">
</div>
<div id="Posts_Active" class="tabcontent">
</div>
<div id="Posts_SOLD" class="tabcontent">
</div>
<div id="Posts_NotSOLD" class="tabcontent">
</div>
<div id="GA_Metrics" class="tabcontent">
<div id="header"><span style="font-size:10px;font-weight: bold;">Record No: 019036</span></div>
<div id="postings_gametric_container_linechart" class="container"></div>
<div id="postings_gametric_container_piechart" class="container"></div>
<div id="postings_gametric_container_geoworld" class="container"></div>
<div id="postings_gametric_container_geousa" class="container"></div>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
// Note: you will need to get a mapsApiKey for your project. "mapsApiKey" is the property name and is required no matter what you call your Key.
// See: https://developers.google.com/chart/interactive/docs/basic_load_libs#load-settings
google.charts.load('current', {'packages': ['corechart','geochart','table'],'mapsApiKey': 'API_KEY_GOES_HERE'});
//20190304LG: Noticed the chart was not rendering properly. Found StackOverFlow article where if the charts are in a "display:none" div like a tab
//they will not render properly. They will revert to google chart css which is usually 400x200px. The solution was to either make the
//chart call before the tabs/divs were set to display:none OR load them when the tab/div was activated. As a result, LG commented out
//the next line and put the drawChart() call in the ACCOUNT_MGMNT_TEMP.HTML file in the openPage() Javascript function. This seems to
//have fixed the problem.
//google.charts.setOnLoadCallback(drawChart);
//
//20200209LG: The Geo Strings sometimes contain an apostrophe such as ['Provence-Alpes-Cote d'Azur',1] which will prevent rendering.
// Added some str_replace code to escape those instances, but its bruteforce for now.
function drawLineChart()
{
var data = google.visualization.arrayToDataTable([[{type: 'date', label: 'Date'},
{type: 'number', label: 'SIA35512'},
{type: 'number', label: 'SIA39964'},
{type: 'number', label: 'SIA53391'}],
[new Date(2020,00,14),0,0,1],
[new Date(2020,00,15),0,0,0],
[new Date(2020,00,16),1,2,0],
[new Date(2020,00,17),0,0,0],
[new Date(2020,00,18),1,0,0],
[new Date(2020,00,19),0,1,0],
[new Date(2020,00,20),3,4,0],
[new Date(2020,00,21),2,3,1],
[new Date(2020,00,22),1,0,0],
[new Date(2020,00,23),1,0,0],
[new Date(2020,00,24),2,0,0],
[new Date(2020,00,25),0,0,0],
[new Date(2020,00,26),0,4,0],
[new Date(2020,00,27),6,0,0],
[new Date(2020,00,28),2,1,0],
[new Date(2020,00,29),1,0,0],
[new Date(2020,00,30),0,0,0],
[new Date(2020,00,31),1,1,0],
[new Date(2020,01,01),0,1,1],
[new Date(2020,01,02),0,1,0],
[new Date(2020,01,03),1,2,2],
[new Date(2020,01,04),3,2,1],
[new Date(2020,01,05),1,0,0],
[new Date(2020,01,06),0,1,0],
[new Date(2020,01,07),0,0,0],
[new Date(2020,01,08),1,1,0],
[new Date(2020,01,09),0,1,0],
[new Date(2020,01,10),1,0,0],
[new Date(2020,01,11),0,2,0],
[new Date(2020,01,12),2,0,0]]);
var options = {
title: 'Active Posting(s) PageViews (Last 30 Days)',
hAxis: {
format: 'M/d',
gridlines: {color: '#000080'}
},
vAxis: {
title: 'Page Views',
gridlines: {color: '#000080'}
},
pointSize: 3,
backgroundColor: '#cfcfcf',
chartArea:{width:'62%'}
};
/* Create instance of "Classic" Visualization Line Chart */
var chart = new google.visualization.LineChart(document.getElementById('postings_gametric_container_linechart'));
chart.draw(data, options);
}
function drawPieChart()
{
var data = google.visualization.arrayToDataTable([['Posting','Page Views'],
['35512',1395],
['39964',645],
['53391',80]]);
var options = {
title: 'Active Posting(s) % PageViews (Last 30 Days)',
backgroundColor: '#cfcfcf',
is3D: true
};
//Create instance of "Classic" Visualization Line Chart
var chart = new google.visualization.PieChart(document.getElementById('postings_gametric_container_piechart'));
chart.draw(data, options);
}
//20190321 LG - REPLACE the chart.draw with the geomap.draw. SEE this URL or your TEST_geo2.html file
function drawGeoWorldMap()
{
var data = google.visualization.arrayToDataTable([['Country','PageViews'],
['Australia',8],
['Belgium',11],
['Brazil',3],
['Canada',64],
['Czechia',8],
['Ecuador',3],
['Georgia',3],
['Germany',3],
['Italy',3],
['Malaysia',3],
['Mexico',3],
['New Zealand',3],
['Puerto Rico',3],
['Singapore',3],
['South Korea',3],
['United Kingdom',3],
['United States',1227]]);
var options = {
region: 'world',
displayMode: 'regions',
backgroundColor: '#cfcfcf',
colorAxis: {colors: ['green', 'blue']}
};
var chart = new google.visualization.GeoChart(document.getElementById('postings_gametric_container_geoworld'));
chart.draw(data, options);
}
function drawGeoUSAMap()
{
var data = google.visualization.arrayToDataTable([['State','PageViews'],
['(not set)',3],
['Aguadilla',3],
['Alabama',11],
['Alberta',3],
['Arizona',5],
['Arkansas',3],
['British Columbia',24],
['California',80],
['Canterbury',3],
['Colorado',16],
['Connecticut',37],
['District of Columbia',13],
['England',3],
['Flanders',11],
['Florida',61],
['Georgia',27],
['Guayas',3],
['Gyeonggi-do',3],
['Idaho',34],
['Illinois',16],
['Indiana',50],
['Iowa',5],
['Kansas',13],
['Kentucky',8],
['Liberec Region',5],
['Maine',16],
['Massachusetts',29],
['Michigan',85],
['Minnesota',50],
['Mississippi',8],
['Missouri',77],
['Montana',8],
['Nebraska',16],
['Nevada',3],
['New Hampshire',29],
['New Jersey',11],
['New South Wales',3],
['New York',101],
['North Carolina',32],
['North Dakota',11],
['Nova Scotia',5],
['Ohio',66],
['Oklahoma',5],
['Ontario',27],
['Oregon',13],
['Pennsylvania',56],
['Prague',3],
['Puebla',3],
['Quebec',5],
['Queensland',3],
['Rhineland-Palatinate',3],
['Rhode Island',5],
['Samegrelo-Zemo Svaneti',3],
['Selangor',3],
['Sicily',3],
['South Carolina',5],
['State of Sao Paulo',3],
['Tennessee',27],
['Texas',61],
['Utah',8],
['Vermont',3],
['Victoria',3],
['Virginia',21],
['Washington',27],
['West Virginia',3],
['Wisconsin',74]]);
var options = {
region: 'US',
backgroundColor: '#cfcfcf',
resolution: 'provinces',
displayMode: 'regions',
colorAxis: {colors: ['green', 'blue']}
};
var chart = new google.visualization.GeoChart(document.getElementById('postings_gametric_container_geousa'));
chart.draw(data, options);
}
/*
function drawGeoUSACityMap()
{
var data = google.visualization.arrayToDataTable([<!--GA_METRIC_GEOUSACITY_CALL-->]);
var options = {
region: 'US',
backgroundColor: '#cfcfcf',
displayMode: 'markers',
resolution: 'metros',
colorAxis: {colors: ['green', 'blue']}
};
var chart = new google.visualization.GeoChart(document.getElementById('postings_gametric_container_geousacity'));
chart.draw(data, options);
}
*/
</script>
</div>
<script>
function openPage(pageName,elmnt,color) {
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tablink");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].style.backgroundColor = "";
}
document.getElementById(pageName).style.display = "block";
elmnt.style.backgroundColor = color;
//Moved the drawChart() call to this location so the call to render the chart comes AFTER the
//DIV is visible, otherwise, the chart does not render properly. See DECLARATION for explanation.
if(pageName == "GA_Metrics")
{
drawLineChart();
drawPieChart();
drawGeoWorldMap();
drawGeoUSAMap();
}
}
//INITIALIZATION of the TABS ... get the element with id="defaultOpen" and click on it
document.getElementById("defaultOpen").click();
</script>
<!-- DIV ENDS HERE -->

Related

Google Sheets: Map Not Rendering with Custom Markers

I am trying to render a map in Google Sheets and set custom markers. I have followed the App Script Docs that go over this topic: Visualization: Map. The map is rendering with the icons in the correct places, but the icons are the default set.
I checked my img URLs (by setting them as the default) and they work (the below urls are fake). I believe the issue is somewhere around matching the options.icons.keys with the data that is in the dataTable 3rd column.
Here is the raw data that is pulled from <?= jsonPoints ?>
[[29.59260664700021,-95.77028110299972,"Red"],
[29.591301814000055,-95.76907472100011,"Green"],
[29.591178932000005,-95.76802742100018,"Red"],
[29.587551849000003,-95.77229599100004,"Blue"]]
And here is the function that creates the map:
function drawMap() {
points = <?= jsonPoints ?>;
var data = new google.visualization.DataTable();
data.addColumn('number', 'Latitude');
data.addColumn('number', 'Longitude');
data.addColumn('string', 'Point Type');
data.addRows(JSON.parse(points))
var url = 'https://image.ibb.co/';
var options = {
showTooltip: true,
showInfoWindow: true,
useMapTypeControl: true,
icons: {
Red: {
normal: url + '/red.png',
selected: url + '/red.png'
},
Blue: {
normal: url + '/Blue.png',
selected: url + '/Blue.png'
},
Green: {
normal: url + '/Green.png',
selected: url + '/Green.png'
}
}
};
var map = new google.visualization.Map(document.getElementById('chart'));
map.draw(data, options);
};
I have tried putting quotation marks on the options.icons.keys, like "Green", but that did not work.
Any thoughts?
Thank you!
Figured it out. Added a fourth column that essentially had the same data. One column goes to the tooltip, the other is used as the marker:
data.addColumn('number', 'Latitude');
data.addColumn('number', 'Longitude');
data.addColumn('string', 'Tooltip_Data');
data.addColumn('string', 'Marker');
Now icons are rendered!

geochart regions clickable urls

We want to embed a really basic interactive map on our website, where clicking a region will take you to a specific page on our site. We would like to use the regions in google geochart
This is the map we are working with
https://jsfiddle.net/tyvnfxf4/
google.charts.load('current', {'packages':['geochart']});
google.charts.setOnLoadCallback(drawRegionsMap);
function drawRegionsMap() {
var data = google.visualization.arrayToDataTable([
['Country', 'Popularity'],
['England', 400],
['Wales', 300],
['Scotland', 400],
['Ireland', 600],
]);
var options = {
region: 'GB',
resolution: 'provinces',
};
var chart = new google.visualization.GeoChart(document.getElementById('regions_div'));
chart.draw(data, options);
}
And we would want:
Wales to link to www.example.com/wales
Ireland to link to www.example.com/ireland
etc
Can any help?
Many thanks
there are a number of ways to handle, but the key is using the 'select' event
keep in mind, the 'select' event is fired both when something is selected and de-selected,
so make sure length > 0
recommend using a column in the DataTable to store the URLs
use a DataView to hide the column from the chart
then get the URL based on the chart selection
see following working snippet...
google.charts.load('current', {
callback: function () {
var data = google.visualization.arrayToDataTable([
['Country', 'Popularity', 'Domain'],
['England', 400, 'www.example.com/England'],
['Wales', 300, 'www.example.com/Wales'],
['Scotland', 400, 'www.example.com/Scotland'],
['Ireland', 600, 'www.example.com/Ireland'],
]);
var view = new google.visualization.DataView(data);
view.setColumns([0, 1]);
var options = {
region: 'GB',
resolution: 'provinces'
};
var chart = new google.visualization.GeoChart(document.getElementById('regions_div'));
google.visualization.events.addListener(chart, 'select', function () {
var selection = chart.getSelection();
if (selection.length > 0) {
console.log(data.getValue(selection[0].row, 2));
//window.open('http://' + data.getValue(selection[0].row, 2), '_blank');
}
});
chart.draw(view, options);
},
packages:['geochart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script src="https://www.google.com/jsapi"></script>
<div id="regions_div" style="width: 600px; height: 500px;"></div>

How to control the behavior of tooltip on google chart

when i click on google chart point, In tooltip it is showing 'See sample book'.
I want to control the enable and disable property on tooltip using the code.
As of now enable and disable is working with mouse over event but i want to remove this and simply enable and disable the 'see sample block' using programming.
At first point it should be disable its working fine
second point should be enable but it showing disable when mouse over it showing as enable . I need this should be happen as soon as i click the point in the graph.
My HTML code is here:
<html>
<head>
<script type="text/javascript"
src="https://www.google.com/jsapi?autoload={
'modules':[{
'name':'visualization',
'version':'1',
'packages':['corechart']
}]
}"></script>
<script type="text/javascript">
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Year', 'Sales', 'Expenses'],
['2004', 1000, 400],
['2005', 1170, 460],
['2006', 660, 1120],
['2007', 1030, 540]
]);
var options = {
title: 'Company Performance',
legend: { position: 'bottom' },
tooltip: { trigger: 'selection' }
};
var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));
chart.setAction({
id: 'sample',
text: 'See sample book',
enabled:function()
{
if (typeof(chart.getSelection) == 'undefined')
return false;
if (typeof (chart.getSelection()[0]) == 'undefined')
return false;
selection = chart.getSelection();
var ans = selection[0].row;
if(ans == 0)
{
return false;
}
else
{
return true;
}
},
action: function() {
selection = chart.getSelection();
alert(selection[0].row);
}
});
chart.draw(data, options);
}
</script>
</head>
<body>
<div id="curve_chart" style="width: 900px; height: 500px"></div>
</body>
</html>
You can set the tooltip to HTML, this should give you more control of how it operates, and what it displays. To do this, add a tooltip column to your chart, when you're building the chart with columns and rows
data.addColumn({ type: 'string', role: 'annotation', 'p': { 'html': true } });
As you can see, we are setting the tooltip information to be html instead of SVG, and the data you want to populate into your tooltip, should be added as a row to your chart, corresponding to the column.
To modify the tooltip behaviour, you can use the options you pass to the chart, and add the isHtml to true
tooltip: { trigger: selection, isHtml: true }
To make additional changes to your tooltip, in css, you can add this line to your CSS and start overriding the default css
div.google-visualization-tooltip {
}

show/hide kml on defined zoom levels

I´m trying to hide/show my own kml files (polygons) depending on zoom levels in OpenLayers - when reached certain zoom level one layer should hide and another show. So far I found this solution (How to load layers depending on zoom level?), but it doesn´t seem to be working in my case. I´m relatively new to javascript and I don´t know if I´m using this right, I also made some changes to the example:
map.events.register("zoomend", map, zoomChanged); //inserted in function init()
function zoomChanged()
{
if (map.getZoom() == 18)
{
kml1.setVisibility (true);
kml2.setVisibility (false);
}
else if (map.getZoom() == 19)
{
kml1.setVisibility (false);
kml2.setVisibility (true);
}
}
I also tried another solution to hide kml1, but in this case my layer isn´t drawn. The LayerSwitcher works - the layer is unselectable in defined zoom levels, but nothing is visible when zoomed out (when layer is already selectable):
var kml1 = new OpenLayers.Layer.Vector("prehled",
{minScale: 1000,}, //1:1000
{
projection: map.displayProjection,
strategies: [new OpenLayers.Strategy.Fixed()],
protocol: new OpenLayers.Protocol.HTTP({
url: "kml/zahrada.kml",
format: new OpenLayers.Format.KML({
extractStyles: true,
extractAttributes: true,
})
})
});
map.addLayer(kml1);
Thanks for any response and advice on this.
Try:
var kml1 = new OpenLayers.Layer.Vector("prehled", {
minResolution: map.getResolutionForZoom(18), // or the desired maximum zoom
projection: map.displayProjection,
strategies: [new OpenLayers.Strategy.Fixed()],
protocol: new OpenLayers.Protocol.HTTP({
url: "kml/zahrada.kml",
format: new OpenLayers.Format.KML({
extractStyles: true,
extractAttributes: true
})
})
});
map.addLayer(kml1);
```

Layer Ordering in leaflet.js

How can I force a new layer added to the map in Leaflet to be the first over the basemap?
I could not find a method to easily change the order of the layers, which is a very basic GIS feature. Am I missing something?
A Leaflet map consists of a collection of "Panes" whose view order is controlled using z-index. Each pane contains a collection of Layers The default pane display order is tiles->shadows->overlays->markers->popups. Like Etienne described, you can control the display order of Paths within the overlays pane by calling bringToFront() or bringToBack(). L.FeatureGroup also has these methods so you can change the order of groups of overlays at once if you need to.
If you want to change the display order of a whole pane then you just change the z-index of the pane using CSS.
If you want to add a new Map pane...well I'm not sure how to do that yet.
http://leafletjs.com/reference.html#map-panes
http://leafletjs.com/reference.html#featuregroup
According to Leaflet API, you can use bringToFront or bringToBack on any layers to brings that layer to the top or bottom of all path layers.
Etienne
For a bit more detail, Bobby Sudekum put together a fantastic demo showing manipulation of pane z-index. I use it as a starting point all the time.
Here's the key code:
var topPane = L.DomUtil.create('div', 'leaflet-top-pane', map.getPanes().mapPane);
var topLayer = L.mapbox.tileLayer('bobbysud.map-3inxc2p4').addTo(map);
topPane.appendChild(topLayer.getContainer());
topLayer.setZIndex(7);
Had to solve this recently, but stumbled upon this question.
Here is a solution that does not rely on CSS hacks and works with layer groups. It essentially removes and re-adds layers in the desired order.
I submit this as a better "best practice" than the current answer. It shows how to manage the layers and re-order them, which is also useful for other contexts. The current method uses the layer Title to identify which layer to re-order, but you can easily modify it to use an index or a reference to the actual layer object.
Improvements, comments, and edits are welcome and encouraged.
JS Fiddle: http://jsfiddle.net/ob1h4uLm/
Or scroll down and click "Run code snippet" and play with it. I set the initial zoom level to a point that should help illustrate the layerGroup overlap effect.
function LeafletHelper() {
// Create the map
var map = L.map('map').setView([39.5, -0.5], 4);
// Set up the OSM layer
var baseLayer = L.tileLayer(
'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18
}).addTo(map);
var baseLayers = {
"OSM tiles": baseLayer
};
this.map = map;
this.BaseLayers = {
"OSM tiles": baseLayer
};
this.LayersControl = L.control.layers(baseLayers).addTo(map);
this.Overlays = [];
this.AddOverlay = function (layerOptions, markers) {
var zIndex = this.Overlays.length;
var layerGroup = L.layerGroup(markers).addTo(map);
this.LayersControl.addOverlay(layerGroup, layerOptions.title);
this.Overlays.push({
zIndex: zIndex,
LeafletLayer: layerGroup,
Options: layerOptions,
InitialMarkers: markers,
Title: layerOptions.title
});
return layerGroup;
}
this.RemoveOverlays = function () {
for (var i = 0, len = this.Overlays.length; i < len; i++) {
var layer = this.Overlays[i].LeafletLayer;
this.map.removeLayer(layer);
this.LayersControl.removeLayer(layer);
}
this.Overlays = [];
}
this.SetZIndexByTitle = function (title, zIndex) {
var _this = this;
// remove overlays, order them, and re-add in order
var overlays = this.Overlays; // save reference
this.RemoveOverlays();
this.Overlays = overlays; // restore reference
// filter overlays and set zIndex (may be multiple if dup title)
overlays.forEach(function (item, idx, arr) {
if (item.Title === title) {
item.zIndex = zIndex;
}
});
// sort by zIndex ASC
overlays.sort(function (a, b) {
return a.zIndex - b.zIndex;
});
// re-add overlays to map and layers control
overlays.forEach(function (item, idx, arr) {
item.LeafletLayer.addTo(_this.map);
_this.LayersControl.addOverlay(item.LeafletLayer, item.Title);
});
}
}
window.helper = new LeafletHelper();
AddOverlays = function () {
// does not check for dups.. for simple example purposes only
helper.AddOverlay({
title: "Marker A"
}, [L.marker([36.83711, -2.464459]).bindPopup("Marker A")]);
helper.AddOverlay({
title: "Marker B"
}, [L.marker([36.83711, -3.464459]).bindPopup("Marker B")]);
helper.AddOverlay({
title: "Marker C"
}, [L.marker([36.83711, -4.464459]).bindPopup("Marker c")]);
helper.AddOverlay({
title: "Marker D"
}, [L.marker([36.83711, -5.464459]).bindPopup("Marker D")]);
}
AddOverlays();
var z = helper.Overlays.length;
ChangeZIndex = function () {
helper.SetZIndexByTitle(helper.Overlays[0].Title, z++);
}
ChangeZIndexAnim = function () {
StopAnim();
var stuff = ['A', 'B', 'C', 'D'];
var idx = 0;
var ms = 200;
window.tt = setInterval(function () {
var title = "Marker " + stuff[idx++ % stuff.length];
helper.SetZIndexByTitle(title, z++);
}, ms);
}
StopAnim = function () {
if (window.tt) clearInterval(window.tt);
}
#map {
height: 400px;
}
<link rel="stylesheet" type="text/css" href="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.css">
<script type='text/javascript' src="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.js"></script>
<div id="map"></div>
<input type='button' value='Remove overlays' onclick='helper.RemoveOverlays();' />
<input type='button' value='Add overlays' onclick='AddOverlays();' />
<input type='button' value='Move bottom marker to top' onclick='ChangeZIndex();' />
<input type='button' value='Change z Index (Animated)' onclick='ChangeZIndexAnim();' />
<input type='button' value='Stop animation' onclick='StopAnim();' />
I've found this fix (css):
.leaflet-map-pane {
z-index: 2 !important;
}
.leaflet-google-layer {
z-index: 1 !important;
}
found it here: https://gis.stackexchange.com/questions/44598/leaflet-google-map-baselayer-markers-not-visible