I am building mapbox & deck.gl application and I want to filter some bars at runtime based on value ranges
I want to only show bars, which's aggregated value falls in some range [min,max]
So, my simplified question is
How can I get deck.gl hexagonLayer aggregated bar data after hexagons are drawn on map?
So,then I can correctly calculate upperPercentile and lowerPercentile, which are responsible for graphical filtering...
var { MapboxLayer, HexagonLayer } = deck;
//Create the Mapbox map
var map = new mapboxgl.Map({
container: document.body,
style: 'mapbox://styles/mapbox/dark-v9?optimize=true',
center: [-1.4157, 52.2324],
zoom: 6,
pitch: 40.5
});
// Get Data for visual
var DATA_URL = 'https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/3d-heatmap/heatmap-data.csv';
//Create the deck.gl hexagon layer and style for the data
var OPTIONS = ['radius', 'coverage', 'upperPercentile'];
var COLOR_RANGE = [
[1, 152, 189],
[73, 227, 206],
[216, 254, 181],
[254, 237, 177],
[254, 173, 84],
[209, 55, 78]
];
var LIGHT_SETTINGS = {
lightsPosition: [-0.144528, 49.739968, 8000, -3.807751, 54.104682, 8000],
ambientRatio: 0.4,
diffuseRatio: 0.6,
specularRatio: 0.2,
lightsStrength: [0.8, 0.0, 0.8, 0.0],
numberOfLights: 2
};
var hexagonLayer;
map.on('style.load', () => {
hexagonLayer = new MapboxLayer({
type: HexagonLayer,
id: 'heatmap',
data: d3.csv(DATA_URL),
radius: 1000,
coverage: 1,
upperPercentile: 100,
colorRange: COLOR_RANGE,
elevationRange: [0, 1000],
elevationScale: 250,
extruded: true,
getPosition: d => [Number(d.lng), Number(d.lat)],
lightSettings: LIGHT_SETTINGS,
opacity: 1
});
// Add the deck.gl hex layer below labels in the Mapbox map
map.addLayer(hexagonLayer, 'waterway-label');
// I WANT TO GET MINIMUM AND MAXIMUM VALUES FOR BARS HERE
<html>
<head>
<title>Road AccidentsIncidents</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src="https://unpkg.com/deck.gl#^6.2.0/deckgl.min.js"></script>
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v0.51.0/mapbox-gl.js"></script>
<link rel="stylesheet" type="text/css" href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.51.0/mapbox-gl.css">
<script src="https://d3js.org/d3.v5.min.js"></script>
<style type="text/css">
#map { position:absolute; top:0; bottom:0; width:100%; }
body {
font-family: Helvetica, Arial, sans-serif;
width: 100vw;
height: 100vh;
margin: 0;
padding: 0
}
#control-panel {
position: absolute;
background: #fff;
top: 0;
left: 0;
margin: 12px;
padding: 20px;
font-size: 12px;
line-height: 1.5;
z-index: 1;
}
label {
display: inline-block;
width: 140px;
}
</style>
</head>
<body>
<div id="control-panel">
<div>
<label>Radius</label>
<input id="radius" type="range" min="500" max="10000" step="500" value="1000"></input>
<span id="radius-value"></span>
</div>
<div>
<label>Coverage</label>
<input id="coverage" type="range" min="0" max="1" step="0.1" value="1"></input>
<span id="coverage-value"></span>
</div>
<div>
<label>Upper Percentile</label>
<input id="upperPercentile" type="range" min="90" max="100" step="1" value="100"></input>
<span id="upperPercentile-value"></span>
</div>
</div>
</body>
<script type="text/javascript">
mapboxgl.accessToken = 'pk.eyJ1IjoicnNiYXVtYW5uIiwiYSI6ImNqbjdsemZybzFtc3MzcnFvNXFucXQweTEifQ.2N_6Nd1rZG-I2pyA9I1xfA';
var { MapboxLayer, HexagonLayer } = deck;
//Create the Mapbox map
var map = new mapboxgl.Map({
container: document.body,
style: 'mapbox://styles/mapbox/dark-v9?optimize=true',
center: [-1.4157, 52.2324],
zoom: 6,
pitch: 40.5
});
// Get Data for visual
var DATA_URL = 'https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/3d-heatmap/heatmap-data.csv';
//Create the deck.gl hexagon layer and style for the data
var OPTIONS = ['radius', 'coverage', 'upperPercentile'];
var COLOR_RANGE = [
[1, 152, 189],
[73, 227, 206],
[216, 254, 181],
[254, 237, 177],
[254, 173, 84],
[209, 55, 78]
];
var LIGHT_SETTINGS = {
lightsPosition: [-0.144528, 49.739968, 8000, -3.807751, 54.104682, 8000],
ambientRatio: 0.4,
diffuseRatio: 0.6,
specularRatio: 0.2,
lightsStrength: [0.8, 0.0, 0.8, 0.0],
numberOfLights: 2
};
var hexagonLayer;
//Add the deck.gl Custom Layer to the map once the Mapbox map loads
map.on('style.load', () => {
hexagonLayer = new MapboxLayer({
type: HexagonLayer,
id: 'heatmap',
data: d3.csv(DATA_URL),
radius: 1000,
coverage: 1,
upperPercentile: 100,
colorRange: COLOR_RANGE,
elevationRange: [0, 1000],
elevationScale: 250,
extruded: true,
getPosition: d => [Number(d.lng), Number(d.lat)],
lightSettings: LIGHT_SETTINGS,
opacity: 1
});
// Add the deck.gl hex layer below labels in the Mapbox map
map.addLayer(hexagonLayer, 'waterway-label');
// I WANT TO GET MINIMUM AND MAXIMUM VALUES FOR BARS HERE
});
// Add sliders to change the layer's settings based on user input
OPTIONS.forEach(key => {
document.getElementById(key).onchange = (evt) => {
var value = Number(evt.target.value);
document.getElementById(key + '-value').innerHTML = value;
if (hexagonLayer) {
hexagonLayer.setProps({
[key]: value });
}
};
});
</script>
</html>
getColorValue function will be called for each cluster with points belonging to that cluster. You can modify this function like:
// other props
// will be called num_cluster times
getColorValue: (points) => {
// points that belong to a particular cluster
// do stuff with points
return points.length;
},
// other props
Finally, you can use the onSetColorDomain callback (think onClusteringComplete callback) to fill in the values into your html. Added advantage here is that this function calls the callback with [min, max], so you don't have to compute them if it's only for showing a bar.
I've altered your example to show number of clusters and min and max.
<html>
<head>
<title>Road AccidentsIncidents</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src="https://unpkg.com/deck.gl#^6.2.0/deckgl.min.js"></script>
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v0.51.0/mapbox-gl.js"></script>
<link rel="stylesheet" type="text/css" href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.51.0/mapbox-gl.css">
<script src="https://d3js.org/d3.v5.min.js"></script>
<style type="text/css">
#map { position:absolute; top:0; bottom:0; width:100%; }
body {
font-family: Helvetica, Arial, sans-serif;
width: 100vw;
height: 100vh;
margin: 0;
padding: 0
}
#control-panel {
position: absolute;
background: #fff;
top: 0;
left: 0;
margin: 12px;
padding: 20px;
font-size: 12px;
line-height: 1.5;
z-index: 1;
}
label {
display: inline-block;
width: 140px;
}
</style>
</head>
<body>
<div id="control-panel">
<div>
<label>Radius</label>
<input id="radius" type="range" min="500" max="10000" step="500" value="1000"></input>
<span id="radius-value"></span>
</div>
<div>
<label>Coverage</label>
<input id="coverage" type="range" min="0" max="1" step="0.1" value="1"></input>
<span id="coverage-value"></span>
</div>
<div>
<label>Upper Percentile</label>
<input id="upperPercentile" type="range" min="90" max="100" step="1" value="100"></input>
<span id="upperPercentile-value"></span>
</div>
<div>
<div style="padding: 7px 0">
<span>Total Clusters: </span>
<span id="total-clusters-value">Loading</span>
</div>
<div>
<span>[Min, Max]: </span>
<span id="min-max-value">Loading</span>
</div>
</div>
</div>
</body>
<script type="text/javascript">
mapboxgl.accessToken = 'pk.eyJ1IjoicnNiYXVtYW5uIiwiYSI6ImNqbjdsemZybzFtc3MzcnFvNXFucXQweTEifQ.2N_6Nd1rZG-I2pyA9I1xfA';
var { MapboxLayer, HexagonLayer } = deck;
//Create the Mapbox map
var map = new mapboxgl.Map({
container: document.body,
style: 'mapbox://styles/mapbox/dark-v9?optimize=true',
center: [-1.4157, 52.2324],
zoom: 6,
pitch: 40.5
});
// Get Data for visual
var DATA_URL = 'https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/3d-heatmap/heatmap-data.csv';
//Create the deck.gl hexagon layer and style for the data
var OPTIONS = ['radius', 'coverage', 'upperPercentile'];
var COLOR_RANGE = [
[1, 152, 189],
[73, 227, 206],
[216, 254, 181],
[254, 237, 177],
[254, 173, 84],
[209, 55, 78]
];
var LIGHT_SETTINGS = {
lightsPosition: [-0.144528, 49.739968, 8000, -3.807751, 54.104682, 8000],
ambientRatio: 0.4,
diffuseRatio: 0.6,
specularRatio: 0.2,
lightsStrength: [0.8, 0.0, 0.8, 0.0],
numberOfLights: 2
};
var hexagonLayer;
let clusters = [];
const minMax = document.getElementById('min-max' + '-value');
const totalClusters = document.getElementById('total-clusters' + '-value');
//Add the deck.gl Custom Layer to the map once the Mapbox map loads
map.on('style.load', () => {
hexagonLayer = new MapboxLayer({
type: HexagonLayer,
id: 'heatmap',
data: d3.csv(DATA_URL),
radius: 1000,
coverage: 1,
upperPercentile: 100,
colorRange: COLOR_RANGE,
elevationRange: [0, 1000],
elevationScale: 250,
extruded: true,
getPosition: d => [Number(d.lng), Number(d.lat)],
getColorValue: points => { clusters.push(points.length); return points.length; },
onSetColorDomain: ([min, max]) => { minMax.innerHTML = `[${min}, ${max}]`; totalClusters.innerHTML = clusters.length; },
lightSettings: LIGHT_SETTINGS,
opacity: 1
});
// Add the deck.gl hex layer below labels in the Mapbox map
map.addLayer(hexagonLayer, 'waterway-label');
// I WANT TO GET MINIMUM AND MAXIMUM VALUES FOR BARS HERE
});
// Add sliders to change the layer's settings based on user input
OPTIONS.forEach(key => {
document.getElementById(key).onchange = (evt) => {
clusters = [];
var value = Number(evt.target.value);
document.getElementById(key + '-value').innerHTML = value;
if (hexagonLayer) {
hexagonLayer.setProps({
[key]: value });
}
};
});
</script>
</html>
Related
I have a codepen at https://codepen.io/ericg_off/pen/RwMLEmX which demonstrates the issue.
I am trying to use FontAwesome icons with leaflet, but there appears to be nuances to how the fa css is defined that does not play well with leaflet.
For example, the SVG will not be sized or constrained by the html element that contains it.
What needs to be changed so the icon can be sized and constrained by the L.divIcon that contains it?
HTML
<div id="map"></div>
CSS
#map {
height: 100vh;
}
.my-icons {
background-color: rgba(0, 255, 0, 1.0);
}
JS
var map = L.map("map", {
center: [38, -77],
zoom: 5
});
// Create a Tile Layer and add it to the map
var tiles = new L.tileLayer(
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
{
attribution:
'© OpenStreetMap contributors',
minZoom: 3,
maxZoom: 9
}
).addTo(map);
divIcon = L.divIcon({
html: '<i class="fab fa-google"></i>',
className: "my-icons",
iconSize: [20, 20]
});
const markerLayer = L.layerGroup().addTo(map);
const lineLayer = L.layerGroup().addTo(map);
const from = [38, -77];
const to = [38, -100];
const fromMarker = L.marker(from, {
icon: divIcon
}).addTo(lineLayer);
const line = L.polyline([from, to], { color: "green", weight: 1 }).addTo(
markerLayer
);
If you need your FontAwesome icon to grow/shrink according to its parent container, you can use height:100% and a max-with:100% instead of em (font-size related):
Overriding css
/* center align svg elements */
.leaflet-marker-icon {
text-align: center;
}
/* scale icon to parent height - set a max-width to preventoverflows */
.svg-inline--fa {
display: inline-block;
font-size: inherit;
width: auto!important;
height: 100%!important;
overflow: visible;
max-width: 100%;
}
Example
var map = L.map("map", {
center: [38, -77],
zoom: 5
});
// Create a Tile Layer and add it to the map
var tiles = new L.tileLayer(
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
{
attribution:
'© OpenStreetMap contributors',
minZoom: 3,
maxZoom: 9
}
).addTo(map);
divIcon = L.divIcon({
html: '<i class="fab fa-google"></i>',
className: "my-icons",
iconSize: [20, 32]
});
const markerLayer = L.layerGroup().addTo(map);
const lineLayer = L.layerGroup().addTo(map);
const from = [38, -77];
const to = [38, -100];
const fromMarker = L.marker(from, {
icon: divIcon
}).addTo(lineLayer);
const line = L.polyline([from, to], { color: "green", weight: 1 }).addTo(
markerLayer
);
#map {
height: 100vh;
}
.my-icons {
background-color: rgba(0, 255, 0, 1);
}
/* center align svg elements */
.leaflet-marker-icon {
text-align: center;
}
/* scale icon to parent height - set a max-width to avoid overflows */
.svg-inline--fa {
display: inline-block;
font-size: inherit;
width: auto!important;
height: 100%!important;
overflow: visible;
max-width: 100%;
}
<link href="https://unpkg.com/leaflet#1.8.0/dist/leaflet.css" rel="stylesheet"/>
<script src="https://pro.fontawesome.com/releases/v5.0.6/js/all.js"></script>
<script src="https://unpkg.com/leaflet#1.8.0/dist/leaflet.js"></script>
<div id="map"></div>
I need to know (clicking with the mouse) the coordinate under the polyline.
The polyline cannot be hidden (NO mymap.removeLayer(LayA / B)), the polyline must remain filled (if necessary, may temporarily hide its popup).
Thanks to someone who can help me.
Here an example to work on:
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>
</head>
<body style="margin:0; border: 0; padding:0; content: 0;">
<div id="mapid" style="width: 100%; height: 666px;"></div>
<script>
"use strict";
var mymap = L.map('mapid', { zoomControl:false, doubleClickZoom:false, minZoom: 2, maxZoom: 18, keyboard: false}).setView([43, 11], 7);
var LayMap = L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {zIndex:1, minZoom: 2, maxZoom: 18, zoom: 8, doubleClickZoom: false, id: 'mapbox/streets-v11', tileSize: 512, zoomOffset: -1, accessToken: '...'}).addTo(mymap);
mymap.createPane('PanA').style.zIndex = 501;
var LayA = new L.layerGroup();
var Poly1 = L.polygon([[43,11],[43.5,11],[43.5,11.5]], {pane: 'PanA' , weight: 9, color: 'Indigo', opacity: 1, fill: true, fillOpacity: 0.1, dashArray: '2,5'}).bindPopup('HI from Poly1');
LayA.addLayer(Poly1);
var Poly2 = L.polygon([[44,11],[44.5,11],[44.5,11.5]], {pane: 'PanA' , weight: 9, color: 'Red', opacity: 1, fill: true, fillOpacity: 0.1, dashArray: '2,5'}).bindPopup('HI from Poly1');
LayA.addLayer(Poly2);
mymap.addLayer(LayA);
mymap.on('click', function(e) {
console.log(e.latlng);
});
</script>
</body>
</html>
I have created a simple leaflet web app that allows for the user to search for the countries that they have traveled.
The user can use a search box or click on the layer on the map. either action will highlight the country green and load the name and flag in an adjacent table.
This works fine. However, problems arise should the user decide to remove a country visited (for example they made a mistake when selecting)
I have included the ability to delete the table items by user click and enabled a function on double click of the layer itself to reset the colour.
What I need is for these two actions to relate to one another. so if the user removes the flag, the related country is reset and vis versa.
I think I need some sort of listener on the click remove or highlight function or perhaps defining the symbology based on the user-generated table of countries visited. Any suggestions?
<!DOCTYPE html>
<html>
{% load static %}
{% load leaflet_tags %}
<head>
{% leaflet_js %}
{% leaflet_css %}
<script type="text/javascript" src="{% static 'dist/leaflet.ajax.js' %}"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<title>hello world</title>
<link rel="stylesheet" href="{% static 'leaflet-groupedlayercontrol/leaflet.groupedlayercontrol.min.css' %}" />
<link rel="stylesheet" href="https://labs.easyblog.it/maps/leaflet-search/src/leaflet-search.css" />
<link rel="stylesheet" href="https://labs.easyblog.it/maps/leaflet-search/examples/style.css" />
<style type="text/css">
#findbox {
background: #eee;
border-radius: 0.125em;
border: 2px solid #1978cf;
box-shadow: 0 0 8px #999;
margin-bottom: 10px;
padding: 2px 0;
width: 600px;
height: 26px;
}
.search-tooltip {
width: 200px;
}
.leaflet-control-search .search-cancel {
position: static;
float: left;
margin-left: -22px;
}
#map {
width: 50%;
height: 650px;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<p style="text-align: center; font-size: 24px; color: #175b81; font-weight: bold;"></p>
<h3>My World Map</h3>
<div id="findbox"></div>
<div id="map" style="height: 680px; width: 48%; display: ;"></div>
<div class="sidebar" style="display: right;">
<p style="text-align: centre; font-size: 24px; color: #175b81; font-weight: bold;">My Flags:</p>
<table style="width: 90%;">
<tr>
<td id="name" hidden></td>
<td id="code" hidden></td>
</tr>
<ul id="Countries_Visted"></ul>
</table>
</div>
<script>
var img1 = "<img src=";
var im2 = ">";
var quotes = "'";
var flagimage_pt1 = "https://www.countryflags.io/";
var flagimage_pt2 = "/flat/64.png";
// creating mapbox basemap
var mapboxAccessToken =
"pk.eyJ1IjoiY2hyaXNyeWFuLXRlY2giLCJhIjoiY2thY2c3bDZyMDZsNDJ4cHJlZmhwZmFjaCJ9.3GuHRvRz-8fxi4r103z05w";
var mapbox = L.map("map").setView([46.0, 8.0], 2.2);
mapbox.doubleClickZoom.disable();
L.tileLayer(
"https://api.mapbox.com/styles/v1/chrisryan-tech/ckaxvc0bt10041iqfz5fb7dgj/tiles/256/{z}/{x}/{y}#2x?access_token=" +
mapboxAccessToken,
{
tileSize: 512,
zoomOffset: -1,
attribution:
'© Mapbox © OpenStreetMap',
}
).addTo(mapbox);
//loading data with style, click function and listener
var data_layer = new L.GeoJSON.AJAX("{% url 'borders_data' %}", {
style: countriesStyle,
onEachFeature: countriesOnEachFeature,
});
//listener - adding to map on load
data_layer.on("data:loaded", function (e) {
layer.addTo(mapbox);
});
function countriesStyle(feature) {
return {
fillColor: "grey",
weight: 2,
opacity: 0.2,
color: "grey",
dashArray: 3,
fillOpacity: 0.2,
};
}
function countriesOnEachFeature(feature, layer) {
layer.on({
click: function (e) {
var layer = e.target;
layer.setStyle({
weight: 1,
color: "#fff",
dashArray: "",
fillOpacity: 0.9,
fillColor: "green",
});
if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
layer.bringToFront();
}
},
});
layer.on({
click: load_name_flag,
});
layer.on({
dblclick: clear,
});
}
///// clearing styling
var layer = data_layer;
function clear(e) {
layer.resetStyle(e.target);
}
///// adding to clicked countries to countries visted list
function load_name_flag(e) {
var field1 = document.getElementById("name");
field1.innerHTML = e.target.feature.properties.name;
var field2 = document.getElementById("code");
field2.innerHTML = e.target.feature.properties.iso2;
var selected_name_search = field1.innerHTML;
var selected_flag_search = img1 + quotes + flagimage_pt1 + field2.innerHTML + flagimage_pt2 + quotes + im2;
var selected_features_combine = selected_name_search + selected_flag_search;
$("#Countries_Visted").append("<li>" + selected_features_combine + "</li>").disabled = true;
}
</script>
<!- search box functionality - searches attribute data -->
<!- contained within Geojson from loaded event listener -->
<script src="https://unpkg.com/leaflet#1.3.0/dist/leaflet.js"></script>
<script src="https://labs.easyblog.it/maps/leaflet-search/src/leaflet-search.js"></script>
<script>
//pointing search function to map layer
var searchControl = new L.Control.Search({
container: "findbox",
layer: data_layer,
initial: false,
collapsed: false,
propertyName: "name",
marker: false,
});
// search box finds layer and adds country name and flag, changes layer symbol to green
searchControl.on("search:locationfound", function (e) {
var field1 = document.getElementById("name");
field1.innerHTML = e.layer.feature.properties.name;
var field2 = document.getElementById("code");
field2.innerHTML = e.layer.feature.properties.iso2;
var selected_name_search = field1.innerHTML;
var selected_flag_search = img1 + quotes + flagimage_pt1 + field2.innerHTML + flagimage_pt2 + quotes + im2;
var selected_features_combine = selected_name_search + selected_flag_search;
// styles for selected country
e.layer.setStyle({ fillColor: "green", color: "black", fillOpacity: 0.8 });
/// adding name and flag to countriesvisted list from searchbox select
$("#Countries_Visted").append("<li>" + selected_features_combine + "</li>").disabled = true;
});
mapbox.addControl(searchControl); //inizialize search control
// function to remove added layers
Countries_Visted.onclick = function remove(e) {
var li = e.target;
var layer = data_layer;
var listItems = document.querySelectorAll("li");
var ul = document.getElementById("ul");
li.parentNode.removeChild(li);
layer.resetStyle(e.target);
};
</script>
</body>
</html>
I would like to trigger an extra event when clicking on a marker. Now, it opens a popup, but instead I would like to show the information in an extra info layer. I have managed to show the layer (var info), but I don't know how to change the information with a click on the marker.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Schönberg Topography</title>
<link rel="stylesheet" href="../lib/mapbox.css" />
<script src="../lib/mapbox.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../dist/MarkerCluster.css" />
<link rel="stylesheet" href="../dist/MarkerCluster.Default.css" />
<script src="../dist/leaflet.markercluster-src.js"></script>
<script charset="UTF-8" src="topography.js"></script>
<style>
body {
padding: 0;
margin: 0;
}
html,
body,
#map {
height: 100%;
}
.info {
padding: 6px 8px;
font: 14px/16px Arial, Helvetica, sans-serif;
background: white;
background: rgba(255, 255, 255, 0.8);
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
border-radius: 5px;
}
.info h4 {
margin: 0 0 5px;
color: #777;
}
</style>
<style type="text/css">
a:link {
text-decoration: none;
}
</style>
</head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<body>
<div id="map"></div>
<script type="text/javascript">
var cloudmadeUrl = 'http://otile1.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png',
cloudmadeAttribution = 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 Mapbox, Points © 2012 LINZ',
cloudmade = new L.TileLayer(cloudmadeUrl, {
maxZoom: 17,
attribution: cloudmadeAttribution
}),
latlng = new L.LatLng(48.86, 2.34);
var map = new L.Map('map', {
center: latlng,
zoom: 12,
maxBounds: [
[49, 2.7],
[48.7, 2, 45]
],
layers: [cloudmade]
});
var markers = new L.MarkerClusterGroup();
for (var i = 0; i < addressPoints.length; i++) {
var a = addressPoints[i];
var title = a[2];
var name = a[3]
var colormarker = a[4]
var typemarker = a[5]
var marker = L.marker(new L.LatLng(a[0], a[1]), {
icon: L.mapbox.marker.icon({
'marker-symbol': typemarker,
'marker-color': colormarker
}),
title: name
});
var info = L.control();
info.onAdd = function() {
this._div = L.DomUtil.create('div', 'info'); // 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
info.update = function() {
this._div.innerHTML = title;
};
marker.bindPopup(title);
markers.addLayer(marker);
}
map.addLayer(markers);
info.addTo(map);
</script>
</body>
</html>
You would need to modify your update function to take a parameter to begin here.You also only need to be creating this info control once, not each time inside the loop..because you only need one open at a time, right?
info.update = function(content) {
this._div.innerHTML = content;
};
Don't forget to update your onAdd with regards to removing the update.
info.onAdd = function() {
this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
return this._div;
};
Then, inside the callback for a click event on a marker, you would call info.update("My new content").
I am trying to load a GeoJSON file for an interactive map of West Virginia Counties but I am getting an error saying Uncaught ReferenceError: wvData is not defined on line 140. Can someone help me in figuring out how to resolve this? I am attaching my full code.
<html>
<head>
<title>Leaflet Interactive GeoJSON</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
<style>
#map {
width: 100%;
height: 100%;
}
.info {
padding: 6px 8px;
font: 14px/16px Arial, Helvetica, sans-serif;
background: white;
background: rgba(255,255,255,0.8);
box-shadow: 0 0 15px rgba(0,0,0,0.2);
border-radius: 5px;
}
.info h4 {
margin: 0 0 5px;
color: #777;
}
.legend {
text-align: left;
line-height: 18px;
color: #555;
}
.legend i {
width: 18px;
height: 18px;
float: left;
margin-right: 8px;
opacity: 0.7;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
<script type="text/javascript" src="CountySelection.js"></script>
<script type="text/javascript">
var map = L.map('map').setView([37.8, -96], 4);
L.tileLayer('https://{s}.tiles.mapbox.com/v3/{id}/{z}/{x}/{y}.png', {
maxZoom: 16,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
id: 'examples.map-20v6611k'
}).addTo(map);
// control that shows state info on hover
var info = L.control();
info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info');
this.update();
return this._div;
};
info.update = function (props) {
this._div.innerHTML = '<h4>US Population Density</h4>' + (props ?
'<b>' + props.NAME + '</b><br />' + props.POP2010 + ' people / mi<sup>2</sup>'
: 'Hover over a state');
};
info.addTo(map);
// get color depending on population density value
function getColor(d) {
return d > 1000 ? '#800026' :
d > 500 ? '#BD0026' :
d > 200 ? '#E31A1C' :
d > 100 ? '#FC4E2A' :
d > 50 ? '#FD8D3C' :
d > 20 ? '#FEB24C' :
d > 10 ? '#FED976' :
'#FFEDA0';
}
function style(feature) {
return {
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7,
fillColor: getColor(feature.properties.POP2010)
};
}
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 5,
color: '#666',
dashArray: '',
fillOpacity: 0.7
});
if (!L.Browser.ie && !L.Browser.opera) {
layer.bringToFront();
}
info.update(layer.feature.properties);
}
var geojson;
function resetHighlight(e) {
geojson.resetStyle(e.target);
info.update();
}
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
}
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
click: zoomToFeature
});
} <!-- ADDED: Line 140 in the source code -->
geojson = L.geoJson(wvData, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);
map.attributionControl.addAttribution('Population data © US Census Bureau');
var legend = L.control({position: 'bottomright'});
legend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'info legend'),
grades = [0, 10, 20, 50, 100, 200, 500, 1000],
labels = [],
from, to;
for (var i = 0; i < grades.length; i++) {
from = grades[i];
to = grades[i + 1];
labels.push(
'<i style="background:' + getColor(from + 1) + '"></i> ' +
from + (to ? '–' + to : '+'));
}
div.innerHTML = labels.join('<br>');
return div;
};
legend.addTo(map);
</script>
</body>
</html>
In the line
geojson = L.geoJson(wvData, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);
you haven't yet defined wvData anywhere, and looks like you haven't loaded your geojson file yet either. If you're data is defined in a separate geojson file, you'll need to load it via an ajax request, or checkout the leaflet-omnivore plugin.
Lyzi Diamond published some blog posts about loading geojson with leaflet. It helped me a lot: http://lyzidiamond.com/posts/external-geojson-and-leaflet-the-other-way/