how to highlight a chosen line on a leaflet map? - javascript

I want to draw a map with few routes drawn on it.
I want to have a dropbox with numbers 1,..,n
when an item in the dropbox is chosen, the corresponding route is highlighted on the map.
I have started using "leaflet".
how do I highlight a line? I have used "weight" but it's more a border to a line. I would like to see the line is getting bolder.
here is my code:
document.onload = loadMap();
function loadMap() {
var map = L.map('map').setView([37.8, -96], 4);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: 'Map data © OpenStreetMap contributors,CC-BY-SA, Imagery © Mapbox',
maxZoom: 18,
id: 'mapbox.streets',
accessToken: 'pk.eyJ1IjoiZW======V6ZTdlb2V5cyJ9.3HqHQ4BMRvSPaYe8ToA7YQ'
}).addTo(map);
var marker = L.marker([51.5, -0.09]).addTo(map);
var myLines = [{
"type": "LineString",
"properties": {
"id": "1"
}
"coordinates": [
[-100, 40],
[-105, 45],
[-110, 55]
]
}, {
"type": "LineString",
"properties": {
"id": "2"
}
"coordinates": [
[-105, 40],
[-110, 45],
[-115, 55]
]
}];
var myLayer = L.geoJson().addTo(map);
myLayer.addData(myLines);
geojson = L.geoJson(myLines, {
onEachFeature: onEachFeature
}).addTo(map);
}
function highlightFeature(e) {
var layer = e.target;
layer
layer.setStyle({
weight: 25,
color: '#ff3300',
dashArray: '',
fillOpacity: 0.7
});
if (!L.Browser.ie && !L.Browser.opera) {
layer.bringToFront();
}
}
function resetHighlight(e) {
geojson.resetStyle(e.target);
layer.setStyle({
weight: 5,
color: '#0000ff',
dashArray: '',
fillOpacity: 0.7
});
}
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
// click: zoomToFeature
});
}
$('select[name="dropdown"]').change(function() {
var item = $(this).val();
alert("call the do something function on option " + item);
//how to make the chosen line highlighted ??
});

weight property is not changing line border, it changes stroke width in pixels. You get border effect because you are adding lines twice. Here:
myLayer.addData(myLines);
And here:
geojson = L.geoJson(myLines, {
onEachFeature: onEachFeature
}).addTo(map);
When a polyline is hovered, top layer's style is changed, but because you are adding polylines twice, there still remains a polyline from the lower layer. As it is described here, default stroke opacity is 0.5 (setting fillOpacity is redundant for the polyline by the way, for changing stroke-opacity opacity property is used). Polyline from the top layer becomes semi-transparent, and that makes the illusion of the border effect.
So, you can just remove this line myLayer.addData(myLines); and get the expected result.
I've made a fiddle, where your example is corrected.

Related

Make data layer disappear and different one appear on click in Leaflet

