How can I style layer.control in leaflet.js? - javascript

I am trying to change the default dropdown menu icon in the layer control. I'd like to have text alongside the icon. Is there any way to do this? Perhaps using JQuery and CSS?
I'm working on a leaflet project based on this example: http://leafletjs.com/examples/layers-control.html
Code:
<html>
<head>
<title>Leaflet Layers Control Example</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../dist/leaflet.css" />
</head>
<body>
<div id="map" style="width: 600px; height: 400px"></div>
<script src="../dist/leaflet.js"></script>
<script>
var cities = new L.LayerGroup();
L.marker([39.61, -105.02]).bindPopup('This is Littleton, CO.').addTo(cities),
L.marker([39.74, -104.99]).bindPopup('This is Denver, CO.').addTo(cities),
L.marker([39.73, -104.8]).bindPopup('This is Aurora, CO.').addTo(cities),
L.marker([39.77, -105.23]).bindPopup('This is Golden, CO.').addTo(cities);
var cmAttr = 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 Clou dMade',
cmUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/{styleId}/256/{z}/{x}/{y}.png';
var minimal = L.tileLayer(cmUrl, {styleId: 22677, attribution: cmAttr}),
midnight = L.tileLayer(cmUrl, {styleId: 999, attribution: cmAttr}),
motorways = L.tileLayer(cmUrl, {styleId: 46561, attribution: cmAttr});
var map = L.map('map', {
center: [39.73, -104.99],
zoom: 10,
layers: [minimal, motorways, cities]
});
var baseLayers = {
"Minimal": minimal,
"Night View": midnight
};
var overlays = {
"Motorways": motorways,
"Cities": cities
};
L.control.layers(baseLayers, overlays).addTo(map);
</script>

Add this style after leaflet.css:
<style>
.leaflet-control-layers-toggle:after{
content:"your text";
color:#000 ;
}
.leaflet-control-layers-toggle{
width:auto;
background-position:3px 50% ;
padding:3px;
padding-left:36px;
text-decoration:none;
line-height:36px;
}
</style>

You can use HTML and you can change text when you define baselayers dans overlays.
Example:
var baseLayers = {
"<div id='my-div-id'><img src='img/icon-minimal.png' />Minimal View</div>": minimal,
"<div id='my-div-id'><img src='img/icon-night.png' />Super Night View</div>": midnight
};
var overlays = {
"<img src='myimage.png' /> Motorways": motorways,
"<img src='myimage2.png' /> All Cities": cities
};

If you are using Jquery you can add this to the document ready section
$(document).ready(function () {
$('.leaflet-control-layers').css({ 'width': 'auto', 'float': 'left' });
$('.leaflet-control-layers-toggle').css('float', 'left');
$('.leaflet-control-layers-toggle').after('<div class='control-extend'>Your text goes here</div>')
$('.control-extend').css({ 'float': 'left', 'line-height': '35px', 'font-weight': 'bold', 'margin-right' : '10px'});
$('.leaflet-control-layers').on('mouseover', function (e) {
$('.control-extend').hide();
});
$('.leaflet-control-layers').on('mouseout', function (e) {
$('.control-extend').show();
});
});

This actually doesn't work because there is apparently no way to control the vertical spacing between the radio buttons, which means that the buttons don't line up with the labels (and images).
The only example of this sort of thing I have seen that ACTUALLY WORKS is in the Leaflet Providers plug-in demo page in the package at https://github.com/leaflet-extras/leaflet-providers. What he apparently has done is to place the radio button and label on a overlay above the actual layer control, sort of like the Leaflet attribution overlay at the bottom right of most Leaflet maps...

This is what I did:
var overlayMaps = {
" <img src=\'scripts/images/eagle-icon.png\' height=\'50px\' /><br/>City Foundation Dates<br/> ": lg_cities,
" <img src=\'scripts/images/milestone.png\' height=\'50px\' /> <br/>The Golden Milestone": lg_specialMarkers
}
I tweaked my control layer with a small image...

If you want to make the check boxes prettier with low effort just add materialize icons and materialize css to your code.
This will make your layer control fancier:
This will also add a nice effect to checkboxes.
And you could also change the color of the texts, if icons make it look too busy:
this.layerControl.addOverlay(
nature,
'<span style="color: #31882A; ">Nature</span>'
);

