How to add I3SLoader 3dtile layer (deck.gl) integrated with mapbox - mapbox-gl-js

I am trying to add arcgis 3d layer in mapbox with DeckGL. But I have this error (Uncaught TypeError: Tile3DLayer is not a constructor)
If I could bring data from arcgis sceneserver ,I try add two maps like compare(mapbox gl swipe tool) them.
maybe there are different ways to solve this problem. Taking the arcgis data I need and calling two maps on the same web page. Then make a presentation with the comparison tool between these maps.
<html>
<head>
<title>deck.gl + Mapbox Integration</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.50.0/mapbox-gl.js"></script>
<link rel="stylesheet" type="text/css" href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.50.0/mapbox-gl.css">
<script src="https://unpkg.com/#loaders.gl/i3s#2.1.6/dist/dist.min.js"></script>
</head>
<body>
<div id="map" style="width: 100vw; height: 100vh"></div>
</body>
<script type="text/javascript">
const { MapboxLayer, ScatterplotLayer } = deck;
// Get a mapbox API access token
mapboxgl.accessToken = 'pk.eyJ1IjoidWJlcmRhdGEiLCJhIjoiY2pudzRtaWloMDAzcTN2bzN1aXdxZHB5bSJ9.2bkj3IiRC8wj3jLThvDGdA';
// Initialize mapbox map
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v9',
center: [-74.50, 40],
zoom: 9
});
const {DeckGL, Tile3DLayer} = deck;
const {I3SLoader} = loaders;
const deckgl = new DeckGL({
controller: true,
layers: [
new Tile3DLayer({
id: 'tile-3d-layer',
data:
'https://tiles.arcgis.com/tiles/z2tnIkrLQ2BRzr6P/arcgis/rest/services/SanFrancisco_Bldgs/SceneServer/layers/0',
loader: I3SLoader,
onTilesetLoad: (tileset) => {
const {zoom, cartographicCenter} = tileset;
const [longitude, latitude] = cartographicCenter;
const viewState = {
...deckgl.viewState,
zoom: zoom + 2.5,
longitude,
latitude
};
deckgl.setProps({initialViewState: viewState});
}
})
]
});
map.on('load', () => {
map.addLayer(deckgl);
});
</script>
</html>

I'm using React, the core code is here, hope I can help you.
// import { MapboxLayer } from '#deck.gl/mapbox';
// import {I3SLoader} from '#loaders.gl/i3s';
// import { Tile3DLayer } from '#deck.gl/geo-layers';
// import mapboxgl from 'mapbox-gl';
mapboxgl.accessToken = 'your-token';
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [-122.51473530281777,37.70463582140094],
zoom: 13
});
const layer = new MapboxLayer({
id:'i3s',
type: Tile3DLayer,
data: 'https://tiles.arcgis.com/tiles/z2tnIkrLQ2BRzr6P/arcgis/rest/services/SanFrancisco_Bldgs/SceneServer/layers/0',
loader: I3SLoader
});
map.on('load', () => {
map.resize();
map.addLayer(layer);
});

Related

L.GPX is not a constructor

i'm looking for import GPX file inside my Leaflet map
but when i try the site it respond with L.GPX is not a constructor
i only have that in my head
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js"></script>
and that inside body
<div id="map"></div>
<script>
var sites = {!! json_encode($markers) !!};
var map = L.map('map').setView([{{ config('leaflet.map_center_latitude') }}, {{ config('leaflet.map_center_longitude') }}], {{ config('leaflet.zoom_level') }});
L.tileLayer('https://api.maptiler.com/maps/streets/{z}/{x}/{y}#2x.png?key=2Qw6dd02HLfOXS3LDGMP', {
attribution: '© MapTiler © OpenStreetMap contributors'
}).addTo(map);
var marker;
sites.forEach(element => {
marker = L.marker([element[0], element[1]]).addTo(map);
});
var gpx = '/resources/gpx/pont.gpx'; // URL to your GPX file or the GPX itself
new L.GPX(gpx, {
async: true,
polyline_options: {
color: '#ff0000',
}
}
).on('loaded', function(e) {
map.fitBounds(e.target.getBounds());
}).addTo(map);
</script>
You have to load the plugin before you can use it:
Usage
First, include the Leaflet.js and Leaflet-GPX scripts in your HTML
page:
As described, add the following line, in your header or before your script
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-gpx/1.4.0/gpx.min.js"></script>