I'm mapping COVID vaccinations per state and per county in the MXN. I have state data as well as county data displaying properly.
I'm trying to make it so that when I click on a state it zooms in to the selected state, turns off the state data layer and turns on the county data layer. So basically it goes from showing state data to county data.
How do I do this? Would I need to add something to the zoomTofeature function?
var map = L.map("map", {
center: [24.0376106, -102.9590598],
zoom: 4.5,
});
// add basemap
var Stamen_TonerLite = L.tileLayer(
"https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
{
attribution:
'© OpenStreetMap'
maxZoom: 18,
minZoom: 3,
}
).addTo(map);
//zoom to a state, turn off state data, turn on county data
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
}
//zoom to county
function zoomToFeature1(e) {
map.fitBounds(e.target.getBounds());
}
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 4,
opacity: 1,
color: "#dbff4d",
});
layer.bringToFront();
}
function highlightFeature1(e) {
var layer = e.target;
layer.setStyle({
weight: 4,
opacity: 1,
color: "#dbff4d",
});
layer.bringToFront();
}
//reset the hightlighted states on mouseout
function resetHighlight(e) {
geojsonStates.resetStyle(e.target);
}
//reset the hightlighted counties on mouseout
function resetHighlight1(e) {
geojsonCounties.resetStyle(e.target);
}
//add these events to the layer object
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
click: zoomToFeature,
mouseout: resetHighlight,
});
}
//add these events to the layer object
function onEachFeature1(feature, layer) {
layer.on({
mouseover: highlightFeature1,
click: zoomToFeature1,
mouseout: resetHighlight1,
});
}
function getColor(d) {
return d > 70
? "#2c7bb6"
: d >= 60
? "#abd9e9"
: d >= 50
? "#fdae61"
: d < 50
? "#d7191c"
: "#5f5f5f";
}
function getColor1(d) {
return d >= 75
? "#1a9641"
: d >= 50
? "#a6d96a"
: d >= 25
? "#fdae61"
: d > 0
? "#d7191c"
: "#5f5f5f";
}
function states(feature) {
return {
weight: 3,
opacity: 1,
color: "whitesmoke",
fillOpacity: 0.8,
fillColor: getColor(feature.properties.vaxData_states_Series_Complete),
};
}
function counties(feature) {
return {
weight: 0.5,
opacity: 0.5,
color: "whitesmoke",
fillOpacity: 0.75,
fillColor: getColor1(feature.properties.vaxData_Series_Complete),
};
}
// add state borders
var geojsonStates = L.geoJson.ajax("data/us_states.geojson", {
style: states,
onEachFeature: onEachFeature,
});
geojsonStates.addTo(map);
//add county geojson
var geojsonCounties = L.geoJson.ajax("data/counties.geojson", {
style: counties,
onEachFeature: onEachFeature1,
});
geojsonCounties.addTo(map);
I hope you can help me and I have had this issue for more than a week and I don't know what the problem could be.

Here maps javascript transparent object with higher zIndex hides other objects underneath it

I am using Here maps for javascript v3.1.24.0.
My use case is to have a wide transparent polyline over another thin visible polyline so that I can make it easier for users to perform events like hover and tap.
However the transparent polyline with higher zIndex completely hides the polyline underneath it.
Is there a solution or a workaround for this?
const path = [
{ lat: 51, lng: 10 },
{ lat: 51, lng: 20 }
];
const path2 = [
{ lat: 50, lng: 15 },
{ lat: 53, lng: 18 }
];
const linestring = new window.H.geo.LineString();
path.forEach(function (point) {
linestring.pushPoint(point);
});
const linestring2 = new window.H.geo.LineString();
path2.forEach(function (point) {
linestring2.pushPoint(point);
});
const redPolyline = new window.H.map.Polyline(linestring2, {
style: { strokeColor: "red", lineWidth: 5 },
zIndex: 0
});
const transparentPolyline = new window.H.map.Polyline(linestring, {
style: { strokeColor: "rgba(255, 255, 255, 0.1)", lineWidth: 10 },
zIndex: 1
});
JS Fiddle link: https://jsfiddle.net/sharmakushagra/nabsxez9/19/

Mapbox - How to check if linestring is in view

