Geographic Information Systems Asked by Maximilian on July 6, 2021
I can’t quite figure out how to extract elevation data from a geojson to use with Mapbox fill-extrusion-height
.
The geojson looks like this but obviously with a lot more waypoints:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"name": "Businesslauf Spielberg 1st #KingofRedbullRing",
"type": "9",
},
"geometry": {
"type": "LineString",
"coordinates": [
[
14.765181,
47.220035,
725.2
],
[
14.765127,
47.220028,
726
],
[
14.764863,
47.219974,
726
],
]
}
}
]
},
As you can see every third array item of every item in the coordinates array is elevation data.
I’m using Mapbox as a React Component like this:
import React, { useRef, useEffect, useState } from 'react'
import 'mapbox-gl/dist/mapbox-gl.css'
import mapboxgl from '!mapbox-gl' // eslint-disable-line import/no-webpack-loader-syntax
import turf from '@turf/center'
const MapBox = ({ geojson, height, pitch, zoom, BRBot }) => {
const mapContainer = useRef(null)
const map = useRef(null)
const [lng, setLng] = useState(-70.9)
const [lat, setLat] = useState(42.35)
const [zoomLevel, setZoom] = useState(zoom ? zoom : 13)
useEffect(() => {
mapboxgl.accessToken = process.env.REACT_APP_MAPBOXGL_ACCESS_TOKEN
if (map.current) {
map.current.on('move', () => {
setLng(map.current.getCenter().lng.toFixed(4))
setLat(map.current.getCenter().lat.toFixed(4))
setZoom(map.current.getZoom().toFixed(2))
})
} else {
const coords = turf(geojson).geometry.coordinates
map.current = new mapboxgl.Map({
container: mapContainer.current,
style: "mapbox://styles/track-runner/ckqjpfiyl04t118mugkuokdm6",
center: coords ? coords : [lng, lat],
zoom: zoomLevel,
pitch: pitch ? pitch : 0,
antialias: true,
})
map.current.on("load", () => {
map.current.addSource("track", {
type: "geojson",
data: geojson,
})
map.current.addLayer({
id: "track",
type: "fill-extrusion",
source: "track",
paint: {
"fill-extrusion-color": "#ff0000",
"fill-extrusion-height": ["get", "elevation"],
"fill-extrusion-opacity": 0.5,
}
})
})
}
})
return (
<div
ref={mapContainer}
style={{ height: height, position: 'relative' }}
className={BRBot && 'border-radius-bottom'}
/>
)
}
export default MapBox
My problem is with this line: "fill-extrusion-height": ["get", "elevation"],
If I give "fill-extrusion-height":
a number the code runs with no errors and the layer I’ve added with the above json is rendered but this means that the height is the same for every waypoint. I get the same result if I add "elevation": number
to the properties object in the geojson file as ["get", "elevation"]
is able to extract that number.
However, this is not what I want.
I want each waypoint to have a different height/elevation resulting in a visual representation much like this one: https://www.matt.scot/strava-3d-elevation-profiles/#the-results
I just can’t figure out how Matt has been able to extract elevation data with the line "fill-extrusion-height":["get", "elevation"],
because surely that gives him a constant number!
How do I use every elevation number for every waypoint using fill-extrusion-height?
It's all about data preparation. You split your linestring in multiple smallest linestrings where you assign elevation to each.
For the 3 cases, report the third coordinates ( implicit z
) as elevation
in each feature properties
var mygeojson = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"name": "Businesslauf Spielberg 1st #KingofRedbullRing",
"type": "9",
},
"geometry": {
"type": "LineString",
"coordinates": [
[
14.765181,
47.220035,
725.2
],
[
14.765127,
47.220028,
726
],
[
14.764863,
47.219974,
726
],
]
}
}
]
}
var mygeojsonfeatures = mygeojson.features;
var results = [];
for (let j = 0; j < mygeojsonfeatures.length;j++) {
var mycoords = mygeojsonfeatures[j].geometry.coordinates;
for (let i = 0; i < mycoords.length;i++) {
let line;
if (i == 0) {
line = turf.lineString([
mycoords[i].slice(0, 2),
turf.midpoint(turf.point(mycoords[i].slice(0, 2)), turf.point(mycoords[i + 1].slice(0, 2))).geometry.coordinates
]);
} else if (i == mycoords.length - 1) {
line = turf.lineString([
turf.midpoint(turf.point(mycoords[i - 1].slice(0, 2)), turf.point(mycoords[i].slice(0, 2))).geometry.coordinates,
mycoords[i].slice(0, 2)
]);
} else {
line = turf.lineString([
turf.midpoint(turf.point(mycoords[i - 1].slice(0, 2)), turf.point(mycoords[i].slice(0, 2))).geometry.coordinates,
mycoords[i].slice(0, 2),
turf.midpoint(turf.point(mycoords[i].slice(0, 2)), turf.point(mycoords[i + 1].slice(0, 2))).geometry.coordinates
]);
}
line.properties = Object.assign({}, mygeojsonfeatures[j].properties);
line.properties.elevation = mycoords[i][2];
console.log(mycoords[i][2], line.properties.elevation);
results.push(line)
}
}
var featOut = {
"type": "FeatureCollection",
"features": results
}
Tested using my browser console at URL https://turfjs.org/docs/
You also may substract to all elevation values the minimum value to avoid getting lines bars from extrusion too high e.g screenshot below for tilt 45° (interactive standalone demo using MapLibre GL JS, the forked version of Mapbox GL JS)
Correct answer by ThomasG77 on July 6, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP