I'm using MapBox GL JS v1.4.1
Based on the example here: https://docs.mapbox.com/mapbox-gl-js/example/cluster/
I cannot get my cluster count to display.
I have tried replicating the MapBox example directly and also using my own data but whatever I try results in the count not displaying.
This is what I have:
<div id="map"></div>
mapboxgl.accessToken = 'ACCESS_TOKEN';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/dark-v10',
zoom: 1
});
My geoJson data:
var geoData = {
"type": 'FeatureCollection',
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [151.12100, -33.78420]
},
"properties": {
"title" : "title",
"description": "description"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [151.12100, -33.78420]
},
"properties": {
"title" : "title",
"description": "description"
}
}
]
};
Loading the map, adding geoJSON, clusters etc:
map.on('load', function() {
map.addSource("testMapData", {
type: "geojson",
data: geoData,
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50
});
map.addLayer({
id: "cluster-count",
type: "symbol",
source: "testMapData",
filter: ["has", "point_count"],
layout: {
"text-field": "{point_count_abbreviated}",
"text-font": ["Arial Unicode MS Bold"],
"text-size": 12,
"text-allow-overlap" : true
}
});
map.addLayer({
id: "clusters",
type: "circle",
source: "testMapData",
filter: ["has", "point_count"],
paint: {
"circle-color": "#f1f075",
"circle-radius": 40
}
});
map.addLayer({
id: "unclustered-point",
type: "circle",
source: "testMapData",
filter: ["!", ["has", "point_count"]],
paint: {
"circle-color": "#51bbd6",
"circle-radius": 8,
"circle-stroke-width": 1,
"circle-stroke-color": "#fff"
}
});
});
Based on the above I should get the cluster count on each of my clusters, but I only see the cluster with no count.
The console also shows no errors.
I can't determine if there's an issue with my geoJSON (it validates via the linter here: http://geojsonlint.com/)... or if the issue lies in how I have added the cluster-count layer... or somewhere else entirely.
Currently you are adding the cluster-count layer before the clusters layer so the latter is covering up the former. If you switch the order you will see both: https:///codepen.io/pj_leonard/pen/bGGgYwv?editors=1000
Update your code to the following:
map.on('load', function() {
map.addSource("testMapData", {
type: "geojson",
data: geoData,
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50
});
map.addLayer({
id: "clusters",
type: "circle",
source: "testMapData",
filter: ["has", "point_count"],
paint: {
"circle-color": "#f1f075",
"circle-radius": 40
}
});
map.addLayer({
id: "cluster-count",
type: "symbol",
source: "testMapData",
filter: ["has", "point_count"],
layout: {
"text-field": "{point_count_abbreviated}",
"text-font": ["Arial Unicode MS Bold"],
"text-size": 12,
"text-allow-overlap" : true
}
});
map.addLayer({
id: "unclustered-point",
type: "circle",
source: "testMapData",
filter: ["!", ["has", "point_count"]],
paint: {
"circle-color": "#51bbd6",
"circle-radius": 8,
"circle-stroke-width": 1,
"circle-stroke-color": "#fff"
}
});
});
Disclaimer: I work at Mapbox
If the order of the layers is correct, pay attention to text font, eg: "text-font": ["MicrosoftYaHeiRegular"]
Related
I am trying to display multiple circles on a mapbox-gl map. The color of the circles depends on the value of the aqi property. I have set interpolation of the color depending on that value. The problem is I am always getting black circles.
The circle color property:
'circle-color': [
'interpolate',
['linear'],
['get', 'aqi'],
0,
'#eee695',
50,
'#a5fc03',
100,
'#dbfc03',
200,
'#fc1c03'
],
The full function:
map.on('load', () => {
Axios.get('https://api.waqi.info/map/bounds/?latlng=41.03143,20.52421,42.20194,22.89056&token='+AQI_KEY).then(res=>{
const data = [];
res.data.data.map(station=>{
if(station.aqi!=='-'){
data.push(JSON.stringify({ "type": "Feature", "properties": {"aqi": station.aqi},
"geometry":
{
"type": "Point", "coordinates": [ station.lon, station.lat ]
}
}))
}
})
map.addSource('AQI', {
'type': 'geojson',
'data':
{
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "aqi": "aqi" } },
"features": data.map(JSON.parse)
}
});
map.addLayer(
{
'id': 'AQI-heat',
'type': 'circle',
'source': 'AQI',
'paint': {
'circle-radius': {
'type': 'exponential',
'stops': [[0, 70], [500, 70]]
},
'circle-opacity': {
'type': 'exponential',
'stops': [[-99, 0.0], [-50, 1.0]]
},
'circle-color': [
'interpolate',
['linear'],
['get', 'aqi'],
0,
'#eee695',
50,
'#a5fc03',
100,
'#dbfc03',
200,
'#fc1c03'
],
'circle-blur': 1
}
}
);
})
})
}
Even tho I have set different colors for different values, I always just get black circles.
I want to click the bubble in Am chart and call the server through ajax call and manipulate some data in a view is it possible ?
I am loading my map through ajax call . below is the code . I tried it using eventlistener clickable object , but wont get success.
function StatisticsMap(item, categoryID, statusID) {
languageShortName = $("#languageShortName").val();
$("[relf-map-tab]").removeClass("active");
var url = "/" + languageShortName + "/saudiprojects/statistics/map-data?categoryID=" + categoryID + "&statusID=" + statusID;
dataPoints = [];
$.ajax({ type: "GET", url: url }).done(function (data) {
$(data).each(function (index, value) {
dataPoints.push({
longitude: value.Longitude,
latitude: value.Latitude,
type: 'circle',
color: '#E98C3E',
label: value.CountNo,
labelPosition: "middle",
labelColor: "#ffffff",
labelFontSize: 20,
fixedSize: false,
labelBackgroundAlpha: 1,
labelBackgroundColor: "#E98C3E",
height: 50 + (value.CountNo * 10),
width: 50 + (value.CountNo * 10),
centered: true,
title: value.Status
});
});
var map = AmCharts.makeChart("mapdiv", {
"type": "map",
"theme": "light",
"dataProvider": {
"map": "saudiArabiaHigh",
"images": dataPoints
}
});
$(item).addClass("active");
});
}
Here is my HTML
<div class="graph">
<div id="mapdiv" style="width:100%;height:100%;"></div>
</div>
You can use the clickMapObject listener on the map to capture what bubble was clicked. The image itself is stored in the mapObject property of the event:
"listeners": [{
"event": "clickMapObject",
"method": function(ev) {
alert('clicked on ' + ev.mapObject.title)
}
}]
Note that in order to make the image clickable, you have to set selectable to true in imagesSettings:
"imagesSettings": {
"selectable": true
}
Demo below:
var dataPoints = [{
longitude: 45,
latitude: 25,
type: 'circle',
color: '#E98C3E',
label: "1",
labelPosition: "middle",
labelColor: "#ffffff",
labelFontSize: 20,
fixedSize: false,
labelBackgroundAlpha: 1,
labelBackgroundColor: "#E98C3E",
height: 60,
width: 60,
centered: true,
title: "Example"
}];
var map = AmCharts.makeChart("mapdiv", {
"type": "map",
"theme": "light",
"dataProvider": {
"map": "saudiArabiaHigh",
"images": dataPoints
},
"imagesSettings": {
"selectable": true
},
"listeners": [{
"event": "clickMapObject",
"method": function(ev) {
alert('clicked on ' + ev.mapObject.title)
}
}]
});
#mapdiv {
width: 100%;
height: 500px;
}
<script src="https://www.amcharts.com/lib/3/ammap.js"></script>
<script src="https://www.amcharts.com/lib/3/maps/js/saudiArabiaHigh.js"></script>
<script src="https://www.amcharts.com/lib/3/plugins/export/export.min.js"></script>
<div id="mapdiv"></div>
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/
I am trying to use Mapbox/Turfjs to understand how many points are in a polygon. I have rendered my polygon and points in map.onload Is then possible to call Turf.js from another function AFTER the polygon and points have been rendered to the map?
Something like this...?
$(document).ready(function(){
mapboxgl.accessToken = 'eeeeeeeeee';
map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v9',
center: [ 32.62939453125,1.7355743631421197],
zoom: 6.5,
pitch: 40,
maxZoom: 17
});
map.on('load', function () {
//geofence data
map.addSource('fencedata', {
type: 'geojson',
data: 'data/fence.geojson'
});
map.addLayer({
id: 'fence',
type: 'fill',
"source": "fencedata",
'layout': {},
'paint': {
'fill-color': '#FF0000',
'fill-opacity': 0.3
}
});
//points data
map.addSource("pointdata", {
type: "geojson",
data: 'data/points.geojson',
cluster: true,
clusterRadius: 20
});
map.addLayer({
"id": "points",
"type": "circle",
"source": "pointdata",
"paint": {
'circle-color': 'rgba(255, 255, 46, 1.0)',
'circle-radius': 8
}
});
});
map.addControl(new mapboxgl.NavigationControl());
});
geofence();
function geofence(){
var ptsWithin = turf.within(points, fence);
}
You have your points as GeoJSON, and your polygon as GeoJSON - so, yes, you can use TurfJS to find out which points are within the polygon. It looks like the code you've proposed is correct. The fact you're using Mapbox is irrelevant to this particular task.
If you're experiencing a problem with this approach, indicate it in your question.
Try to add the geofence() function inside the map on-load function after adding those layers, By that way you can make sure that the geofence() function is called after the layers have been loaded
map.on('load', function () {
//geofence data
map.addSource('fencedata', {
type: 'geojson',
data: 'data/fence.geojson'
});
map.addLayer({
id: 'fence',
type: 'fill',
"source": "fencedata",
'layout': {},
'paint': {
'fill-color': '#FF0000',
'fill-opacity': 0.3
}
});
//points data
map.addSource("pointdata", {
type: "geojson",
data: 'data/points.geojson',
cluster: true,
clusterRadius: 20
});
map.addLayer({
"id": "points",
"type": "circle",
"source": "pointdata",
"paint": {
'circle-color': 'rgba(255, 255, 46, 1.0)',
'circle-radius': 8
}
});
geofence();
});
map.addControl(new mapboxgl.NavigationControl());
});
function geofence() {
var ptsWithin = turf.within(points, fence);
}
I am working on drawing a bubble map using highcharts and i have reached to a certain point where I am successfully plotting the bubble based on the state code (in/RJ) and value (1000).
http://jsfiddle.net/voidSO/h2f4ugz4/
$(function () {
var mapData = Highcharts.geojson(Highcharts.maps['countries/in/in-all']);
var data = [{
"z": 10038,
"code": "RJ"
}, {
"z": 100,
"code": "PB"
}];
$('#container').highcharts('Map', {
chart: {
borderWidth: 1
},
title: {
text: 'World population 2010 by country'
},
subtitle: {
text: 'Demo of Highcharts map with bubbles'
},
legend: {
enabled: false
},
mapNavigation: {
enabled: true,
buttonOptions: {
verticalAlign: 'bottom'
}
},
series: [{
name: 'Countries',
mapData: mapData,
color: '#E0E0E0',
enableMouseTracking: false
}, {
type: 'mapbubble',
mapData: mapData,
name: 'Population 2010',
data: data,
joinBy: ['postal-code', 'code'],
minSize: 4,
maxSize: '12%',
tooltip: {
pointFormat: '{point.code}: {point.z} thousands'
}
}]
});
});
But instead of using the state code I want to make the bubble using latitude and longitude, and i am not getting any hint how to do it.
For example the lat long of (RJ) Rajasthan (a state of india) using it's lat long 26.5727° N, 73.8390° E.
There are a couple of small steps you need to take. First of all, include Proj4s, which does the coordinate system conversion. This boils down to:
<script src="http://.../proj4.js"></script>
Secondly, you should swap your mapData to look like this:
var mapData = Highcharts.maps['countries/in/in-all'];
The reason for this is that wrapping it in Highcharts.geojson means Highmaps doesn't recognize it as a map from their own collection, and won't allow for easy lat/lng conversion.
The last thing is to place the bubbles using latitude and longitude, like this:
var data = [{
"z": 10038,
"lat": 26.5727,
"lon": 73.8390
// "code": "RJ"
}, {
"z": 100,
"code": "PB"
}];
See this updated JSFiddle demonstration, which uses lat/lng for Rajasthan (RJ).