Display div elements based on leaflet js base map selection - javascript

I have various baselayers on my leaflet map. I've also created div elements that correspond to each of those layers. I need to show and hide those div elements based on which baselayer is actually in use. I do not want all the div elements on the page simulatenously.
I've tried to use jQuery .show() & .hide() & .toggle() but haven't been able to get these to work. I need my .cuomoinfo & .nixoninfo to be hidden by default and then show based on which baselayer is in use.
var baselayers = {
"Andrew Cuomo Votes": CuomoLayer,
"Cynthia Nixon Votes": NixonLayer,
"Total Votes Cast": totalvotecountlayer,
};
var overlays = {
"NYS Assembly Districts": AssemblyOverlay,
"NYC Council Districts": CouncilOverlay,
};
L.control.layers(baselayers, overlays).addTo(mymap);
// creating a custom div that changes the ed information within it based on mouseover
var cuomoinfo = L.control();
cuomoinfo.onAdd = function (cuomomap) {
this._div = L.DomUtil.create('div', 'cuomoinfo'); // create a div with a class "info"
this.update();
return this._div;
};
// method that we will use to update the control based on feature properties passed
cuomoinfo.update = function (cuomoprops) {
this._div.innerHTML = '<h4>Votes for Andrew M. Cuomo</h4>' + (cuomoprops ?
'<b>' + cuomoprops.ElectDist + '</b><br/>' + cuomoprops.QueensCountyGovernorDemocraticPrimarySept2018_Cuomo + ' votes cast'
: 'Hover over an Electrion District to see voting results');
};
cuomoinfo.addTo(mymap);
$('.cuomoinfo').hide()

Related

How to Rewrite an onclick() Function in my Javascript to Call a Function

