javascript map in leaflet how to refresh - javascript

i have a basic geoJson program in javascript by using leaflet API.
<html>
<head>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.js"></script>
<script src="india.js" type="text/javascript"></script>
</head>
<body>
<div id = "map1" style="width: 1100px; height: 400px"> </div>
<script>
var area = L.map('map1', {center: [27.8800,78.0800], zoom: 4 });
L.tileLayer('http://a.tiles.mapbox.com/v3/raj333.map-gugr5h08/{z}/{x}/{y}.png').addTo(area);
var indiaLayer= L.geoJson(india, {style: {weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.1}});
area.addLayer(indiaLayer);
function clicked(){
this.options.style.fillOpacity = 0.8;
//how to refresh layer in the given map
}
indiaLayer.on('click', clicked);
</script>
</body>
</html>
the problem is how would i automatically refresh the content of Layer on the map.
example here
function clicked(){
indiaLayer.style.fillOpacity = 0.8;
//how to refresh layer in the given map
}
indiaLayer.on('click', clicked);
when user click on indiaLayer , the fillOpacity variable changes but doesn't reflect back on map which is understood since i am not refreshing the map. I don't know how to do it.
please help
P/s: these are the functions available on indiaLayer object (i.e. this object inside clicked function...which one to use for this purpose or there exist none)
You can check the list of methods available of GEOJson in the Leaflef documentation This is the link to v.0.7.7, which is the closest available to used in this example.

Last time I've used
map._onResize();
and that help me refresh map. Maybe a little hack, but, it work.
In your code will be area._onResize()
P.S: Maybe you should try change the way to set new opacity value - try change
function clicked(){
this.options.style.fillOpacity = 0.8;
}
to that
function clicked(){
this.setStyle({fillOpacity: 0.2});
}

map.invalidateSize();
map._onResize() - it's a hack, and there is no guarantee that it won't be removed in future versions.

area.fitBounds(area.getBounds());

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 MarkerCluster: Is it possible to open multiple cluster-groups?

I have recently started working with leaflet. I found the great plugin leaflet markercluster. I am currently trying to open several clustergroups at the same time. Unfortunately I can't find anything on google.
I have several cluster groups and draw connections from one marker to another. The user should be able to open both cluster groups to which the drawn line goes:
Therefore my question: Is there a function for this that I have to switch on or is opening several groups at the same time not provided at all?
Okay I have experimented a little bit on it now ;)
In the leaflet.markercluster-src.js I created an array called _spiderMan[] which is filled with the clicked objects in the function spiderfy.
spiderfy: function() {
if (this._group._spiderfied === this || this._group._inZoomAnimation) {
return;
}
var childMarkers = this.getAllChildMarkers(null, true),
group = this._group,
map = group._map,
center = map.latLngToLayerPoint(this._latlng),
positions;
// this._group._unspiderfy(); //deactivated
var markers = markers + childMarkers;
_spiderMan.push(this); //new
if (childMarkers.length >= this._circleSpiralSwitchover) {
positions = this._generatePointsSpiral(childMarkers.length, center);
} else {
center.y += 10;
positions = this._generatePointsCircle(childMarkers.length, center);
}
this._animationSpiderfy(childMarkers, positions);
},
Then I have created a for loop which runs through the array and calls _spiderMan[i].unspiderfy(zoomDetails) every time. I built this loop into the function _unspiderfyZoomAnim for testing. Means every time you zoom in or out, all open groups are summarized.
_unspiderfyZoomAnim: function(zoomDetails) {
if (L.DomUtil.hasClass(this._map._mapPane, 'leaflet-touching')) {
return;
}
this._map.off('zoomanim', this._unspiderfyZoomAnim, this);
var i;
for (i = 0; i < _spiderMan.length; i++) {
_spiderMan[i].unspiderfy(zoomDetails);
}
_spiderMan = [];
},
In addition, the following lines must be deactivated in the unspiderfy function:
unspiderfy: function(zoomDetails) {
/// <param Name="zoomDetails">Argument from zoomanim if being called in a zoom animation or null otherwise</param>
// if (this._group._inZoomAnimation) {
// return;
// }
this._animationUnspiderfy(zoomDetails);
// this._group._spiderfied = null;
},
So it's now possible to open and close mutiple cluster-groups but this is only a workaround and I think it will have some bad effects somewhere because of commenting out or removing code lines.
I think someone with more experience in JS and this plugin should find a better and more comfortable solution ;).
Welcome to SO!
Unfortunately, the spiderfication management in Leaflet.markercluster plugin currently assumes a single cluster can be spiderfied at a time.
See also danzel's comment in Leaflet.markercluster issue #744 (Spiderfy all clusters at a particular view):
Leaflet.MarkerCluster only supports having one cluster spiderfied at the moment, so this would need a bit of work to support.
May be you will get a better answer if you give a use case ...
However, it is safe to say that there is no function you can switch on to open several groups in one click.
From a usability point of view, it does not make much sense as the basic behaviour of MarkerCluster is to click on one icon to zoom in and expand the group you are interested in.
Quoting from https://github.com/Leaflet/Leaflet.markercluster#other-clusters-methods :
spiderfy: Spiderfies the child markers of this cluster
unspiderfy: Unspiderfies a cluster (opposite of spiderfy)
So once you have references to the clusters you want to "open" (spiderify) at the same time, just call their .spiderify() method.
e.g. if the desired clusters are in variables cluster1 and cluster2:
cluster1.spiderify();
cluster2.spiderify();
See also https://github.com/Leaflet/Leaflet.markercluster#getting-the-visible-parent-of-a-marker and https://github.com/Leaflet/Leaflet.markercluster#clusters-methods about how to get references to the clusters.
As far as I can tell you can keep open multiple clusters, but only one for each group. My guess is that your markers all belong to a single group. In which case you can't keep open multiple clusters.
You could opt for a hover approach, which opens a cluster if you hover over it.
const mymap = L.map('mapid').setView([48.550, 8.207], 6);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
maxZoom: 18,
id: 'mapbox.streets'
}).addTo(mymap);
const markers = L.markerClusterGroup({zoomToBoundsOnClick: false});
[[47.5617, 7.5504], [47.5255, 7.6163], [47.5691, 7.6355],
[49.4922, 8.3922], [49.5306, 8.5172], [49.4547, 8.5062]]
.map(latLng => L.marker(latLng))
.forEach(marker => markers.addLayer(marker));
mymap.addLayer(markers);
markers.on("clustermouseover", a => a.layer.spiderfy());
markers.on("clustermouseout", a => a.layer.unspiderfy());
html, body, #mapid { margin: auto; height: 100%; }
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.5.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.5.1/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster#1.4.1/dist/MarkerCluster.Default.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster#1.4.1/dist/MarkerCluster.css" />
<script src="https://unpkg.com/leaflet.markercluster#1.4.1/dist/leaflet.markercluster.js"></script>
<div id="mapid"></div>