Fixing "Can't find variable: mapboxgl" Issue

I am not good a JS at all but after following the examples from the MAPBOX website I am unable to render a map at all. Code is exactly as it should be according to the website. The only error that shows up Can't find variable: mapboxgl. After researching this I have not found anything on this. What am I doing wrong?
MyCode:
<script>
mapboxgl.accessToken = '<? print $mapboxapi; ?>';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11', // stylesheet location
center: [<? print $SQL["long"] ?>, <? print $SQL["lat"] ?>], // starting position [lng, lat]
zoom: 9 // starting zoom
});
var marker = new mapboxgl.Marker()
.setLngLat([<? print $SQL["long"] ?>, <? print $SQL["lat"] ?>])
.addTo(map);
</script>
This renders out this code:
<script>
mapboxgl.accessToken = 'xxxxxxxxxxxxxxxxxxxxxxxx';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11', // stylesheet location
center: [-00.00000, 00.000000000], // starting position [lng, lat]
zoom: 9 // starting zoom
});
var marker = new mapboxgl.Marker()
.setLngLat([-00.00000, 00.000000000])
.addTo(map);
</script>
You probably haven't included the necessary script and CSS files in your <head> section. These bits:
<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" />

Leaflet zooms so now and than too much on clicking a cluster

Leaflet zooms so now and than too much on clicking a cluster.
A small part of 1 marker is shown on the right and a small part from the other marker is shown on the left side of the map.
My workaround is counting markers in scope and re-adjust the zoomlevel when the counter = 0.
Shouldn't that be in the zoomcalculation of leaflet?
The zoom correction:
mcg.on('clusterclick', function () {
if (markersInScope == 0) {
var zoom = map.getZoom();
map.setZoom(zoom - 1);
}
});
You could try adjusting the zoom to fit the bounds of the mcg and add some padding
mcg.on('clusterclick', function () {
map.fitBounds(mcg.getBounds().pad(0.5));
}
});
If you add the markers to a featureGroup, the bounds for the group will available to you:
Here is a sample file from Leaflet:
<!DOCTYPE html>
<html>
<head>
<title>Leaflet debug page</title>
<link rel="stylesheet" href="../../dist/leaflet.css" />
<link rel="stylesheet" href="../css/screen.css" />
<script src="../leaflet-include.js"></script>
</head>
<body>
<div id="map" style="width: 600px; height: 600px; border: 1px solid #ccc"></div>
<button onclick="geojsonLayerBounds();">Show GeoJSON layer bounds</button>
<button onclick="featureGroupBounds();">Show feature group bounds</button>
<script src="geojson-sample.js"></script>
<script>
var osmUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
osmAttrib = '© OpenStreetMap contributors',
osm = L.tileLayer(osmUrl, {maxZoom: 18, attribution: osmAttrib}),
rectangle,
featureGroup;
var map = new L.Map('map', {
center: new L.LatLng(0.78, 102.37),
zoom: 7,
layers: [osm]
});
var geojson = L.geoJson(geojsonSample, {
style: function (feature) {
return {color: feature.properties.color};
},
onEachFeature: function (feature, layer) {
var popupText = 'geometry type: ' + feature.geometry.type;
if (feature.properties.color) {
popupText += '<br/>color: ' + feature.properties.color
}
layer.bindPopup(popupText);
}
});
geojson.addLayer(new L.Marker(new L.LatLng(2.745530718801952, 105.194091796875)))
var eye1 = new L.Marker(new L.LatLng(-0.7250783020332547, 101.8212890625));
var eye2 = new L.Marker(new L.LatLng(-0.7360637370492077, 103.2275390625));
var nose = new L.Marker(new L.LatLng(-1.3292264529974207, 102.5463867187));
var mouth = new L.Polyline([
new L.LatLng(-1.3841426927920029, 101.7333984375),
new L.LatLng(-1.6037944300589726, 101.964111328125),
new L.LatLng(-1.6806671337507222, 102.249755859375),
new L.LatLng(-1.7355743631421197, 102.67822265625),
new L.LatLng(-1.5928123762763, 103.0078125),
new L.LatLng(-1.3292264529974207, 103.3154296875)
]);
map.addLayer(eye1).addLayer(eye2).addLayer(nose).addLayer(mouth);
featureGroup = new L.FeatureGroup([eye1, eye2, nose, mouth]);
map.addLayer(geojson);
map.addLayer(featureGroup);
function geojsonLayerBounds() {
if (rectangle) {
rectangle.setBounds(geojson.getBounds());
} else {
rectangle = new L.Rectangle(geojson.getBounds());
map.addLayer(rectangle);
}
}
function featureGroupBounds() {
if (rectangle) {
rectangle.setBounds(featureGroup.getBounds());
} else {
rectangle = new L.Rectangle(featureGroup.getBounds());
map.addLayer(rectangle);
}
}
</script>
</body>
</html>