I created a map using Leaflet with clusters. I wanted to add a popup when you click the cluster and it will show a popup list of names of the markers inside the cluster. I found a code and it does exactly what I’m looking for: a list popup showing the names of the markers inside the cluster and when you click on the different names on the popup list the related marker popup appears. But when I added the code to my project, I get the error, “reference error onclick is not defined” and the function won't run. I research this error and I found it’s not good practice to use the onclick function in my javascript/HTML in the way the code is written. My question is, how do I rewrite the script to work the way the example I’m using. Here’s a link to the example I’m using to show what I’m trying to accomplish (and this example works when I download it and run it…no error) - http://www.digital-geography.com/working-with-clusters-in-leaflet-increasing-useability/. And I also included my script. Any help on how to make this work will greatly be appreciated. Or, I’m open to achieve this in a different way. Thanks in advance!
function openPopUp(id, clusterId){
map.closePopup(); //which will close all popups
map.eachLayer(function(layer){ //iterate over map layer
if (layer._leaflet_id == clusterId){ // if layer is markerCluster
layer.spiderfy(); //spiederfies our cluster
}
});
map.eachLayer(function(layer){//iterate over map rather than clusters
if (layer._leaflet_id == id){// if layer is marker
layer.openPopup();
}
});
markers.on('clusterclick', function(a){
if(a.layer._zoom == 6){
var myText = '<ul>';
for (feat in a.layer._markers){
myText += '<li><u onclick="openPopUp"(' + a.layer._markers[feat]._leaflet_id + ',' + a.layer._leaflet_id + ')>' + a.layer._markers[feat].feature.properties['cityName2'] + ',' + a.layer._markers[feat].feature.properties['cityName2'] + '</u></li>';
}
myText += '</u>';
var popup = L.popup().setLatLng([a.layer._cLatLng.lat,a.layer._cLatLng.lng]).setContent(myText).openOn(map);
}
})
Because .setContent can accept an HTMLElement rather than just an HTML string, all you need to do is pass in an element with the listener attached, instead of the HTML string - construct the elements explicitly with createElement, and use addEventListener on the element you want to attach the listener to:
markers.on('clusterclick', function(a) {
if (a.layer._zoom !== 6) return;
const ul = document.createElement('ul');
a.layer._markers.forEach(({ _leaflet_id, feature }) => {
const { cityName2 } = feature.properties;
const li = ul.appendChild(document.createElement('li'));
const u = li.appendChild(document.createElement('u'));
u.addEventListener('click', () => openPopUp(_leaflet_id, a.layer._leaflet_id));
u.textContent = cityName2 + ',' + cityName2;
});
const popup = L
.popup()
.setLatLng([a.layer._cLatLng.lat, a.layer._cLatLng.lng])
.setContent(ul)
.openOn(map);
})

How to test the value of a label

I have a list of news and I can modify the news. When I modify one she stay at her inital position (if she was at place 5 she stay here). But when I click "modify this new" a form pop to the bottom of the page and then when I submit the modifications I want to scroll to this modified new. To do that I would use something like
find position where label.text() == titleModified
then I could do
window.scrollTo(0,result of the line above);
For the moment I tried to do document.getElementById but it always bring me to the top of the page...
Thank you for helping me
PS: there is a link on Plunker to see the structure of news : https://plnkr.co/edit/mLCxPYaBR56KkEOLNF8F?p=preview
and this is my JS for the modification:
'submit .modifyArticle'(event) {
event.preventDefault();
const target = event.target;
const textModif = target.textModif.value;
const titreModif = target.titreModif.value;
const photoModif = target.photoModif.value;
const idModif = Session.get('idTemp');
//test if values from the from are not empty or whitespaced
if ((/\S/.test(textModif))||(/\S/.test(titreModif))) {
console.log("2ème étape: dans body.js -> submit .modifyArticle");
Meteor.call('articles.modify',idModif,textModif,titreModif,photoModif);
Session.set('wantModif',false);
//here my new is modified so I want to scroll to her
//var titreModified actually contains the title after the modification but only for the first new...
setTimeout(function(){
var titreModified = document.getElementById("titreArticle");
var position = titreModified.offsetTop;
console.log("Y: " + position);
console.log("var titreArticleModif: "+ titreModified.textContent);
}, 50)
[...]
EDIT (i'll put the solution here but the real hero is #alexr101): First I had to add a class to my label <label class="titreArticle">{{titre}}</label>
then this is the JS:
`setTimeout(function(){
$('.titreArticle').each(function(i, obj) {
if(obj.textContent.includes(titreModif)){
alert("le titre devrait être: " + obj.textContent);
var position = obj.offsetTop;
window.scrollTo(0,position);
return false;
}
});
}, 20)`
the timeout is here because it's not 100% real-time and I had to wait until the new title was put in the DOM.
Try getting the y position of the element like so:
//get modified element
var titleModified = document.getElementById("modifiedElement");
//get y position of element through offsetTop function
var yPosition = titleModified.offsetTop;
//Set scroll amount
window.scrollTo(0, yPosition );
Would that work?

Add Custom Default Places In Google Places AutoComplete

I want to make an input with autocomplete use google places API. And this is my code:
var options = {
componentRestrictions: {
country: "de"
}
};
var place = '';
var locationAutocompleteOneWay = document.getElementById('locationAutocompleteOneWay');
var autocompleteLocationOneWay = new google.maps.places.Autocomplete(locationAutocompleteOneWay, options);
google.maps.event.addListener(autocompleteLocationOneWay, 'place_changed', function() {
place = autocompleteLocationOneWay.getPlace();
});
For more customize, I want to add some custom place result when I input in the textbox. Here my code and result:
setTimeout(function() {
$(".pac-container").append('<div id="areasearch" class="pac-item areasearch"><span class="pac-icon pac-icon-areas"></span><span class="pac-item-query"><span class="pac-matched"></span>Test place</span> <span>custom place</span></div>');
}, 500);
But I want when I click on the result, it make my input locationAutocompleteOneWay has had a value of the result. But I don't know how to make it. And I want it can apply for multi-input on the page. I use it by jQuery and AngularJS. All solution of Jquery and AngularJS is good for me. Thank in advanced.
What I found is that, if you load the custom locations you're adding with attributes that can be used to set the lat/lng (and anything else you need), then you can bind to the mousedown event to assign a custom place object to the autocomplete.
In my script, I have the following snippet adding an item to the autocompletes (this adds to all auto-complete elements on the page):
$(".pac-container").append('<div id="areasearch' + i + '" class="pac-item areasearch custom" val="' + PlaceName + '" lat="' + Latitude + '" lng="' + Longitude + '" style="display: none;"><span class="pac-icon pac-icon-areas"></span><span class="pac-item-query"><span class="pac-matched"></span>' + PlaceName + '</span> <span>' + LocationName + '</span></div>');
Using the classes pac-item and custom, I then bind as follows:
setTimeout(function () {
$("div.pac-item.custom").mousedown(function () {
setCustomLocation($(this));
})
}, 100);
And the custom location function is:
setCustomLocation = function (obj) {
$("#" + currInput).val($(obj).attr("val"));
var newObj = {};
newObj["geometry"] = {}
newObj["geometry"]["location"] = {}
newObj["geometry"]["location"]["lat"] = function () { return $(obj).attr("lat"); }
newObj["geometry"]["location"]["lng"] = function () { return $(obj).attr("lng"); }
currAutocomplete.set("place", newObj);
}
The first line sets the name into the active input field, and the rest sets the place object for the active autocomplete (both variables captured in other events). The only values I needed for the project was the geometry lat/lng pair, but if you need more, just load it with whatever values you need to retrieve from the parent.

hiding a child layer name link from mapbox and then making it visible when its parent layer is clicked

I have an array of mapLayers coming in from a table in sql. These mapLayers have parent layers which contain one or more child layers. The element a that is being created is the one that holds the name of the layer
I would like to make the layer name to the parent layer visible by default and then only make the child layer names visible when the parent layer is clicked.
The kind of functionality I'm seeking is similar to that of the bootstrap accordion. My index emp[2] != null is what determines if the layer has a parent or not (if its a child).Iif it is a child I would like to hide it then only display when the parent is clicked, but since there is no ID on the "a" tag I am not sure how to set the onClick event. Also if I assing ID to a each time its created it will mean a will always have the same ID and that will cause problems.
$.when(getSecureData("/api/layers/"))
.then(function (retmaplayers) {
for (i = 0; i < retmaplayers.length; i++) {
addLayer(map, L.mapbox.tileLayer(retmaplayers[i][1]), retmaplayers[i][0], i + 1);
$.each(retmaplayers, function (index, emp) {
// pageViewModel.LocationViewModel.parentID(emp.fullname);
if (emp[2] != null)
{
pageViewModel.locationVM.parentID(1)
}
function addLayer(map, layer, name, zIndex) {
var layers = document.getElementById('menu-ui');
layer.setZIndex(zIndex)
layer.addTo(map);
// Create a simple layer switcher that
// toggles layers on and off.
var link = document.createElement('a');
link.href = '#';
if (zIndex == 1) {
link.className = 'active';
// link.class = 'accordion-toggle';
if(pageViewModel.locationVM.parentID()==1)
{
link.style.visibility = "hidden";
}
}
else {
map.removeLayer(layer);
this.className = '';
}
link.innerHTML = name;
if (zIndex != 1) {
link.onclick = function (e) {
e.preventDefault();
e.stopPropagation();
if (map.hasLayer(layer)) {
map.removeLayer(layer);
this.className = '';
} else {
layer.setOpacity(1.0);
map.addLayer(layer);
this.className = 'active';
}
};
}
layers.appendChild(link);
since there is no ID on the "a" tag I am not sure how to set the
onClick event
In general, you don't use elements' ids in Knockout (at least not in your viewmodel code), and in particular, you don't set onClick events. You use the click binding on the clickable element.
You do not seem to be embracing the spirit of Knockout, which is that you manipulate the view elements by doing data operations on your viewmodel. You're creating DOM elements in your viewmodel code instead of in a binding handler.
Your addLayer should just be inserting a row into an observableArray. You should have (probably) a foreach binding for that observableArray, and within it a custom binding handler that turns each element into a map layer.

Sidebar and tabbed info windows using google maps v2

Does anyone know of an example where a Google Map is used to create a map with both a sidebar
http://econym.org.uk/gmap/example_map4c.htm
and tabbed info windows
http://econym.org.uk/gmap/example_map10a.htm?
The markers are defined and ready for sidebar
function createMarker(point,name,html) {
var marker = new GMarker(point,{icon:myIcon});
// add a line to the side_bar html
side_bar_html += '<div id="'+linkid+'"><a href="javascript:myclick(' + (gmarkers.length-1) + ')">' + name + '<\/a><br><\/div>';
return marker;
}
The sidebar gets its titles from the 'name' defined for the marker :
var marker = createMarker(point,"Point Title", 'Point Content')
map.addOverlay(marker);
Tabs are generated by passing the markers into arrays :
function createTabbedMarker(point,htmls,labels) {
var marker = new GMarker(point);
and
var marker = createTabbedMarker(point, ["Tab 1 contents", "Tab 2 contents","Tab 3 contents","Tab 4 contents"],["One","Two","Three","Four"]);
map.addOverlay(marker);
My question is how can I grab just the first part of the array [labels], in this example 'One', and have that be what the output is for the sidebar ?
The sidebar in the first example is not a feature of the Google Maps API; i's just a table cell which is updated in Javascript.
It is doable ... if you check the Google Maps documentation on Gmarker, or more specifically Gmarker.openInfoWindowTabsHtml, you will see that it takes two arguments:
An array of GInfoWindowTab's
A GInfoWindowOptions javascript object.
In the documentation for GInfoWindowOptions you will see that you can pass in the tab index via the selectedTab property. In that case, we can use the code from the sidebar example and simply update the myclick function:
function myclick(i) {
gmarkers[i].openInfoWindowHtml(htmls[i]);
}
becomes:
function myclick(i, tab_index) {
gmarkers[i].openInfoWindowHtml(htmls[i], { selectedTab : tab_index });
}
And we update the createMarker function to accept the number of tabs this marker should have:
createMarker(point,name,html,tab_count) {
// ...snip ...
var links_html_temp = "";
while (--tab_count) {
links_html_temp = '<a href="javascript:myclick(' + i + ',' + tab_count + ')">' + name + ': Tab #' + tab_count + '<\/a><br>' + links_html_temp;
}
side_bar_html += links_html_temp;
I'll leave it to your own specific implementation to pass the appropriate tab count to createMarker.

Categories