Unable to add floors in Mapbox GL - javascript

I want to add 2 or 3 floors for each building using MapBox GL, but when i try using the addlayer, the colours are getting overriden but no layers or floors are added. Been stuck with this for some time now.
I want 3d extrusions of floors in a building.
Tried putting this into a button click as well, but still it is not returning expected results.
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title></title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.39.1/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.39.1/mapbox-gl.css' rel='stylesheet' />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<div id='map'>
</div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiZGFuc3dpY2siLCJhIjoiY2l1dTUzcmgxMDJ0djJ0b2VhY2sxNXBiMyJ9.25Qs4HNEkHubd4_Awbd8Og';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v9',
center: [-87.61694, 41.86625],
zoom: 15.99,
pitch: 40,
bearing: 20
});
map.on('load', function() {
map.addLayer({
'id': 'room-extrusion10',
'type': 'fill-extrusion',
'source': 'composite',
'source-layer': 'building',
'paint': {
'fill-extrusion-color': 'blue',
'fill-extrusion-height': {
'type': 'identity',
'property': 'height'
},
'fill-extrusion-base': {
'type': 'identity',
'property': 'max_height'
},
'fill-extrusion-opacity': 1
}
});
map.addLayer({
'id': 'room-extrusion11',
'type': 'fill-extrusion',
'source': 'composite',
'source-layer': 'building',
'paint': {
'fill-extrusion-color': 'red',
'fill-extrusion-height': {
'type': 'identity',
'property': 'height'
},
'fill-extrusion-base': {
'type': 'identity',
'property': 'min_height'
},
'fill-extrusion-opacity': 1
}
},'room-extrusion10');
});
</script>
</body>
</html>

fill-extrusion-height and fill-extrusion-base are the paint properties that control the lower and upper height (in meters) of a fill-extrusion feature. In your example these are styled with identity functions based on building height data from OpenStreetMap (in the Mapbox Streets data source), causing them to imitate real-world building shapes (as best as they are mapped). In order to create a fill-extrusion layer that spans only one floor you'd want fill-extrusion-height: 3 (or however tall, in meters, you perceive one story to be) and fill-extrusion-base: 0 for the first floor; the second would be height=6 and base=3, and so forth.
Note that in all released versions of Mapbox GL JS, multiple fill-extrusion layers don't render correctly with respect to each other. This is fixed in master and will be included in the next release this month.

Related

Only rendering Mapbox features once, when showing multiple world copies? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I'm working on this Mapbox map, and shows features using geojson/FeatureCollection (basically something like this).
If you zoom all the way out, the map will show multiple world copies (which I want), but it will also show each feature on ALL world copies (don't want this!). What should I do so that the mapbox only displays the features on ONE of the world copies?
The example linked above also has the same issue (as you can see in the image below).
Sample code showcasing the issue
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Add multiple geometries from one GeoJSON source</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1Ijoic2h1YmhhbW1laHJhIiwiYSI6ImNqempxZWNqeDBicnMzbnFpaTZ6amVmYjQifQ.US2y0mYyWtRABvxzfpBWrw';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/outdoors-v11',
center: [-121.403732, 40.492392],
zoom: 10
});
map.on('load', function () {
map.addSource('national-park', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'geometry': {
'type': 'Polygon',
'coordinates': [
[
[-121.353637, 40.584978],
[-121.284551, 40.584758],
[-121.275349, 40.541646],
[-121.246768, 40.541017],
[-121.251343, 40.423383],
[-121.32687, 40.423768],
[-121.360619, 40.43479],
[-121.363694, 40.409124],
[-121.439713, 40.409197],
[-121.439711, 40.423791],
[-121.572133, 40.423548],
[-121.577415, 40.550766],
[-121.539486, 40.558107],
[-121.520284, 40.572459],
[-121.487219, 40.550822],
[-121.446951, 40.56319],
[-121.370644, 40.563267],
[-121.353637, 40.584978]
]
]
}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-121.415061, 40.506229]
}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-121.505184, 40.488084]
}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-121.354465, 40.488737]
}
}
]
}
});
map.addLayer({
'id': 'park-boundary',
'type': 'fill',
'source': 'national-park',
'paint': {
'fill-color': '#888888',
'fill-opacity': 0.4
},
'filter': ['==', '$type', 'Polygon']
});
map.addLayer({
'id': 'park-volcanoes',
'type': 'circle',
'source': 'national-park',
'paint': {
'circle-radius': 6,
'circle-color': '#B42222'
},
'filter': ['==', '$type', 'Point']
});
});
</script>
</body>
</html>
I don't think this is possible. Geographically, what you're asking for doesn't really make sense. Your point has the same location as the map tile underneath it, so to have the basemap display but not your point, on the basis of the user having effectively rotated the map is...weird.
Your best workaround would be to use a Marker rather than a symbol layer. Each Marker is a single DOM element so only ever displayed once.

