I'm trying to give each marker/shape on leaflet different information for onClick. The data I'm using is from a JSON array filled with objects.
The code I used to do this is:
var map = L.map('map').setView([43.16556, -77.61139], 13);
var OpenStreetMap_DE = L.tileLayer('http://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', {
attribution: '©>'
}).addTo(map);
//Adding a circle. (point[long,Lat], radius in meters
// Saving for later :-)
// var zip = "/javascripts/zcta5.json",
// hsa = "/javascripts/hsa.json";
var host = new Array();
var temp;
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
$.getJSON("/allHospitals",function(data,status){
var color;
var thefill;
for (var i = 0; i < data.length; i++) {
temp = data[i];
if (temp.name === "rgh") {
color = '#FF9755';
thefill = '#009666';
} else if (temp.name === "strong") {
color = '#FFE03A';
thefill = '#7C83FF';
}
host.push(L.circle(data[i].lnglat, data[i].pplNum/2, {
color: color,
fillColor: thefill,
fillOpacity: 1,
weight:3
}));
host[i].on("click", onClick);
host[i].addTo(map);
}
});
var svg = d3.select(map.getPanes().overlayPane).append("svg"),
g = svg.append("g").attr("class", "leaflet-zoom-hide");
function onOver(e){
}
function onClick (e) {
console.log(temp);
}
It returns the last entry in the json file. How can I just make this work?
function onClick (e) {
console.log(temp);
}
You want to be looking at e not temp. e is what was clicked, temp is just leftover from the loop above.
Related
I am trying to add custom html <a href="state/alaseka"><a> on each state of america as shown in map example out put would be something like this site "https://covidactnow.org/?s=1311324" and i am trying this as follow
Javascript
am4core.ready(function() {
function am4themes_myTheme(target) {
if (target instanceof am4core.ColorSet) {
target.list = [
am4core.color("#ff3b37")
];
}
}
// Themes begin
am4core.useTheme(am4themes_myTheme);
// Themes end
// Create map instance
var chart = am4core.create("usstatemap", am4maps.MapChart);
// Set map definition
chart.geodata = am4geodata_usaLow;
// Set projection
chart.projection = new am4maps.projections.AlbersUsa();
var polygonSeries = chart.series.push(new am4maps.MapPolygonSeries());
// Create map polygon series polygonSeries
//Set min/max fill color for each area
polygonSeries.heatRules.push({
property: "fill",
target: polygonSeries.mapPolygons.template,
min: chart.colors.getIndex(1).brighten(-0.3),
max: chart.colors.getIndex(1).brighten(1)
});
// Make map load polygon data (state shapes and names) from GeoJSON
polygonSeries.useGeodata = true;
stateName = {{ allStateName | safe }}
statePopulation = {{ allStatePopulation | safe }}
console.log("==========================act casess keyindicator3 =====================")
console.log(actcase)
var data = [];
var id = "";
var value = "";
var expenses = "";
for(var i = 0; i < stateName.length; i++){
year =actdate[i]
//e.,g "US-"+actdate[i]
id ="US-"+actdate[i];
url="http://127.0.0.1:8000/states/"+actdate[i]
value = actdeath[i];
console.log(url);
data.push({id:id, value:value,url:url});
}
console.log("==== state from us ap =======\t\t\t",data)
// Set heatmap values for each state
polygonSeries.data = data;
chart.events.on( "ready", updateCustomMarkers );
chart.events.on( "mappositionchanged", updateCustomMarkers );
// this function will take current images on the map and create HTML elements for them
function updateCustomMarkers( event ) {
// go through all of the images
polygonSeries.MapPolygon.each(function(image) {
// check if it has corresponding HTML element
if (!image.dummyData || !image.dummyData.externalElement) {
// create onex
image.dummyData = {
externalElement: createCustomMarker(image)
};
}
// reposition the element accoridng to coordinates
var xy = chart.geoPointToSVG( { longitude: image.longitude, latitude: image.latitude } );
image.dummyData.externalElement.style.top = xy.y + 'px';
image.dummyData.externalElement.style.left = xy.x + 'px';
});
}
// this function creates and returns a new marker element
function createCustomMarker( image ) {
var chart = image.dataItem.component.chart;
// create holder
var holder = document.createElement( 'a' );
holder.className = 'map-marker';
holder.title = image.dataItem.dataContext.title;
holder.style.position = 'absolute';
holder.href = 'www.google.com';
holder.target = '_parent';
// maybe add a link to it?
if ( undefined != image.url ) {
holder.onclick = function() {
window.location.href = image.url;
};
holder.className += 'map-clickable';
}
}//Set up heat legend
heatLegend = chart.createChild(am4maps.HeatLegend);
heatLegend.series = polygonSeries;
heatLegend.align = "right";
heatLegend.valign = "bottom";
heatLegend.width = am4core.percent(20);
heatLegend.marginRight = am4core.percent(4);
heatLegend.minValue = 0;
heatLegend.maxValue = 400000;
// Set up custom heat map legend labels using axis ranges
var minRange = heatLegend.valueAxis.axisRanges.create();
minRange.value = heatLegend.minValue;
minRange.label.text = "min";
var maxRange = heatLegend.valueAxis.axisRanges.create();
maxRange.value = heatLegend.maxValue;
maxRange.label.text = "max";// Set up custom heat map legend labels using axis ranges
// Blank out internal heat legend value axis labels
heatLegend.valueAxis.renderer.labels.template.adapter.add("text", function(labelText) {
return "";
});
// Configure series tooltip
var polygonTemplate = polygonSeries.mapPolygons.template;
polygonTemplate.tooltipText = "{name}: {value}";
polygonTemplate.nonScalingStroke = true;
polygonTemplate.strokeWidth = 0.5;
// Create hover state and set alternative fill color
var hs = polygonTemplate.states.create("hover");
hs.properties.fill = am4core.color("#3c5bdc");
});
Note:
i have used my data you can use the data from the amchart as link mentioned bellow for dummy data to be used and i am following exactly the same chart as in the link,
https://www.amcharts.com/demos/us-heat-map/
i have resolve this question by adding this simple one line in the above code
polygonTemplate.propertyFields.url = "url";
to make this work you have to add the URL for each state into the data series object
I've got real time gps positions for a few cars and I want to create a map with updating markers. My code works but it doesn't "update" the markers, instead it adds new objects with new coordinates to the leaflet map. After few minutes my map is full of markers. What I'm doing wrong? Here is my basic concept.
var intervalV = document.getElementById("intervalValue").value * 1000;
document.getElementById("setIntervalButton").onclick = startData;
function startData() {
DataInterval = window.setInterval(getNewData, intervalV);
};
function getNewData() {
$.getJSON(server, {
fun : "GetGpsData",
userId : "user",
sessionId : $("#sessionId").val()
}, fillMap);
}
function fillMap(json) {
for (var i = 0; i < json.devicesData.length; i++) {
var positions = json.devicesData[i].positions.length;
var devicepostiion;
if (json.devicesData[i].connected == false
) {
var devicepostion = L.marker([json.devicesData[i].positions[positions - 1].lat, json.devicesData[i].positions[positions - 1].lon], {
icon : offlineCarIcon
}, {
draggable : false
}).addTo(map);
} else {
devicepostion = new L.marker(, {
icon : onlineCarIcon
});
devicepostion.addTo(map).setLatLng([json.devicesData[i].positions[positions - 1].lat, json.devicesData[i].positions[positions - 1].lon]).update();
}
}
}
};
If your goal is to update markers with a new visual appearance and location if they already exist on the map...then you should be using .setIcon and .setLatLng on the existing marker instead of making a new one.
Your current code makes new markers in both cases.
Here your code updated to work as you want. As #snkashis pointed out, you do not need to create a new marker each time
var devicePosition = -1;
function fillMap(json) {
for (var i = 0; i < json.devicesData.length; i++) {
var data = json.devicesData[i];
if (data.positions) {
var index = data.positions.length - 1;
if (data.positions[index].lat && data.positions[index].lon) {
var latLng = L.latLng(parseFloat(data.positions[index].lat), parseFloat(data.positions[index].lon));
if (devicePosition === -1) {
var devicePosition = L.marker(latLng, {draggable : false})
.addTo(map);
} else {
devicePosition.setLatLng(latLng)
.update();
}
// Optional if you want to center the map on th marker
// map.panTo(latLng);
}
}
if (data.connected && devicePosition !== -1) {
devicePosition.setIcon(data.connected ? 'onlineCarIcon' : 'offlineCarIcon');
}
}
If you have multiple markers, you need to update each one accordingly to their id, I suggest to find (or add, if you create the APIs) an unique ID in json.devicesData[i].
Let's suppose the uniqueId of each marker is called, well, uniqueId, then your code can be something like this:
var devicePosition = {};
function fillMap(json) {
for (var i = 0; i < json.devicesData.length; i++) {
var data = json.devicesData[i];
var uniqueId = data.uniqueId;
if (data.positions) {
var index = data.positions.length - 1;
if (data.positions[index].lat && data.positions[index].lon) {
var latLng = L.latLng(parseFloat(data.positions[index].lat), parseFloat(data.positions[index].lon));
if (!devicePosition[uniqueId]) {
var devicePosition[uniqueId] = L.marker(latLng, {draggable : false})
.addTo(map);
} else {
devicePosition[uniqueId].setLatLng(latLng)
.update();
}
// Optional if you want to center the map on th marker
// map.panTo(latLng);
}
}
if (data.connected && devicePosition[uniqueId]) {
devicePosition[uniqueId].setIcon(data.connected ? 'onlineCarIcon' : 'offlineCarIcon');
}
}
I am trying to save on localstorage the markers that I create on click in leaflet and delete them using a button. The problem is that I don't know how to delete just one marker at time and remove them from the main layer without affecting the others.
I want to add a unique id to each marker created (that's why the "Marker #") and later on delete see if the current marker's id or location (lat,lng) match the one stored on localstorage, then delete it from the localstorage and remove it from the main layer.
Anyone could help me solve this? This is giving me headaches!
I am using this function to add them on the map and in localstorage:
initUserLayerGroup();
map.on('click', onMapClick);
var groupUser;
function initUserLayerGroup() {
if (localStorage.userMarkers !== undefined) {
var storageMarkers = [];
var markersUser = [];
storageMarkers = JSON.parse(localStorage.userMarkers);
for (var i = 0; i < storageMarkers.length; i++) {
var x = storageMarkers[i].coords.x;
var y = storageMarkers[i].coords.y;
var name = storageMarkers[i].name;
var marker = L.marker([y, x]).bindPopup(name + "<br><a href='#' class='delete'>Delete</a>");
marker.on("popupopen", onPopupOpen);
markersUser.push(marker);
}
groupUser = L.layerGroup(markersUser);
map.addLayer(groupUser);
}
}
function onMapClick(e) {
var storageMarkers = [];
var markersUser = [];
if (localStorage.userMarkers !== undefined) {
storageMarkers = JSON.parse(localStorage.userMarkers);
}
storageMarkers.push({
"coords": {
"x": e.latlng.lng,
"y": e.latlng.lat
},
"name": "Marker #"
});
var x = storageMarkers[storageMarkers.length -1].coords.x;
var y = storageMarkers[storageMarkers.length -1].coords.y;
var name = storageMarkers[storageMarkers.length -1].name;
var marker = L.marker([y, x]).bindPopup(name + "<br>X: "+ x +", Y: "+ y +"<br><a href='#' class='delete'>Delete</a>");
marker.on("popupopen", onPopupOpen);
markersUser.push(marker);
groupUser = L.layerGroup(markersUser);
map.addLayer(groupUser);
localStorage.userMarkers = JSON.stringify(storageMarkers);
}
function onPopupOpen() {
var tempMarker = this.getLatLng();
$('.delete').click(function() {
localStorage.removeItem('userMarkers');
map.removeLayer(groupUser);
});
}
You can see it working here:
http://plnkr.co/edit/vYDExBBqy9zCGBRZJ944?p=preview
One way is to iterate over the saved array of coordinates in localStorage when the marker is clicked and compare them with the coordinates of the clicked marker. Once they are the same, delete this item from localSotrage and update it.
function onPopupOpen() {
var _this = this;
var clickedMarkerCoords = this.getLatLng();
$('.delete').click(function() {
storageMarkers = JSON.parse(localStorage.userMarkers);
for(i = storageMarkers.length; i > 0; i--) {
if (typeof storageMarkers[i] != 'undefined' &&
(clickedMarkerCoords.lat == storageMarkers[i].coords.y &&
clickedMarkerCoords.lng == storageMarkers[i].coords.x)
) {
storageMarkers.splice(i, 1);
localStorage.userMarkers = JSON.stringify(storageMarkers);
}
}
map.removeLayer(_this);
});
}
Here is the plunker: http://plnkr.co/edit/1xVZjKC1184dfuOlGqVX?p=preview
I want to create a arrow in leaflet using poly lines of multipolylines whichever suits..
The arrow class should take in following param
baselatitude = base of the arrow where the arrow will be on map
baselongitude = base of the arrow where the arrow will be on map
pointlatitude = the tip of the arrow on the map
pointlongitude = the tip of the arrow on the map
apointlatitude
apointlongitude
bpointlatitude
bpointlongitude
angle = rotation degree
can anyone please provide guidance on creating the arrow using following param . It would be nice to if you can create a leaflet class extension L.arrow
did that myself for fit my requirement .. pasting in if somebody finds it useful someday
feature.geometry.coordinates[0] is the geoJson collection where all the coordinates are retrieved
L.Playback.WindArrowMarker = L.Marker.extend({
initialize: function (startLatLng, options, feature) {
this._min = 99;
this._max = 0;
this._arrowStyleOptions = [
{ color: '#ffff00' },
{ color: '#00ffff' },
{ color: '#00ff00' }];
var ArrowData = feature.geometry.coordinates[0];
var ArrowBaseLon = ArrowData[0];
var ArrowBaseLat = ArrowData[1];
var ArrowPointLat = ArrowData[2];
var ArrowPointLon = ArrowData[3];
var ArrowPointALat = ArrowData[4];
var ArrowPointALon = ArrowData[5];
var ArrowPointBLat = ArrowData[6];
var ArrowPointBLon = ArrowData[7];
var ArrowHeight = ArrowData[8];
var ArrowMagnitude = ArrowData[9];
var ArrowBearing = ArrowData[10];
if (ArrowMagnitude > this._max) this._max = ArrowMagnitude;
if (ArrowMagnitude < this._min) this._min = ArrowMagnitude;
var styleToUse=this._getArrowStyle(ArrowMagnitude);
//Create Arrow structure and assign first value from the playback data
//baseLtlg //PointLtlg
this._arrowbase = L.polyline([[ArrowBaseLat, ArrowBaseLon], [ArrowPointLat, ArrowPointLon]], styleToUse);
//PointLtlg //PointAtLtlg
this._arrowpointA = L.polyline([[ArrowPointLat, ArrowPointLon], [ArrowPointALat, ArrowPointALon]], styleToUse);
//PointLtlg //PointBLtlg
this._arrowpointB = L.polyline([[ArrowPointLat, ArrowPointLon], [ArrowPointBLat, ArrowPointBLon]], styleToUse);
//Call leaflet marker initialization to attach this as marker
L.Marker.prototype.initialize.call(this, [ArrowBaseLat, ArrowBaseLon], {});
//Calculate windspeed
var windspeed = this._calculateWindspeed(ArrowMagnitude, feature.modeldata.Adder, feature.modeldata.Multiplier)
//Attach a popup
this._arrowbase.bindPopup(this.getPopupContent(ArrowBearing, windspeed));
},
_calculateWindspeed: function (magnitude, adder, multiplier) {
return (magnitude - parseFloat(adder)) / multiplier
},
_getArrowStyle: function (magnitude) {
this._arrowMagMed = 7;
this._arrowMagHigh = 10;
if (magnitude > this._arrowMagHigh)
styleToUse = this._arrowStyleOptions[2];
else if (magnitude > this._arrowMagMed)
styleToUse = this._arrowStyleOptions[1];
else
styleToUse = this._arrowStyleOptions[0];
return styleToUse;
},
getPopupContent: function (bearing, windspeed) {
return sprintf("Wind blowing from: %s deg(from North)<br> Wind Speed(m/s): %s", bearing.toFixed(1), windspeed.toFixed(1));
},
addTo: function (map) {
this._arrowbase.addTo(map);
this._arrowpointA.addTo(map);
this._arrowpointB.addTo(map);
},
move: function (windData,transitionTime, modelData) {
var ArrowBaseLon = windData[0];
var ArrowBaseLat = windData[1];
var ArrowPointLat = windData[2];
var ArrowPointLon = windData[3];
var ArrowPointALat = windData[4];
var ArrowPointALon = windData[5];
var ArrowPointBLat = windData[6];
var ArrowPointBLon = windData[7];
var ArrowHeight = windData[8];
var ArrowMagnitude = windData[9];
var ArrowBearing = windData[10];
var styleToUse = this._getArrowStyle(ArrowMagnitude);
//Assign color based on magnitude
this._arrowbase.setStyle(styleToUse);
this._arrowpointA.setStyle(styleToUse);
this._arrowpointB.setStyle(styleToUse);
//Set Base,Apoint,Bpoint LatLongs as they are the ones changing
this._arrowbase.setLatLngs([[ArrowBaseLat, ArrowBaseLon], [ArrowPointLat, ArrowPointLon]])
this._arrowpointA.setLatLngs([[ArrowPointLat, ArrowPointLon], [ArrowPointALat, ArrowPointALon]])
this._arrowpointB.setLatLngs([[ArrowPointLat, ArrowPointLon], [ArrowPointBLat, ArrowPointBLon]])
//Calculate windspeed
var windspeed = this._calculateWindspeed(ArrowMagnitude, modelData.Adder, modelData.Multiplier)
//Check if popup is attached
if (this._arrowbase._popup) {
//Set popup content while moving
this._arrowbase._popup.setContent(this.getPopupContent(ArrowBearing, windspeed));
}
}
});
It would be nice to if you can create a leaflet class extension L.arrow
No: this is not a place where people make things for you. But we can Google things, like Leaflet arrow which leads you directly to Leaflet.PolylineDecorator.
I have a map like data in JSON
var map = {
level1 : {
x : {name:'level1 x' , },
y : {name:'level1 y'}
},
level2 : {
x : {name:'level2 x'},
y : {name:'level2 y'}
}
}
I need to traverse through this data , i am getting the traverse path as an string
"level1 x name" , "level2 y name";
How can i parse through the JSON data from that string path..??
What i tried is ,
var path = "level1 x name".split(" ");
var pointer = map; // assuming it will take reference of map and change will cause to map also
for (var i = 0, len = path.length; i < len; i++) {
if(pointer){
pointer = pointer[path[i]];
}else{
pointer = map[path[i]];
}
}
pointer = "level1 xx";
console.log(map);
But map data is not changing.. how to loop through with reference and change the value ..?
This is how you get your value:
var name = [map].concat("level1 x name".split(" ")).reduce(function(prev, curr) {
return prev[curr];
});
console.log(name);
// -> 'level1 x'
JavaScript passes arguments by value, not by reference.
For your convenience I changed your code for you to acceomplish what you asked for:
var path = "level1 x name".split(" ");
var pointer = map; // assuming it will take reference of map and change will cause to map also
for (var i = 0, len = path.length-1; i < len; i++) {
if(pointer){
pointer = pointer[path[i]];
}else{
pointer = map[path[i]];
}
}
pointer[path[path.length-1]] = "level1 xx";
console.log(map);
Try This.. Change the path variable as required. It is working fine. I just verified it in firebug.
var map = {
level1 : {
x : {name:'level1 x' , },
y : {name:'level1 y'}
},
level2 : {
x : {name:'level2 x'},
y : {name:'level2 y'}
}
};
var path = "level1 x name";
var pathInfor = path.split(' ');
var pathLength = pathInfor.length;
//alert(map[pathInfor[0]][pathInfor[1]][pathInfor[2]].name);
for(level in map)
{
if(level == pathInfor[0]){
var selLevel = map[level];
for(xy in selLevel)
{
if(xy == pathInfor[1])
{
var selVariable = map[level][xy];
for(innerVal in selVariable){
if(innerVal == pathInfor[2]){
alert(map[level][xy][innerVal]);
}
}
}
}
}
}
In this method you are not required to check with the values. If you want to print all the values form JSON, remove the condition.