Situation:
I use Mapbox to create a map with three markers + a linestring connecting them. Following this exmaple I created a button that zooms the camera to the bounds of the linestring.
This works as intended.
Whenever the function is called (on click and on first map-load), the camera zooms to the linestring bounds correctly.
Problem/Goal:
I would like to only display the button whenever:
the user has changed position of the campera, after linestring was brought into view
the user has changed the zoom, after linestring was brought into view
This can be simply done by adding / removing a .is-visible class.
However I somehow cant figure out how to listen to these two possible user interactions after linestring was brought into view.
I've tried some approaches that seemed overly complex and did not work. I have the feeling that the answer is quite simple, only I'm not seeing it.
Any help appreciated!
Code:
<script src='https://unpkg.com/mapbox#1.0.0-beta9/dist/mapbox-sdk.min.js'></script>
<script src='https://api.mapbox.com/mapbox-gl-js/v1.2.0/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v1.2.0/mapbox-gl.css' rel='stylesheet' />
<div id='map' class="traveljournal__map"></div>
<div class='traveljournal__map-actions'>
<div id='zoomto' class="traveljournal__map-action traveljournal__map-action--zoomto"></div>
</div>
<script>
mapboxgl.accessToken = 'TOKENHERE';
let client = new MapboxClient(mapboxgl.accessToken);
// DEFINE MAP
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/nilsdannemann/cjz2kdev503jo1dnsr23qoca8',
center: [174.724779, -41.288030], // Coordinates of newest Moment
zoom: 9
});
// DEFINE MOMENTS
var moments = [{
id: "1",
properties: {
title: "moment title",
content: "moment content",
mood: "happy",
date: "01. Aug 2019",
weather: "sunny",
iconSize: [60, 60],
location: [174.800314, -41.317955],
},
camera: {
center: [174.800314, -41.317955],
zoom: 13,
bearing: 20, // Add 20 for every location
pitch: 40
}
}, {
id: "2",
properties: {
title: "moment title",
content: "moment content",
mood: "happy",
date: "01. Aug 2019",
weather: "sunny",
iconSize: [60, 60],
location: [174.773008, -41.282235],
},
camera: {
center: [174.773008, -41.282235],
zoom: 13,
bearing: 40, // Add 20 for every location
pitch: 40
}
}, {
id: "3",
properties: {
title: "moment title",
content: "moment content",
mood: "happy",
date: "01. Aug 2019",
weather: "sunny",
iconSize: [60, 60],
location: [174.724779, -41.288030],
},
camera: {
center: [174.724779, -41.288030],
zoom: 13,
bearing: 60, // Add 20 for every location
pitch: 40
}
}];
// ADD MARKERS
moments.forEach(function(marker, index) {
// Create a DOM element for Marker
var el = document.createElement('div');
el.className = 'traveljournal__map-marker';
el.style.width = marker.properties.iconSize[0] + 'px';
el.style.height = marker.properties.iconSize[1] + 'px';
el.addEventListener('click', function() {
//Move Campera to Marker
map.flyTo(moments[index].camera);
});
// Add Marker to Map
new mapboxgl.Marker(el)
.setLngLat(marker.properties.location)
.addTo(map);
});
// ADD LINE BETWEEN MARKERS
var linestring = [];
moments.forEach(function(item) {
linestring.push(item.properties.location);
});
// ADD ZOOM TO LINESTRING FUNCTION
function zoomToLineString() {
var bounds = linestring.reduce(function(bounds, coord) {
return bounds.extend(coord);
}, new mapboxgl.LngLatBounds(linestring[0], linestring[0]));
map.fitBounds(bounds, {
padding: {top: 30, right: 0, bottom: 75, left: 0},
bearing: 0,
pitch: 0
});
};
// ADD ZOOM TO LINESTRING BUTTON EVENT
document.getElementById('zoomto').addEventListener('click', function() {
zoomToLineString();
});
// LOAD MAP
map.on('load', function() {
// ADD LINE TO MAP
map.addLayer({
"id": "route",
"type": "line",
"source": {
"type": "geojson",
"data": {
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": linestring
}
}
},
"layout": {
"line-join": "round",
"line-cap": "round"
},
"paint": {
"line-color": "#2BABEE",
"line-width": 2
}
});
// ZOOM TO LINESTRING ON MAP LOAD
zoomToLineString();
});
</script>
You can listen to the zoomend and moveend events to perform your bounds check, and update classes as required. You can use queryRenderedFeatures to see if the line is (partially) somewhere in the viewport.
function checkLine() {
if (map.queryRenderedFeatures({layers: 'route'}).length) {
// route is within view, do what you want
}
}
map.on('zoomend', checkLine);
map.on('moveend', checkLine);

Leaflet rendering one polygon in a list of polygons

