Answer the question
In order to leave comments, you need to log in
Why are all the markers outside the mapbox?
I'm trying to deal with mapbox + typescript. Everything was great until I tried the marker example. I didn’t change anything in the logic, I just remade it for typescript. For some reason, the block with markers ignores the size of the map itself and stretches as much as it wants. I set the width both through css and through the attribute, it did not help. What could be the problem?
import React, { Component } from "react";
import ENVIRONMENT from "../../environment";
import "./map-style.css";
import mapboxgl from "mapbox-gl";
import mapboxDefaultLayers from "./map-layers";
import mapboxDefaultSources from "./map-sources";
mapboxgl.accessToken = ENVIRONMENT.mapbox.accessToken;
export interface MapControllerProperties {
map: mapboxgl.Map
}
export interface MapProperties extends mapboxgl.MapboxOptions {
onload(map: mapboxgl.Map): void
}
export interface PaintParameters {
'fill-extrusion-color': string,
'fill-extrusion-height': []
}
export interface LayerParameters {
id: string,
source: string,
'sourse-layer': string,
fiter: Array<string>,
type: string,
minzoom: number,
paint: PaintParameters
}
export const defaultMapProperties: MapProperties = {
style: "mapbox://styles/mapbox/streets-v11",
container: "map",
zoom: 0,
center: [0, 0],
onload: () => { console.log("Map was succesfully loaded..."); }
};
export class MapController implements MapControllerProperties {
map: mapboxgl.Map;
constructor(props: MapProperties = defaultMapProperties) {
this.map = new mapboxgl.Map(props);
this.map.addControl(new mapboxgl.NavigationControl());
this.map.on('load', () => {
try {
props.onload(this.map);
} catch (err) {
console.error(err);
}
});
}
public static createLayer(map: mapboxgl.Map, layerParameters: mapboxgl.Layer, labelLayerId?: string) {
try {
map.addLayer(layerParameters, labelLayerId);
} catch (err) {
console.error(err);
}
}
public static createSource(map: mapboxgl.Map, sourceParameters: mapboxgl.Source | any, labelSourceId: string) {
try {
map.addSource(labelSourceId, sourceParameters);
} catch (err) {
console.error(err);
}
}
public createLayer(layerParameters: mapboxgl.Layer, labelLayerId?: string) {
MapController.createLayer(this.map, layerParameters, labelLayerId);
}
public createSource(sourceParameters: mapboxgl.Source | any, labelSourceId: string) {
MapController.createSource(this.map, sourceParameters, labelSourceId);
}
}
export default class Map extends Component<any, any> {
mapController?: MapController;
markers: any = {};
markersOnScreen: any = {};
constructor(props: any) {
super(props);
}
componentDidMount() {
this.mapController = new MapController({
style: "mapbox://styles/mapbox/streets-v11",
container: "map",
onload: () => {
if (!this.mapController) { return; }
this.mapController.createLayer(mapboxDefaultLayers.Buildings3D);
this.mapController.createSource(mapboxDefaultSources.Earthquakes, 'earthquakes');
this.mapController.createLayer(mapboxDefaultLayers.ClusterCircle);
this.mapController.createLayer(mapboxDefaultLayers.ClusterCircleLabel);
// after the GeoJSON data is loaded, update markers on the screen and do so on every map move/moveend
this.mapController.map.on('data', (e) => {
if (!this.mapController) { return; }
if (e.sourceId !== 'earthquakes' || !e.isSourceLoaded) return;
this.mapController.map.on('move', this.updateMarkers);
this.mapController.map.on('moveend', this.updateMarkers);
this.updateMarkers();
});
}
});
}
private updateMarkers = () => {
if (!this.mapController) { return; }
let newMarkers = {};
let features: any = this.mapController.map.querySourceFeatures('earthquakes');
// for every cluster on the screen, create an HTML marker for it (if we didn't yet),
// and add it to the map if it's not there already
for (let i = 0; i < features.length; i++) {
let coords = features[i].geometry.coordinates;
let props = features[i].properties;
if (!props.cluster) continue;
let id = props.cluster_id;
let marker = this.markers[id];
if (!marker) {
let el: any = this.createDonutChart(props);
marker = this.markers[id] = new mapboxgl.Marker({ element: el }).setLngLat(coords);
}
newMarkers[id] = marker;
if (!this.markersOnScreen[id]) marker.addTo(this.mapController.map);
}
// for every marker we've added previously, remove those that are no longer visible
for (let id in this.markersOnScreen) {
if (!newMarkers[id]) this.markersOnScreen[id].remove();
}
this.markersOnScreen = newMarkers;
}
// code for creating an SVG donut chart from feature properties
private createDonutChart = (props) => {
let offsets: any = [];
let counts = [
props.mag1,
props.mag2,
props.mag3,
props.mag4,
props.mag5
];
let total = 0;
let fontSize = total >= 1000 ? 22 : total >= 100 ? 20 : total >= 10 ? 18 : 16;
let r = total >= 1000 ? 50 : total >= 100 ? 32 : total >= 10 ? 24 : 18;
let r0 = Math.round(r * 0.6);
let w = r * 2;
let html = '<div><svg width="' + w + '" height="' + w + '" viewbox="0 0 ' + w + ' ' + w + '" text-anchor="middle" style="font: ' + fontSize + 'px sans-serif; display: block">';
const colors = ['#fed976', '#feb24c', '#fd8d3c', '#fc4e2a', '#e31a1c'];
for (let i = 0; i < counts.length; i++) {
offsets.push(total);
total += counts[i];
}
for (let i = 0; i < counts.length; i++) {
html += this.donutSegment(
offsets[i] / total,
(offsets[i] + counts[i]) / total,
r,
r0,
colors[i]
);
}
html += '<circle cx="' + r + '" cy="' + r + '" r="' + r0 + '" fill="white" /><text dominant-baseline="central" transform="translate(' + r + ', ' + r + ')">' + total.toLocaleString() + '</text></svg></div>';
let el = document.createElement('div');
el.innerHTML = html;
return el.firstChild;
}
private donutSegment = (start, end, r, r0, color) => {
if (end - start === 1) end -= 0.00001;
const a0 = 2 * Math.PI * (start - 0.25);
const a1 = 2 * Math.PI * (end - 0.25);
const x0 = Math.cos(a0), y0 = Math.sin(a0);
const x1 = Math.cos(a1), y1 = Math.sin(a1);
const largeArc = end - start > 0.5 ? 1 : 0;
return [
'<path d="M',
r + r0 * x0,
r + r0 * y0,
'L',
r + r * x0,
r + r * y0,
'A',
r,
r,
0,
largeArc,
1,
r + r * x1,
r + r * y1,
'L',
r + r0 * x1,
r + r0 * y1,
'A',
r0,
r0,
0,
largeArc,
0,
r + r0 * x0,
r + r0 * y0,
'" fill="' + color + '" />'
].join(' ');
}
render() {
return (
<div id="map" width="1200px" height="800px" style={{ width: '1200px', height: '800px' }}></div>
);
}
}
Answer the question
In order to leave comments, you need to log in
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question