Related

Add text box on leaflet map with selected overlay layer name

Relatively new JavaScript user here, first question.
So I have a choropleth leaflet map that uses a jQuery slider (via https://github.com/dwilhelm89/LeafletSlider) to shift between years. The map contains about 50 years of global data, with each overlay layer corresponding to a layergroup containing each country's data for the appropriate year.
The purpose of the slider is to allow the user to quickly shift between years. However, I would like a visual cue to let the user know what year is being displayed at any moment. Is it possible to display something like a text box on the map that displays the name of the current overlay layer and automatically updates whenever the overlay layer switches? (the name of each layergroup is its respective year)
I know the textbox part is certainly possible
(Overlaying a text box on a leaflet.js map), but I'm not sure how to dynamically update it with the necessary info.
Thanks! Let me know if you need my code and I'll post it.
Okay, I thought a bit and here's a quick solution.
var sliderControl = null;
var map = L.map("map").setView([51.95, 7.6], 9);
L.tileLayer("//{s}.tile.osm.org/{z}/{x}/{y}.png", {
attribution:
'© OpenStreetMap contributors',
}).addTo(map);
//Fetch some data from a GeoJSON file
$.getJSON(
"https://dwilhelm89.github.io/LeafletSlider/points.json",
function (json) {
var testlayer = L.geoJson(json);
var sliderControl = L.control.sliderControl({
position: "topright",
layer: testlayer,
range: true,
});
//Make sure to add the slider to the map ;-)
map.addControl(sliderControl);
//An initialize the slider
sliderControl.startSlider();
}
);
map.on("layeradd", function () {
map.eachLayer(function (layer) {
if (layer instanceof L.Marker) {
let desc = document.querySelector(".description");
// desc.textContent = JSON.stringify(layer.getLatLng());
desc.textContent = layer.feature.properties.time;
}
});
});
// create legend
const legend = L.control({ position: "bottomleft" });
legend.onAdd = function () {
let div = L.DomUtil.create("div", "description");
div.className = "description";
return div;
};
legend.addTo(map);
*,
:after,
:before {
box-sizing: border-box;
padding: 0;
margin: 0;
}
html {
height: 100%;
}
body,
html,
#map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.description {
border: 1px solid black;
background: #fff;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.6.0/dist/leaflet.css" />
<link rel="stylesheet" href="https://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" type="text/css">
<script src="https://unpkg.com/leaflet#1.6.0/dist/leaflet.js"></script>
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.2/jquery.ui.touch-punch.min.js"></script>
<script src="https://rawgit.com/dwilhelm89/LeafletSlider/master/SliderControl.js" type="text/javascript"></script>
<div id="map"></div>
And I recommend using the newer version of this plugin ;)
There you have the method event
And the easier way to download the data about the marker.
I've used Leaflet, Mapbox, and Google Maps on some personal and commercial projects, and whenever I wanted to overlay some information, I'd just use simple HTML elements. All you need to do is render whatever elements you want on the screen the same way you would normally, just ensure that you use correct position and applicable positioning units and ensure you have a higher z-index on your element that you want to show, i.e. your year indicator, than you do on your map element. Treat it just like you would any other HTML!
Edit:
Here is an example screenshot: https://imgur.com/a/2fXf5CI. Also, if you aren't already using a position property on your Leaflet map, you should go ahead and add a position: relative; property to the selector for the map so that you can also assign it a z-index. And then, in your year indicator's styles, give it a higher z-index value than the one you gave to your Leaflet map.

Leaflet / LayersControl / Custom buttons on mobile device

