leaflet highlight part of polyline - leaflet

in leaflet.js i have polyline in openstreet map:
point1(long, lat), 2(long, lat)....pointXY(long,lat)
Is possible (and how) highlight or change color only segment from point 2 to 5, no matter how to invoke.
I try add another polyline, but with more segments its mess with more and more duplicit points.
Working sample:
http://next.plnkr.co/edit/FyUzMG9Y9NrbYrzL
i looking for turn segment between [40,10],[10,10],[10,30] red. If its possible, by index [2,3,4]
thanks for help

You can try GeoJson layer to highlight a line. Just make sure that geojson coordinates are in LngLat format.
var map = L.map('map', {
center: [0, 0],
zoom: 0,
layers: [
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data © OpenStreetMap contributors',
}),
],
});
var data = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [[30, 10], [45, 45]],
},
properties: {
color: 'green',
},
},
{
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [[10, 40], [10, 10], [30, 10]],
},
properties: {
color: 'red',
},
},
{
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [[-45, -45], [10, 40]],
},
properties: {
color: 'black',
},
},
],
};
var geoJsonLayer = L.geoJson(data, {
onEachFeature: function(feature, layer) {
if (layer instanceof L.Polyline) {
layer.setStyle({
color: feature.properties.color,
});
}
},
}).addTo(map);
Plunker: http://next.plnkr.co/edit/s4Q72s7RyOLp714U?preview
Ref: https://embed.plnkr.co/plunk/XqzvdR

Related

How to have two mapbox raster layers with different opacities?

Im using Mapbox GL API, and I run into the issue that if I add 2 tile layers, that the opacity of the second layer in the paint object is ignored. Does anyone have any idea why this is? In the browser both tile layers have opacity 1.
let style1 = {
id: "source1-tile",
type: "raster",
source: "source1",
paint: {
"raster-opacity": 1.0
},
}
this.map.addLayer(style1);
let style2 = {
id: "source2-tile",
type: "raster",
source: "source2",
paint: {
"raster-opacity": 0.5
},
}
this.map.addLayer(style2);
// print result
console.log(this.map.getStyle().layers)
// this shows the following:
/*
[
{
id: "source1-tile"
paint: Object { "raster-opacity": 1 }
source: "source1"
type: "raster"
},
{
id: "source2-tile"
source: "source2"
type: "raster"
}
]
*/
Pay attention to add layers in map.load event. I've made this example based on mapbox-gl examples. Easily You could add more raster layers with different opacity.
mapboxgl.accessToken = 'pk.eyJ1IjoibHN0aXoiLCJhIjoiY2s5dGtnNTZ2MWVybzNobjEyam0yd2E3MyJ9.6dCvGbS93SKGMbOqZA4Qag';
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v12',
center: [-87.62, 41.86],
zoom: 9
});
map.on('load', () => {
map.addSource('chicago', {
'type': 'raster',
'url': 'mapbox://mapbox.u8yyzaor'
});
map.addLayer({
'id': 'chicago',
'source': 'chicago',
'type': 'raster'
});
map.setPaintProperty(
'chicago',
'raster-opacity',
0.5
);
});

How to use react-map-gl to draw line between two point