ApexCharts - Adding a number inside the "Simple Donut Chart"

I have been trying to add a number on the inside of the "Simple donut chart" from ApexCharts. This is the link to it - https://apexcharts.com/javascript-chart-demos/pie-charts/simple-donut/ .
To use the chart, I ran the command "npm install apexcharts --save" in my project terminal.
This is my HTML file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="./Chart.css">
<script src="./Chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
</head>
<div id="chart"></div>
<script>
const chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();
</script>
</html>
This is my CSS file:
#chart{
width:400px;
height:400px;
margin-left: auto;
margin-right: auto;
}
This is what I used in my JavaScript file:
var options = {
series: [44, 55, 41, 60],
labels: ["Transport", "Shopping", "Energy use", "Food"],
chart: {
type: 'donut',
},
responsive: [{
breakpoint: 480,
options: {
chart: {
width: 200
},
legend: {
position: 'bottom'
}
}
}]
};
This is the result of the code mentioned above:
Current Chart
This is a model to show how I would like the number to be displayed:
Example Chart
I would like to know if its possible to add a number inside the current chart with ApexCharts as the example chart shows.
Yes it's possible.
let options = {
series: [44, 55, 41, 60],
labels: ["Transport", "Shopping", "Energy use", "Food"],
chart: {
type: 'donut',
},
plotOptions: {
pie: {
donut: {
labels: {
show: true,
total: {
show: true,
label: '',
formatter: () => 'Text you want'
}
}
}
}
}
};
const chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();
<script src="https://cdn.jsdelivr.net/npm/apexcharts#3.18.1/dist/apexcharts.min.js"></script>
<div id="chart"></div>
You can show the following information inside a donut:
a value of an individual donut piece (on hover to that piece)
the total of all the donut pieces
custom text
Try to change values of the total object properties to better understanding what I mean. More detailed information is here

Edit Polygon Added with map.addLayer in Mapbox