i am JS / jQuery beginner and maybe is stupid but i have problem with add + remove custom buttons to Leaflet LayersControl on mobile devices.
Description of project:
I have map with multiple layers and i need to add two buttos for check / uncheck all checkboxes (it works in example).
Here is my example and is neccessary to turn on touch simulation in browser:
https://jsfiddle.net/lukassliacky/n2ep6yg0/42/ (created and tested on Firefox).
As i said, i am JS still beginner and for me seems to be the most easiest solution adding custom HTML with after but i have problem with events on touch devices.
On desktop (non touch) it looks quite simple: in top right corner is icon for collapsed LayerControl and i am using events mouseenter and mouseleave for add and remove custom buttons. It looks fine and i think that is good and working solution (this case isn't included in my example)
And i have problem on mobile / touch devices because i don't know which events can i use for add + remove.
I think that for add event looks good e.g. click, tap or touchstart but i don't know how to remove buttons when LayerControl is expanded and it will be collapsed.
Its quiet complicated for me because i need to exlude some divs from map (LayerControl with checboxes - when i would to click on checboxes, my custom buttons will be removed)
$('#main-map:not(leaflet-control-layers-expanded > div).click(function() {
$('.leaflet-custom-buttons').remove()
})
$('.leaflet-control').click(function(e) {
e.stopPropagation();
});
When i have expanded LayersControl (with buttons) and when i click on Pin marker, buttons are removed and LayerControl is still expanded (it isn't good). In this case is LayersControl collaped after click on different object as Pin Marker.
Please, can you help me with using right events for add / remove custom buttons on mobile devices? Of course, maybe is my approach wrong and it will be necessary to rewrite my code.
Thank you
Okey, i tried different approach and seems to be a correct way.
Updated example with working custom buttons is here: https://jsfiddle.net/lukassliacky/n2ep6yg0/57/
var cities = L.layerGroup();
var secondLayer = L.layerGroup();
var thirdLayer = L.layerGroup();
L.marker([39.61, -105.02]).bindPopup('This is Littleton, CO.').addTo(cities),
L.marker([39.24, -104.39]).bindPopup('This is Denver, CO.').addTo(cities),
L.marker([39.33, -103.2]).bindPopup('This is Aurora, CO.').addTo(cities),
L.marker([39.17, -105.43]).bindPopup('This is Golden, CO.').addTo(cities);
L.marker([39.51, -105.52]).bindPopup('This is Littleton, CO.').addTo(secondLayer),
L.marker([39.34, -104.29]).bindPopup('This is Denver, CO.').addTo(secondLayer),
L.marker([39.13, -104.3]).bindPopup('This is Aurora, CO.').addTo(secondLayer),
L.marker([39.97, -105.63]).bindPopup('This is Golden, CO.').addTo(secondLayer);
L.marker([39.21, -105.52]).bindPopup('This is Littleton, CO.').addTo(thirdLayer),
L.marker([39.34, -104.09]).bindPopup('This is Denver, CO.').addTo(thirdLayer),
L.marker([39.73, -104.28]).bindPopup('This is Aurora, CO.').addTo(thirdLayer),
L.marker([39.17, -105.53]).bindPopup('This is Golden, CO.').addTo(thirdLayer);
var mbAttr = 'Map data © OpenStreetMap contributors, ' +
'Imagery © Mapbox',
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('main-map', {
center: [39.73, -104.99],
zoom: 7,
layers: [grayscale, cities, secondLayer, thirdLayer]
});
var baseLayers = {
/* "Grayscale": grayscale,
"Streets": streets */
};
var overlays = {
"Cities": cities,
"SecondLayer": secondLayer,
"ThirdLayer": thirdLayer,
};
L.Control.Custom = L.Control.Layers.extend({
onAdd: function () {
this._initLayout();
this._addCheckButton();
this._addClearButton();
this._update();
return this._container;
},
_addCheckButton: function () {
var elements = this._container.getElementsByClassName('leaflet-control-layers-list');
var button = L.DomUtil.create('button', 'btn btn-primary rounded-0 my-1 me-1 btn-xs leaflet-btn-check-all', elements[0]);
button.textContent = 'Check All';
L.DomEvent.on(button, 'click', function(e){
L.DomEvent.stop(e);
// fire this function (check all)
$('.leaflet-control input[type="checkbox"]').trigger('click').prop('checked', true);
}, this);
},
_addClearButton: function () {
var elements = this._container.getElementsByClassName('leaflet-control-layers-list');
var button = L.DomUtil.create('button', 'btn btn-primary rounded-0 my-1 btn-xs w-50 leaflet-btn-check-all', elements[0]);
button.textContent = 'Clear All';
L.DomEvent.on(button, 'click', function(e){
L.DomEvent.stop(e);
// fire this function (uncheck all)
$('.leaflet-control input[type="checkbox"]').trigger('click').prop('checked', false);
}, this);
}
});
new L.Control.Custom(
baseLayers,
overlays,
{collapsed:true}).addTo(map);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.1/dist/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.1/dist/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-locatecontrol/0.74.0/L.Control.Locate.min.js"></script>
<link href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css" rel="stylesheet"/>
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js"></script>
<style>
html, body {
height: 100%;
margin: 0;
}
#main-map {
width: 100%;
height: 500px;
}
</style>
</head>
<body>
<div id='main-map'></div>
My solution is based on https://embed.plnkr.co/Je7c0m/ and i am really thank to author.
Grzegorz T. thank you for your support too.