I am trying to draw a line between two points using react-map-gl library. I can not find example from the official document, So I am trying to reproduce same behavior from following code snippet which use Mapbox library
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [-122.486052, 37.830348],
zoom: 15
});
map.on('load', function() {
map.addSource('route', {
'type': 'geojson',
'data': {
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'LineString',
'coordinates': [
[-122.483696, 37.833818],
[-122.493782, 37.833683]
]
}
}
});
map.addLayer({
'id': 'route',
'type': 'line',
'source': 'route',
'layout': {
'line-join': 'round',
'line-cap': 'round'
},
'paint': {
'line-color': '#888',
'line-width': 8
}
});
});
Here is the sandbox, I do not see any errors on the console but the line is not displayed:
https://codesandbox.io/s/draw-line-between-two-point-v0mbc?file=/src/index.js:214-226
The code in the sandbox actually works (for me anyway), but is misleading because the line drawn is nowhere near the viewport.
A couple of things to note are that coordinates are an array given in [long, lat] which may not be what most people would assume. For example, if you cut and paste [lat,long] from google maps for San Fransisco, you get [37.77909036739809, -122.41510269913951]. Then you'll have to reverse those and put them in:
const dataOne = {
type: "Feature",
properties: {},
geometry: {
type: "LineString",
coordinates: [
[-122.41510269913951, 37.77909036739809],
[39.5423, -77.0564]
]
}
};
Also, the sample code has some cruft in it. Edit the variable dataOne not the other unused place.
Now you'll see a line from San Fransisco to some random spot in the middle of Antarctica that was really easy to miss.
Just in case the link goes bad, the full code is:
import React, { Component } from "react";
import { render } from "react-dom";
import ReactMapGL, { Source, Layer } from "react-map-gl";
class App extends Component {
constructor(props) {
super(props);
this.state = {
viewport: {
latitude: 38.63738602787579,
longitude: -121.23576311149986,
zoom: 6.8,
bearing: 0,
pitch: 0,
dragPan: true,
width: 600,
height: 600
}
};
}
render() {
const { viewport } = this.state;
const MAPBOX_TOKEN =
"pk.eyJ1Ijoic21peWFrYXdhIiwiYSI6ImNqcGM0d3U4bTB6dWwzcW04ZHRsbHl0ZWoifQ.X9cvdajtPbs9JDMG-CMDsA";
const dataOne = {
type: "Feature",
properties: {},
geometry: {
type: "LineString",
coordinates: [
[-122.41510269913951, 37.77909036739809],
[39.5423, -77.0564]
]
}
};
return (
<ReactMapGL
{...viewport}
mapboxApiAccessToken={MAPBOX_TOKEN}
onViewportChange={(newViewport) => {
this.setState({ viewport: newViewport });
}}
>
<Source id="polylineLayer" type="geojson" data={dataOne}>
<Layer
id="lineLayer"
type="line"
source="my-data"
layout={{
"line-join": "round",
"line-cap": "round"
}}
paint={{
"line-color": "rgba(3, 170, 238, 0.5)",
"line-width": 5
}}
/>
</Source>
</ReactMapGL>
);
}
}
render(<App />, document.getElementById("root"));

Mapbox proportional symbol feature radius

I'm new to Mapbox GL JS and struggling with data-driven styling. I'd like to scale my circle features proportionally based on a value in my data source (a Google Sheet). Here's a code snippet:
map.addLayer({
id: 'csvData',
type: 'circle',
source: {
type: 'geojson',
data: data
},
paint: {
'circle-color': '#dd502c',
'circle-stroke-width': 1,
'circle-stroke-color': '#dd502c',
'circle-opacity': 0.5,
"circle-radius": {
property: 'value',
stops: [
[2, 5],
[1000, 10],
[8000, 20],
]
}
}
});
Many Thanks,
Looks like AverageNitrate (I assume this was the property you were trying to plot) was a string. Converting to int did the trick.
Also I referenced it in the styling expression instead of the generic 'value'
data.features.forEach((datum)=>{
datum.properties.AverageNitrate = parseInt(datum.properties.AverageNitrate)
})
//Add the the layer to the map
map.addLayer({
id: 'csvData',
type: 'circle',
source: {
type: 'geojson',
data: data
},
paint: {
'circle-color': '#dd502c',
'circle-stroke-width': 1,
'circle-stroke-color': '#dd502c',
'circle-opacity': 0.5,
"circle-radius": {
property: 'AverageNitrate',
stops: [
[2, 5],
[1000, 10],
[8000, 20],
]
}
}
});
Here is a link to the edited fiddle: https://jsfiddle.net/mojsc6pn/35/

Adding multiple sources and layers with .each?