I want to edit polygon which i have added using map.addLayer() on mapbox.
the code:
map.addLayer({
'id': 'maine'+id,
'type': 'fill',
'source': {
'type': 'geojson',
'data': {
'type': 'Feature',
'geometry': {
'type': 'Polygon',
'coordinates': coords
}
}
},
'layout': {},
'paint': {
'fill-color': '#088',
'fill-opacity': 0.8
}
});
Mapbox GL Drawing Library is used to draw/edit the shapes.
You have added the polygon as a map layer. Editing the layer in drawing mode directly seems not possible. Here is a possible way
You need to hide the layer first.
Get the Polygon data from layer source
Init the drawing mode and add a new polygon to drawing manager with the polygon data
Once the editing finished, update the layer source with the edited polygon data from drawing manager
Remove the polygon from the drawing manager
Show the updated layer
You need to use the add method to draw an existing shape.
draw.add({
'id': 'polygon-3355',
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'Polygon',
'coordinates': [[[-67.13734351262877, 45.137451890638886],
[-66.96466, 44.8097],
[-68.03252, 44.3252],
[-69.06, 43.98],
[-70.11617, 43.68405],
[-70.64573401557249, 43.090083319667144],
[-70.75102474636725, 43.08003225358635],
[-70.79761105007827, 43.21973948828747],
[-70.98176001655037, 43.36789581966826],
[-70.94416541205806, 43.46633942318431],
[-71.08482, 45.3052400000002],
[-70.6600225491012, 45.46022288673396],
[-70.30495378282376, 45.914794623389355],
[-70.00014034695016, 46.69317088478567],
[-69.23708614772835, 47.44777598732787],
[-68.90478084987546, 47.184794623394396],
[-68.23430497910454, 47.35462921812177],
[-67.79035274928509, 47.066248887716995],
[-67.79141211614706, 45.702585354182816],
[-67.13734351262877, 45.137451890638886]]]
}
});
Library Link:
https://github.com/mapbox/mapbox-gl-draw
API Methods Reference:
https://github.com/mapbox/mapbox-gl-draw/blob/master/docs/API.md
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title>Show drawn polygon area</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.50.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.50.0/mapbox-gl.css' rel='stylesheet' />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<style>
.calculation-box {
height: 75px;
width: 150px;
position: absolute;
bottom: 40px;
left: 10px;
background-color: rgba(255, 255, 255, .9);
padding: 15px;
text-align: center;
}
p {
font-family: 'Open Sans';
margin: 0;
font-size: 13px;
}
</style>
<script src='https://api.tiles.mapbox.com/mapbox.js/plugins/turf/v3.0.11/turf.min.js'></script>
<script src='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.0.9/mapbox-gl-draw.js'></script>
<link rel='stylesheet' href='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.0.9/mapbox-gl-draw.css' type='text/css'/>
<div id='map'></div>
<div class='calculation-box'>
<p>Draw a polygon using the draw tools.</p>
<div id='calculated-area'></div>
</div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiZWRlbnJheWdhcmRuZXIiLCJhIjoiRlZRVlhqOCJ9.tDrWaeNRbMCtXAovQLYuzA';
/* eslint-disable */
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/mapbox/streets-v8',
center: [-70.11617, 43.68405],
zoom: 5
});
var draw = new MapboxDraw({
displayControlsDefault: false,
controls: {
polygon: true,
trash: true
}
});
map.addControl(draw);
map.on('draw.create', updateArea);
map.on('draw.delete', updateArea);
map.on('draw.update', updateArea);
draw.add({
'id': 'polygon-3355',
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'Polygon',
'coordinates': [[[-67.13734351262877, 45.137451890638886],
[-66.96466, 44.8097],
[-68.03252, 44.3252],
[-69.06, 43.98],
[-70.11617, 43.68405],
[-70.64573401557249, 43.090083319667144],
[-70.75102474636725, 43.08003225358635],
[-70.79761105007827, 43.21973948828747],
[-70.98176001655037, 43.36789581966826],
[-70.94416541205806, 43.46633942318431],
[-71.08482, 45.3052400000002],
[-70.6600225491012, 45.46022288673396],
[-70.30495378282376, 45.914794623389355],
[-70.00014034695016, 46.69317088478567],
[-69.23708614772835, 47.44777598732787],
[-68.90478084987546, 47.184794623394396],
[-68.23430497910454, 47.35462921812177],
[-67.79035274928509, 47.066248887716995],
[-67.79141211614706, 45.702585354182816],
[-67.13734351262877, 45.137451890638886]]]
}
});
function updateArea(e) {
var data = draw.getAll();
var answer = document.getElementById('calculated-area');
if (data.features.length > 0) {
var area = turf.area(data);
// restrict to area to 2 decimal points
var rounded_area = Math.round(area*100)/100;
answer.innerHTML = '<p><strong>' + rounded_area + '</strong></p><p>square meters</p>';
} else {
answer.innerHTML = '';
if (e.type !== 'draw.delete') alert("Use the draw tools to draw a polygon!");
}
}
</script>
</body>
</html>

Reading a local geojson file with Mapbox