MapBox markers Move on zooming

I'm working on MapBoxgl and I want to add several markers.
Here is my index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<link href=" /assets/css/bootstrap.min.css " rel="stylesheet" />
<link href=" /assets/css/mapbox-gl.css " rel="stylesheet" />
<link href=" /assets/css/main.css " rel="stylesheet" />
</head>
<body>
<div id="map"></div>
<script src="/assets/js/mapbox-gl.js"></script>
<script src="/assets/js/map-style.js"></script>
</body>
</html>
This is map-style.js:
var map = new mapboxgl.Map({
container: 'map',
center: [57.3221, 33.5928],
zoom: 5,
style: style
});
var geojson = {
type: 'FeatureCollection',
features: [{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [30.61, 46.28]
},
properties: {
title: 'point 1',
description: 'point 1 Description',
message: 'point1',
iconSize: [25, 25]
}
},
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [30.62, 46.2845]
},
properties: {
title: 'point 2',
description: 'point 2 Description',
message: 'point 2',
iconSize: [25, 25]
}
}]
};
map.on('load', function () {
// add markers to map
geojson.features.forEach(function(marker) {
// create a DOM element for the marker
var el = document.createElement('div');
el.className = 'markers';
el.style.backgroundImage = 'url(assets/marker-azure.png)';
//el.style.width = marker.properties.iconSize[0] + 'px';
el.style.height = marker.properties.iconSize[1] + 'px';
el.addEventListener('click', function() {
window.alert(marker.properties.message);
});
// add marker to map
new mapboxgl.Marker(el)
.setLngLat(marker.geometry.coordinates)
.addTo(map);
});
});
And following is main.css portion related to map and marker:
#map { position:absolute; top:0; bottom:0; width:100% }
.markers {
display: absolute;
border: none;
border-radius: 50%;
cursor: pointer;
padding: 0;
}
So, my problem is that when I add width property to markers, their icon be displayed correctly (with a bit stretch) but they are in wrong coordinate and move on zoom, like picture below:
On the other hand, if width property is eliminated, they are in right place and does not move on zooming, but they are very stretched and in fact as wide as screen (following image):
It's noteworthy that I've used bootstrap. Can it be the reason of this? If not, what's the problem?
Thanks
import 'mapbox-gl/dist/mapbox-gl.css';
Adding import css works for me.
I found the solution and share it here with others who will encounter this problem. The problem caused because of using a not-most-recent version of the library. After upgrading to the latest release, I could get rid of that problem.
Note that these kinds of problems sometimes occur, when you use npm. Make sure that the library is downloaded completely and It's the latest release.
Latest releases of MapBox can be found at here.
had similar issue, the marker seemed to change position on zoom in/out, fixed it by setting offset, thought to share if it can help others, here is the fiddle
// add marker to map
var m = new mapboxgl.Marker(el, {offset: [0, -50/2]});
m.setLngLat(coordinates);
m.addTo(map);
(Using mapbox 1.13.0)
I had a similar issue where the popups weren't displaying and would change position based on zoom.
Mapbox officially states that you need to include the css file to have markers and popups work as expected.
https://docs.mapbox.com/mapbox-gl-js/guides/install/
HOWEVER, you can also copy that css directly into a component and use that as an element. For example:
export default function MarkerMapTest(props) {
const mapContainer = React.useRef(null)
const map = React.useRef(null)
const elemRef = React.useRef(null)
React.useEffect(() => {
map.current = new mapboxgl.Map({
container: mapContainer.current,
style: "mapbox://styles/mapbox/dark-v10",
center: [151.242, -33.9132],
zoom: 14,
})
const marker = new mapboxgl.Marker({
element: elemRef.current,
})
.setLngLat([151.242, -33.9132])
.addTo(map.current)
}, [])
return (
<div
style={{ width: 600, height: 600, backgroundColor: "gray" }}
ref={mapContainer}
>
<div
style={{
width: 30,
height: 30,
borderRadius: 15,
backgroundColor: "red",
position: "absolute", // !
top: 0, // !
left: 0, // !
}}
ref={elemRef}
/>
</div>
In my case the svg I used had some space around the real content. That way it seemed for me that the marker was moving. A simple fix was to remove the space around the content (e.g. with the "Resize page to drawing or selection" option of inkscape: https://graphicdesign.stackexchange.com/a/21638)
Also it is important to set display: block on the svg-marker. See: https://stackoverflow.com/a/39716426/11603006

OSM leafleft JS Getting the center and radius of an editable circle

I am using OSM using layer Leaflet Js.I am trying to edit the circle using the Leaflet.Editable.js. I think, getting the circle and the radius using the 'editable:vertex:dragend' event is not a right approach.
Is there any other way to get the circle center and radius after dragging it.
Here is my apprach
<link href="https://leafletjs-cdn.s3.amazonaws.com/content/leaflet/master/leaflet.css" rel="stylesheet" type="text/css" />
<script src="https://leafletjs-cdn.s3.amazonaws.com/content/leaflet/master/leaflet.js"></script>
<script src="Leaflet.Editable.js"></script>
<style type="text/css">
#mapdiv { height: 500px; }
</style>
<div id="mapdiv"></div>
<script type="text/javascript">
var map = L.map('mapdiv', {editable: true}).setView([23.2599333, 77.41261499999996], 13);
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors',
maxZoom: 30
}).addTo(map);
L.EditControl = L.Control.extend({
options: {
position: 'topleft',
callback: null,
kind: '',
html: ''
},
onAdd: function (map) {
var container = L.DomUtil.create('div', 'leaflet-control leaflet-bar'),
link = L.DomUtil.create('a', '', container);
link.href = '#';
link.title = 'Create a new ' + this.options.kind;
link.innerHTML = this.options.html;
L.DomEvent.on(link, 'click', L.DomEvent.stop)
.on(link, 'click', function () {
window.LAYER = this.options.callback.call(map.editTools);
}, this);
return container;
}
});
var circle = L.circle([23.2599333, 77.41261499999996], {radius: 1000}).addTo(map);
circle.enableEdit();
circle.on('dblclick', L.DomEvent.stop).on('dblclick', circle.toggleEdit);
//circle.on('editable:vertex:drag', function (e) {
map.on('editable:vertex:dragend', function (e) {
//alert(e.vertex.latlng);
circle.setLatLng(e.vertex.latlng);
alert(circle.getRadius());
});
</script>
Any help on this regard or the best approach will be really helpful.
Yes, I would suggest using
map.on('editable:drawing:move', function (e) {
console.log(circle.getLatLng())
console.log(circle.getRadius());
});
This works for either dragging the vertex on the outer edge of the circle, or drags of the entire circle from the center marker.