I try to simplify my codebase for an ongoing project. I render different lines from different sources. Adding the source and layer one by one works as expected. But if I put this in an object it won't work. I even have no errors in the console. Now I am stuck at the following code
var trip_entries = {
t2: {
trip_id: 'trip-entry-2',
trip_geojson: '[[-0.15591514, 51.51830379],[-0.07571203, 51.51424049],[-0.08533793, 51.50438536],[-0.085793, 51.5036],[-0.084793, 51.503336],[-0.089793, 51.505336]]'
},
t3: {
trip_id: 'trip-entry-3',
trip_geojson: '[[-0.15514, 51.518],[-0.075703, 51.515],[-0.085793, 51.50],[-0.0793, 51.506],[-0.08473, 51.50336],[-0.0893, 51.536]]'
},
};
// Set route
$.each(trip_entries,function(key,value){
// Add sources
map.addSource(value.trip_id,{
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'geometry': {
'type': 'LineString',
'coordinates': value.trip_geojson
}
},
],
},
});
// Add layers
map.addLayer({
'id': value.trip_id,
'type': 'line',
'source': value.trip_id,
'layout': {
'line-join': 'round',
'line-cap': 'round'
},
'paint': {
'line-color': 'rgb(160,160,160)',
'line-width': 6,
}
});
});
You are passing the geoJSON as a string, rather than an array of coordinates. You should remove the ' ' on both of your geoJSONs to get the code to run. See below:
mapboxgl.accessToken =
"pk.eyJ1IjoicGxtYXBib3giLCJhIjoiY2s3MHkzZ3VnMDFlbDNmbzNiajN5dm9lOCJ9.nbbtDF54HIXo0mCiekVxng";
var map = new mapboxgl.Map({
container: "map", // container id
style: "mapbox://styles/mapbox/streets-v11", // stylesheet location
center: [-0.084793, 51.503336], // starting position [lng, lat]
zoom: 11 // starting zoom
});
var trip_entries = {
t2: {
trip_id: "trip-entry-2",
trip_geojson: [
[-0.15591514, 51.51830379],
[-0.07571203, 51.51424049],
[-0.08533793, 51.50438536],
[-0.085793, 51.5036],
[-0.084793, 51.503336],
[-0.089793, 51.505336]
]
},
t3: {
trip_id: "trip-entry-3",
trip_geojson: [
[-0.15514, 51.518],
[-0.075703, 51.515],
[-0.085793, 51.5],
[-0.0793, 51.506],
[-0.08473, 51.50336],
[-0.0893, 51.536]
]
}
};
map.on("load", function () {
// Set route
$.each(trip_entries, function (key, value) {
// Add sources
map.addSource(value.trip_id, {
type: "geojson",
data: {
type: "FeatureCollection",
features: [
{
type: "Feature",
geometry: {
type: "LineString",
coordinates: value.trip_geojson
}
}
]
}
});
// Add layers
map.addLayer({
id: value.trip_id,
type: "line",
source: value.trip_id,
layout: {
"line-join": "round",
"line-cap": "round"
},
paint: {
"line-color": "rgb(160,160,160)",
"line-width": 6
}
});
});
});
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://api.mapbox.com/mapbox-gl-js/v1.9.1/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.9.1/mapbox-gl.css" rel="stylesheet" />
<div id="map"></div>

fill-extrusion not displaying correctly with mapbox-gl-js

This is what my dataset looks like:
Seattle Crime Dataset
What I want to do is change the extrusion height based on the frequency column. I can successfully display these as points but I'm struggling with it whenever I use fill-extrusion. Can you help point me in the right direction?
map.addLayer({
'id': 'total',
'type': 'circle',
'source': {
type: 'vector',
url: 'mapbox://askakdagr8.9tklrr8g'
},
'source-layer': 'GroupedOutput-9i6ink',
'paint': {
// make circles larger as the user zooms from z12 to z22
'circle-radius': {
'base': 1.75,
'stops': [
[12, 2],
[22, 180]
]
},
'circle-color': '#ff7770'
}
});
Since the mapbox-gl-js does not currently have functionality for extruding a circle, you need to replace the points with a polygon, and interpolating the circle, for example, by a function turf.circle:
map.on('sourcedata', function(e) {
if (e.sourceId !== 'total') return
if (e.isSourceLoaded !== true) return
var data = {
"type": "FeatureCollection",
"features": []
}
e.source.data.features.forEach(function(f) {
var object = turf.centerOfMass(f)
var center = object.geometry.coordinates
var radius = 10;
var options = {
steps: 16,
units: 'meters',
properties: object.properties
};
data.features.push(turf.circle(center, radius, options))
})
map.getSource('extrusion').setData(data);
})
[ http://jsfiddle.net/zjLek40n/ ]