I have a leaflet map with django. I'm passing geojson from a database. For some reason, I'm not getting any errors, but it's only rendering one polygon instead of around 3,000. Everything else seems to be working correctly.
It's technically not a multipolygon since there aren't shapes inside this shape but a bunch of shapes rendered in the same place.
function initmap(){
var map = new L.map('map',{
center: [1.0,1.0],
layers: [osmLayer,markers,parcelLayer],
minZoom: 1,
zoom: 3 }
).setView([lat,long],13 );
}
var osmLayer = new L.tileLayer( 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap',
subdomains: ['a','b','c']
});
var markers = new L.FeatureGroup();
var parcelFeature = ['{"geometry": {"type": "Polygon", "coordinates": [[[a,b],[c,d],[e,f],[g,h]]]}, "type": "Feature"}',
'{"geometry": {"type": "Polygon", "coordinates": [[[i,j],[k,l],[m,n],[o,p]]], "type": "Feature"}'];
parcelFeature = JSON.parse(parcelFeature[0]);
var parcelLayer = L.geoJson([parcelFeature],{
style : {
"color": "#000000",
"weight": 3,
"opacity": 10.65
}
});
parcelLayer.on("loaded", function(e) {map.fitBounds(e.target.getBounds());} );
//marker icon
var ceIcon = L.icon({
iconUrl: "/static/maps/leaflet/images/somepng.png",
iconSize: [45,45],
iconAnchor: [0, 0],
popupAnchor: [-3, -76]
});
//add markers
marker = new L.marker([lat,long], {icon:ceIcon});
markers.addLayer(marker);
marker = new L.marker([lat,long], {icon:ceIcon});
markers.addLayer(marker);
marker = new L.marker([lat,long], {icon:ceIcon});
markers.addLayer(marker);
marker = new L.marker([lat,long], {icon:ceIcon});
markers.addLayer(marker);
initmap();
What I did was pass this through django as a json and then splitting in javascript each json item and adding it to a new list.
var parcelFeature = [];
var parcel_json = {{ parcel_json|safe }};
for(i = 0; i < parcel_json.length; i++){
var pjson = parcel_json[i];
pjson = JSON.parse(pjson);
parcelFeature.push(pjson);
}
After this I used the default L.geoJson layer and it rendered correctly. Not sure the issue.
var parcelLayer = L.geoJson(parcelFeature,
{ style :{
"color": "#000000",
"weight": 1,
"opacity": 100},
"fillColor":"#FFFFFF",
onEachFeature: function(feature, layer) {
// does this feature have a property named popupContent?
if (feature.properties && feature.properties.popupContent) {
layer.bindPopup(feature.properties.popupContent);
console.dir(feature.properties.popupContent);
} }
});

why doesn't resetStyle of leaflet work for me?

I want to draw a map with few routes drawn on it.
I want to have a dropbox with numbers 1,..,n
when an item in the dropbox is chosen, the corresponding route is highlighted on the map.
I have started using "leaflet".
why doesn't my resetStyle() return the lines to their original style?
here is my code:
document.onload = loadMap();
function loadMap() {
var map = L.map('map').setView([37.8, -96], 4);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: 'Map data © OpenStreetMap contributors,CC-BY-SA, Imagery © Mapbox',
maxZoom: 18,
id: 'mapbox.streets',
accessToken: 'pk.eyJ1IjoiZW==========yJ9.3HqHQ4BMRvSPaYe8ToA7YQ'
}).addTo(map);
var marker = L.marker([51.5, -0.09]).addTo(map);
var myLines = [{
"type": "LineString",
"properties": {
"id": "1"
}
"coordinates": [
[-100, 40],
[-105, 45],
[-110, 55]
]
}, {
"type": "LineString",
"properties": {
"id": "2"
}
"coordinates": [
[-105, 40],
[-110, 45],
[-115, 55]
]
}];
var myLayer = L.geoJson().addTo(map);
myLayer.addData(myLines);
geojson = L.geoJson(myLines, {
onEachFeature: onEachFeature
}).addTo(map);
}
function highlightFeature(e) {
var layer = e.target;
layer
layer.setStyle({
weight: 25,
color: '#ff3300',
dashArray: '',
fillOpacity: 0.7
});
if (!L.Browser.ie && !L.Browser.opera) {
layer.bringToFront();
}
}
function resetHighlight(e) {
geojson.resetStyle(e.target);
layer.setStyle({
weight: 5,
color: '#0000ff',
dashArray: '',
fillOpacity: 0.7
});
}
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
// click: zoomToFeature
});
}
$('select[name="dropdown"]').change(function() {
var item = $(this).val();
alert("call the do something function on option " + item);
//how to make the chosen line highlighted ??
});
The resetStyle method of L.GeoJSON reset the given layer's style back to the style defined when initializing the L.GeoJSON layer:
Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events.
http://leafletjs.com/reference.html#geojson-resetstyle
Code example:
var geojsonLayer = new L.GeoJSON(geojson, {
style: function () {
return {
color: 'red'
}
},
onEachFeature: function (feature, layer) {
layer.on('mouseover', function () {
this.setStyle({
color: 'green'
});
});
layer.on('mouseout', function () {
geojsonLayer.resetStyle(this);
});
}
}).addTo(map);
Working example on Plunker: http://plnkr.co/edit/iriGMBYiFRizeXizMF06?p=preview

Categories

Resources