Google Maps API not showing (fixed height / width does not solve)

Showing the map was working before but for some reason I can't really figure it stopped working.
Here is my html inclusion:
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=THIS_KEY_IS_CORRECT">
</script>
And here is my html:
(with style tags)
#map { height: 500px; }
<div id="map" > </div>
And my javascript
setTimeout(() => {
console.log("Running init map");
var map_div = document.getElementById("map");
var map_handler = new google.maps.Map(map_div, map_options);
console.log(map_handler);
},2000);
Here is the console log of map_handler:
ug {__gm: Yf, W: undefined, mapTypes: Object, features: Object, overlayMapTypes: _.td…}
So map_handler is actually returning something.
As I said, this used to work. For some reason it does not anymore.
Any idea why?
Thank you very much.
While this isn't the primary source of your issue - please note that you can't rely on setTimeout to tell you when the google maps JS API has been loaded. Use a callback:
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=THIS_KEY_IS_CORRECT&callback=myMapIsReady">
</script>
And then
<script>
var myMapIsReady = function() {
console.log("Running init map");
var map_div = document.getElementById("map");
var map_handler = new google.maps.Map(map_div, map_options);
console.log(map_handler);
};
</script>
Here's the question, why are you saying this isn't working? How is it not working? What do you see on your screen?
A hint might be what is map_options you haven't shown where it is defined and if you init a google map with no center latlng/zoom, you'll just see a grey block.

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:.

leaflet api event listener argument access

I am using leaflet api with L.geoJson. the parts of code are
var indiaLayer= L.geoJson(india, {style: {weight: 2,
opacity: 1,
color: '#F7BE81',
dashArray: '10',
fillOpacity: 0.2}});
now i define an event listener on indiaLayer as
indiaLayer.on('click', clicked);
now if i want to access the first argument i.e. india inside clicked function, what should i use?. I consulted dom tree and figured out it to be
alert(this._layers.22.feature.id);
but it throws syntax error. can anyone help me out of it? thank you
i am attaching full code also
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.js"></script>
<script src="india.js" type="text/javascript"></script>
</head>
<body>
<div id = "map1" style="width: 1100px; height: 400px"> </div>
<div id = "zoom" style="width: 100px; height: 100px"></div>
<div id = "select" style="width: 100px; height:100px"></div>
<script>
var area = L.map('map1', {center: [27.8800,78.0800], zoom: 4 });
L.tileLayer('http://a.tiles.mapbox.com/v3/raj333.map-gugr5h08/{z}/{x}/{y}.png').addTo(area);
function zoomDeal()
{
var zoom=document.getElementById("zoom");
zoom.innerHTML= area.getZoom();
}
area.on('zoomend',zoomDeal);
var indiaLayer= L.geoJson(india, {style: {weight: 2,
opacity: 1,
color: '#F7BE81',
dashArray: '10',
fillOpacity: 0.2}});
area.addLayer(indiaLayer);
function clicked(){
if (area.getZoom() == 4) {
if (this.options.style.fillOpacity == 0.5)
{
this.setStyle({fillOpacity: 0.2});
this.options.style.fillOpacity=0.2;
var select = document.getElementById("select");
select.innerHTML = "";
}
else
{
this.setStyle({fillOpacity: 0.5});
this.options.style.fillOpacity=0.5;
var select = document.getElementById("select");
//select.innerHTML = "india";
alert(this._layers.22.feature.id);
}
}
}
indiaLayer.on('click', clicked);
</script>
</body>
</html>
Using the specific leaflet given id in the click handler can result in problems, as Leaflet might assign a different id if you load somewhere else.
The click handler on default throws in the event argument. Meaning that if you'd change your clicked function definition to:
function clicked (e) {
// do stuff etc.
}
You would be able to access the origin of the click (with e.target). In this case the layer.
Even nicer would be adding an onEachFeature function to the layer definition (where it reads out the JSON). Like in the example here: http://leafletjs.com/examples/geojson.html
The onEachFeature (http://leafletjs.com/reference.html#geojson-oneachfeature) gives you direct access to the feature that you try to access so to do what you want e.g.:
L.geoJson(india, {
onEachFeature: function (feature, layer) {
layer.on('click', function (e) {
alert(e.target.feature.id)
})
}
});

Categories

Resources