I am currently trying to make a simple visualization using Mapbox that is based on additional data provided by a local geojson file. I cannot upload this file to Mapbox and would like to keep it local.
I have used this base code from Mapbox that I have modified to include a local geojson file that is structured like this:
{"features": [{"geometry": null, "location": {"coordinates": [40.730610, -73.935242], "type": "Point"}, "properties": {"X": "1", "group": "1"}, "type": "Feature"},...}
I have modified the example code from Mapbox so that it is now:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title>Style circles with a data-driven property</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.48.0/mapbox-gl.js'></script>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.48.0/mapbox-gl.css' rel='stylesheet' />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<div id='map'></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoibG9ubmliZXNhbmNvbiIsImEiOiJjamxjaWNpOHQwMHV0M3FwaHhneGhvY2l2In0.7GxI8W_dnTKITNF4hEvZeQ';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v9',
zoom: 12,
center: [-73.935242, 40.730610],
pitch: 20,
});
var url = "GeoObs.json.json"
map.on('load', function () {
var layers = map.getStyle().layers;
var labelLayerId;
for (var i = 0; i < layers.length; i++) {
if (layers[i].type === 'symbol' && layers[i].layout['text-field']) {
labelLayerId = layers[i].id;
break;
}
}
map.addSource("my_data", {
type: "geojson",
data: url //"./GeoObs.json",
/*cluster: true,
clusterMaxZoom: 15, // Max zoom to cluster points on
clusterRadius: 50 // Radius of each cluster when clustering points (defaults to 50)*/
});
map.addLayer({
'id': 'population',
'type': 'circle',
source: 'my_data',
'source-layer': 'my_data',
'paint': {
// make circles larger as the user zooms from z12 to z22
'circle-radius': {
'base': 1.75,
'stops': [[12, 2], [22, 180]]
},
// color circles by ethnicity, using a match expression
// https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-match
'circle-color': [
'match',
['get', 'group'],
'1', '#fbb03b',
'2', '#223b53',
'3', '#e55e5e',
'4', '#3bb2d0',
/* other */ '#ccc'
]
}
});
map.addLayer({
'id': '3d-buildings',
'source': 'composite',
'source-layer': 'building',
'filter': ['==', 'extrude', 'true'],
'type': 'fill-extrusion',
'minzoom': 15,
'paint': {
'fill-extrusion-color': '#aaa',
// use an 'interpolate' expression to add a smooth transition effect to the
// buildings as the user zooms in
'fill-extrusion-height': [
"interpolate", ["linear"], ["zoom"],
15, 0,
15.05, ["get", "height"]
],
'fill-extrusion-base': [
"interpolate", ["linear"], ["zoom"],
10, 0,
15.05, ["get", "min_height"]
],
'fill-extrusion-opacity': .6
}
}, labelLayerId);
});
</script>
</body>
</html>
I get the following error:
Error: Source layer "my_data" does not exist on source "my_data" as specified by style layer "population"
at i._validateLayer (style.js:274)
at i.addLayer (style.js:576)
at o.addLayer (map.js:1175)
at o.<anonymous> (index3.html:52)
at o.L.fire (evented.js:115)
at o._render (map.js:1619)
at map.js:1683
Can anyone point me in the direction of a possible mistake here and hopefully how to fix it. You can use the example geojson I gave you to try out this example. Just copy paste it into a file called: GeoObs.json if you want the code to right away give the same error.
As the error states, your GeoJSON source does not have a source layer. So you can remove the 'source-layer' property from the map.addLayer call.
Your GeoJSON also needs to be modified to a proper FeatureCollection:
{
"type": "FeatureCollection",
"features": [
{
"geometry": {
"type": "Point",
"coordinates": [
-73.935242,
40.730610
]
},
"properties": {
"X": "1",
"group": "1"
},
"type": "Feature"
}
]
}
For the population layer, comment out the line, because you do not have such a layer:
'source-layer': 'my_data',
And maybe you have an extra ".json" in the URL:
GeoObs.json.json
[ https://jsfiddle.net/c5nauwgx/ ]
This example from MapLibre helped me and also works with Mapbox GL JS. It adds a little interactivity to your map by giving you the option to select a local geojson file within the map.
https://maplibre.org/maplibre-gl-js-docs/example/local-geojson/

Filling color to polygons using Mabox-gl-js

I've countries GeoJson with a geometry of type polygon. Each polygon has only one property name (name is the country name). each polygon represents a country.
Now I want to paint each polygon with different color depending on the value of the name property, but this is not working properly.
See this JS bin Demo
map.on('load', function () {
map.addLayer({
'id': 'maine',
'type': 'fill',
'layout': {},
'paint': {
'fill-color': {
property: 'name',
stops: [
['Albania', '#F2F12D'],
['Algeria', '#7A4900'],
['Australia', '#63FFAC'],
["South Africa", "#4FC601"],
["South Korea", "#3B5DFF"],
]
},
'fill-opacity': 0.8
},
'source': {
'type': 'vector',
'url': 'mapbox://saurabhp.countries_tileset'
},
"source-layer": "countries",
});
});
Every thing in your code was perfect, the only thing which you have missed out is type: 'categorical' inside the fill-color, You need to specify the type
Checkout this link for more details run the below code snippet to see the demo
mapboxgl.accessToken = 'pk.eyJ1Ijoic2F1cmFiaHAiLCJhIjoiY2l6OWRwM2JlMDAxZTJ3b2ZwejAzdzhpdSJ9.nc4cEdRwhErEg2wuUkABbw';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v9',
center: [-1.41, 6.32],
zoom: 5
});
map.on('load', function () {
map.addLayer({
'id': 'maine',
'type': 'fill',
'layout': {},
'paint': {
'fill-color': {
property: 'name',
type: 'categorical',
stops: [
['Albania', '#F2F12D'],
['Algeria', '#7A4900'],
['Australia', '#63FFAC'],
["South Africa", "#4FC601"],
["South Korea", "#3B5DFF"],
]
},
'fill-opacity': 0.8
},
'source': {
'type': 'vector',
'url': 'mapbox://saurabhp.countries_tileset'
},
"source-layer": "countries",
});
});
<html>
<head>
<meta charset='utf-8' />
<title></title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.37.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.37.0/mapbox-gl.css' rel='stylesheet' />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id='map'></div>
</body>
</html>

Categories