Dojo/Dijit TooltipDialog.open: How to override offsetHeight and offsetTop values

Currently trying to implement/solve an issue with an ESRI ArcGIS map environment where I have a multi-layered map with custom graphics being rendered in each layer. Some of the graphics are simple shapes such as lines and circles, but a majority of the graphics are icons (.png) files that are being drawn on the layers. (All of this is being done in JavaScript.)
I have been able to get all of the layers generated correctly - the data IS NOT being stored in ArcGIS maps but a custom designed Contact & Location database (SQL) and other forms within the web application maintain this C&L data.
The graphic icons that are rendered on the map need to have a mouse-over tooltip popup appear with information that has been stored with the icon when it is created where the .substitute() command will update the template. The information displayed is HTML formatted in a <div>.
Problem:
When the mouse is moved over an icon, the tooltipDialog appears but 1) it always appears in the lower right corner of the screen - despite "orient:" and specific "x:" and "y:" coordinates being specified. Additionally when the tooltipDialog.open() command is executed, the dialog's offsetHeight is set to 624 and the offsetTop is set to 502. (The offsetWidth is actually set to the correct value.) How do I override either/both the offsetHeight/offsetTop?
I have tried specifying additional parameters to the tooltipDialog.open() command but nothing tried so far has altered the outcome. Even when I change the template content to be as simple as "Hi There!" does not change the outcome.
Note: If I click on an icon the IconWindow dialog will popup with the proper content and formatting being displayed. So it leads me to believe that the issue is within CSS or some other aspect of dojo/dijit as the tooltipDialog.open() command is actually where the offset changes are being made - the values are retained (offsetTop=0 offsetHeight=0) prior to the open() call.
Ideas/Recommendations?
You could try to use the dijit/popup module to open the TooltipDialog, which would allow you to pass in the DOM node around which the tooltip should be opened:
popup.open({
popup: myTooltipDialog,
around: dom.byId('thenode')
});
There a full example of this here (next to "A TooltipDialog may be popped up from any node.")
Well, It seems like you want to show info popup with some offset value whenever you hover on any feature on the map.
Solution-
Well to do so i don't think you need to deal with TooltipDialog because whenever you are loading feature or feature layer on the map you can attach info popup to it. It will take care of entire loading and displaying info popup Dialog along with its positioning.
To pass offset value-
If want to pass some offset value to popup dialog you can use below mentioned properties:-
For more Properties of popup dialog refer this link- https://developers.arcgis.com/javascript/3/jsapi/popup.html
Hovering Dialog sample-
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
<title>Feature Layer - display results as an InfoWindow onHover</title>
<link rel="stylesheet" href="https://js.arcgis.com/3.18/dijit/themes/tundra/tundra.css">
<link rel="stylesheet" href="https://js.arcgis.com/3.18/esri/css/esri.css">
<style>
html, body, #mapDiv {
padding:0;
margin:0;
height:100%;
}
#mapDiv {
position: relative;
}
#info {
background: #fff;
box-shadow: 0 0 5px #888;
left: 1em;
padding: 0.5em;
position: absolute;
top: 1em;
z-index: 40;
}
</style>
<script src="https://js.arcgis.com/3.18/"></script>
<script>
var map, dialog;
require([
"esri/map", "esri/layers/FeatureLayer",
"esri/symbols/SimpleFillSymbol", "esri/symbols/SimpleLineSymbol",
"esri/renderers/SimpleRenderer", "esri/graphic", "esri/lang",
"esri/Color", "dojo/number", "dojo/dom-style",
"dijit/TooltipDialog", "dijit/popup", "dojo/domReady!"
], function(
Map, FeatureLayer,
SimpleFillSymbol, SimpleLineSymbol,
SimpleRenderer, Graphic, esriLang,
Color, number, domStyle,
TooltipDialog, dijitPopup
) {
map = new Map("mapDiv", {
basemap: "streets",
center: [-80.94, 33.646],
zoom: 8,
slider: false
});
var southCarolinaCounties = new FeatureLayer("https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/3", {
mode: FeatureLayer.MODE_SNAPSHOT,
outFields: ["NAME", "POP2000", "POP2007", "POP00_SQMI", "POP07_SQMI"]
});
southCarolinaCounties.setDefinitionExpression("STATE_NAME = 'South Carolina'");
var symbol = new SimpleFillSymbol(
SimpleFillSymbol.STYLE_SOLID,
new SimpleLineSymbol(
SimpleLineSymbol.STYLE_SOLID,
new Color([255,255,255,0.35]),
1
),
new Color([125,125,125,0.35])
);
southCarolinaCounties.setRenderer(new SimpleRenderer(symbol));
map.addLayer(southCarolinaCounties);
map.infoWindow.resize(245,125);
dialog = new TooltipDialog({
id: "tooltipDialog",
style: "position: absolute; width: 250px; font: normal normal normal 10pt Helvetica;z-index:100"
});
dialog.startup();
var highlightSymbol = new SimpleFillSymbol(
SimpleFillSymbol.STYLE_SOLID,
new SimpleLineSymbol(
SimpleLineSymbol.STYLE_SOLID,
new Color([255,0,0]), 3
),
new Color([125,125,125,0.35])
);
//close the dialog when the mouse leaves the highlight graphic
map.on("load", function(){
map.graphics.enableMouseEvents();
map.graphics.on("mouse-out", closeDialog);
});
//listen for when the onMouseOver event fires on the countiesGraphicsLayer
//when fired, create a new graphic with the geometry from the event.graphic and add it to the maps graphics layer
southCarolinaCounties.on("mouse-over", function(evt){
var t = "<b>${NAME}</b><hr><b>2000 Population: </b>${POP2000:NumberFormat}<br>"
+ "<b>2000 Population per Sq. Mi.: </b>${POP00_SQMI:NumberFormat}<br>"
+ "<b>2007 Population: </b>${POP2007:NumberFormat}<br>"
+ "<b>2007 Population per Sq. Mi.: </b>${POP07_SQMI:NumberFormat}";
var content = esriLang.substitute(evt.graphic.attributes,t);
var highlightGraphic = new Graphic(evt.graphic.geometry,highlightSymbol);
map.graphics.add(highlightGraphic);
dialog.setContent(content);
domStyle.set(dialog.domNode, "opacity", 0.85);
dijitPopup.open({
popup: dialog,
x: evt.pageX,
y: evt.pageY
});
});
function closeDialog() {
map.graphics.clear();
dijitPopup.close(dialog);
}
});
</script>
</head>
<body class="tundra">
<div id="mapDiv">
<div id="info">
Hover over a county in South Carolina to get more information.
</div>
</div>
</body>
</html>
Hoping this will help you :)
However its always recommended to add your code here if you are looking for exact Fix.
Found the answer to my situation. There is what appears to be an unstated requirement that either one of the supplied CSS dijit/themes be utilized OR the user must create their own theme which has some CSS that configures the display location.
The offsetTop issue was resolved by using eliminating any style references to top:.

Moving a Marker after Locate function is called

I trying to move the created movable marker so that it points to the results of the Locate() function.
This would allow the recalculation of the other closest markers in the datasource.
Presently, this works only when I manually drag the movable matker.
I can't seem to be able to get the coordinates of the location found and move the marker there.
Thanks for any help!
Here's my code:
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Reorder marker list based on proximity</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox.js/v2.1.9/mapbox.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox.js/v2.1.9/mapbox.css' rel='stylesheet' />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<style>
.info {
background:#fff;
position: fixed;
width:90%;
top:70%;
right:5%;
left:5%;
bottom: 5%;
border-radius:2px;
max-height:30%;
overflow:auto;
}
.info .item {
display:block;
border-bottom:1px solid #eee;
padding:5px;
text-decoration:none;
}
.info .item small { color:#888; }
.info .item:hover,
.info .item.active { background:#f8f8f8; }
.info .item:last-child { border-bottom:none; }
</style>
<script src='https://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-omnivore/v0.2.0/leaflet-omnivore.min.js'></script>
<script src='https://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-locatecontrol/v0.42.0/L.Control.Locate.min.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-locatecontrol/v0.42.0/L.Control.Locate.mapbox.css' rel='stylesheet' />
<!--[if lt IE 9]>
<link href='https://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-locatecontrol/v0.42.0/L.Control.Locate.ie.css' rel='stylesheet' />
<![endif]-->
<div id='map' class='map'></div>
<div id='info' class='info'></div>
<script>
L.mapbox.accessToken = 'pk.eyJ1IjoiamZnaWFyZCIsImEiOiJ6S09PVU5vIn0.kn_-BVWarxfNjT1hak0kyA';
var map = L.mapbox.map('map', 'jfgiard.9dee89eb')
.setView([51.953608, 36.776667], 4);
var info = document.getElementById('info');
// create control and add to map
var lc = L.control.locate({
position: 'topleft', // set the location of the control
drawCircle: true, // controls whether a circle is drawn that shows the uncertainty about the location
follow: false, // follow the user's location
setView: true, // automatically sets the map view to the user's location, enabled if `follow` is true
keepCurrentZoomLevel: true, // keep the current map zoom level when displaying the user's location. (if `false`, use maxZoom)
stopFollowingOnDrag: false, // stop following when the map is dragged if `follow` is true (deprecated, see below)
remainActive: false, // if true locate control remains active on click even if the user's location is in view.
markerClass: L.circleMarker, // L.circleMarker or L.marker
circleStyle: {}, // change the style of the circle around the user's location
markerStyle: {},
followCircleStyle: {}, // set difference for the style of the circle around the user's location while following
followMarkerStyle: {},
icon: 'fa fa-map-marker', // class for icon, fa-location-arrow or fa-map-marker
iconLoading: 'fa fa-spinner fa-spin', // class for loading icon
circlePadding: [0, 0], // padding around accuracy circle, value is passed to setBounds
metric: true, // use metric or imperial units
onLocationError: function(err) {alert(err.message)}, // define an error callback function
onLocationOutsideMapBounds: function(context) { // called when outside map boundaries
alert(context.options.strings.outsideMapBoundsMsg);
},
showPopup: true, // display a popup when the user click on the inner marker
strings: {
title: "Show me where I am", // title of the locate control
popup: "You are within {distance} {unit} from this point", // text to appear if user clicks on circle
outsideMapBoundsMsg: "You seem located outside the boundaries of the map" // default message for onLocationOutsideMapBounds
},
locateOptions: {} // define location options e.g enableHighAccuracy: true or maxZoom: 10
}).addTo(map);
// Creates a single, draggable marker on the page.
var m = L.marker(new L.LatLng(51.953608, 36.776667), {
icon: L.mapbox.marker.icon({
'marker-color': '#000000',
'marker-size': 'large'
}),
draggable: true
}).bindPopup('Drag me around the map to simulate GeoLocalization!').addTo(map);
// Repopulate the features layer in the menu listing based on the dragged markers proximity to them.
// console.log(marker.getLatLng());
m.on('dragend', function() {
populateListing();
});
// Load the features from the CSV files.
var features = omnivore.csv('NMOandHTC.csv')
.on('ready', function(layer) {
// Customizing marker styles based on an attribute.
this.eachLayer(function(marker) {
if (marker.toGeoJSON().properties.type === 'National Member Organization') {
// The argument to L.mapbox.marker.icon is based on the simplestyle-spec: see that specification for a full description of options.
marker.setIcon(L.mapbox.marker.icon({
'marker-color': '#e31837',
'marker-size': 'medium'
}));
} else {
marker.setIcon(L.mapbox.marker.icon({
'marker-color': '#616265',
'marker-size': 'small'
}));
}
// Bind a popup to each icon based on the same properties
marker.bindPopup(marker.toGeoJSON().properties.name + '<br>' + marker.toGeoJSON().properties.country);
});
})
.addTo(map);
map.on('ready', function() {
// Display the tooltip after the marker has been added to the map.
m.openPopup();
});
// When the features layer is ready (added to the map), run populateListing.
features.on('ready', populateListing);
function populateListing() {
// Clear out the listing container first.
info.innerHTML = '';
var listings = [];
// Build a listing of markers
features.eachLayer(function(marker) {
// Draggable marker coordinates.
var home = m.getLatLng();
var metresToMiles = 0.000621371192;
var distance = (metresToMiles * home.distanceTo(marker.getLatLng())).toFixed(1);
var link = document.createElement('a');
link.className = 'item';
link.href = '#';
link.setAttribute('data-distance', distance);
// Populate content from each markers object.
link.innerHTML = marker.feature.properties.type + '<br />' + marker.feature.properties.name + '<br />' +
'<small>' + distance + ' mi. away</small>';
link.onclick = function() {
if (/active/.test(this.className)) {
this.className = this.className.replace(/active/, '').replace(/\s\s*$/, '');
} else {
var siblings = info.getElementsByTagName('a');
for (var i = 0; i < siblings.length; i++) {
siblings[i].className = siblings[i].className
.replace(/active/, '').replace(/\s\s*$/, '');
};
this.className += ' active';
// When a menu item is clicked, animate the map to center
// its associated marker and open its popup.
map.panTo(marker.getLatLng());
marker.openPopup();
}
return false;
};
listings.push(link);
});
// Sort the listing based on the
// assigned attribute, 'data-listing'
listings.sort(function(a, b) {
return a.getAttribute('data-distance') - b.getAttribute('data-distance');
});
listings.forEach(function(listing) {
info.appendChild(listing);
});
}
</script>
</body>
</html>
Is L.control.locate really needed here? Why not just call map.locate() after binding an callback to locationfound with map.on('locationfound, dostuff) Your function receives the results of the geolocation and can proceed from there.

geographic chart by nation

I need to implement a chart like geographic chart which is an image of America seperated by state by state. And then, based on data for each state, it will the chart will display state by color.
For example we have
California : 20 products
Texas: 100 products
Ohio: 5 products
.....
If the number of product for a state > 20, then display that state with GREEN color, or else, display it with RED color
Until now I have no ideas how to do it.
I intend to split the America Map into 50 divs and color it, but it is not effective.
There are some geo chart frameworks, for example Google Geo Chart, though it is not fully customizeable.
But you can do it by using the jVectorMap framework. Download jVectorMap 1.2.2, also choose some map of the USA (I used the Mercator and you can use the following code:
<head>
<link rel="stylesheet" href="jquery-jvectormap-1.2.2.css" type="text/css" />
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.0.min.js"></script>
<script type="text/javascript" src="jquery-jvectormap-1.2.2.min.js"></script>
<script type="text/javascript" src="http://jvectormap.com/js/jquery-jvectormap-us-merc-en.js"></script>
<script type="text/javascript">
$(function(){
var data = { "US-CA": 20, "US-TX": 100, "US-OH": 5 };
var colors = {};
// create an object with colors
for (var key in data) {
var value = data[key];
colors[value] = value > 20 ? "#00FF00" : "#FF0000";
}
$('#map_canvas').vectorMap({
map: 'us_merc_en',
series: {
regions: [{
values: data,
scale: colors
}]
}
});
});
</script>
</head>
<body>
<div id="map_canvas" style="width: 400px; height: 300px;"></div>
</body>
The color assigning part in the for loop is quite tricky because of some limitations of the framework. Also it requires special naming for states like US-CA. But in result you will see green Texas and red California with Ohio.
Also the framework is open source and if you need some more complex functionality, you can update the code yourself.

Categories

Resources