Flutter: Mapbox Cluster and click event on unclustered point - flutter

I use this code to have clusters:
for (int index = 0; index < punti_di_interesse.length; index++) {
var point = {
"type": "Feature",
"id": index,
"properties": {
"id": index,
"name": punti_di_interesse[index].name,
'descrizione': punti_di_interesse[index].descrizione,
},
"geometry": {
"type": "Point",
"coordinates": [
punti_di_interesse[index].longitude,
punti_di_interesse[index].latitude,
0.0
]
}
};
allSymbolGEOJSON.add(point);
}
var allPoints = {
"type": "FeatureCollection",
"crs": {
"type": "name",
"properties": {"name": "urn:ogc:def:crs:OGC:1.3:CRS84"}
},
"features": allSymbolGEOJSON,
};
var source = await controller.addSource(
"earthquakes",
GeojsonSourceProperties(
data: allPoints,
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50,
),
);
await controller.addLayer(
"earthquakes",
"clusters",
CircleLayerProperties(circleColor: [
Expressions.step,
[Expressions.get, 'point_count'],
'#51bbd6',
100,
'#f1f075',
750,
'#f28cb1'
], circleRadius: [
Expressions.step,
[Expressions.get, 'point_count'],
20,
100,
30,
750,
40
]),
);
await controller.addLayer(
"earthquakes",
"cluster-count",
SymbolLayerProperties(
textField: [Expressions.get, 'point_count_abbreviated'],
textSize: 12,
));
await controller.addSymbolLayer(
"earthquakes",
"unclustered-point",
SymbolLayerProperties(
textField: [Expressions.get, "name"],
textHaloWidth: 1,
textSize: 12.5,
textHaloColor: '#ffffff',
textOffset: [
Expressions.literal,
[0, 2]
],
iconImage: "assets/icona_stato-rosso.png",
iconSize: 2,
iconAllowOverlap: true,
textAllowOverlap: true,
textColor: '#000000',
textHaloBlur: 1,
),
filter: [
'!',
['has', 'point_count']
],
enableInteraction: true,
);
Under my custom iconImage I see a black dot, how can this be removed?
In addition, I need that when the iconImage is clicked, a modal opens with information that is contained in the data structure in "properties"
I have tried using controller.onFeatureTapped.add(onFeatureTap);
but in the onFeatureTap function how do I access properties from featureId, point or latLng?
Am I doing something wrong?

For anyone stumbling across this problem, i figured out the following:
the CircleLayerProperties set a standard #000000 color value for circles. This together with the fact that you recolor everything with a point_count (which singular symbols do not have) leads to the CircleLayer drawing a black circle.
To fix this, use expressions to set the circleOpacity to 0.0 for all the unclustered symbols like so:
circleOpacity: [
"case",
["has", "point_count"],
1.0,
[
"!",
["has", "point_count"]
],
0.0,
1.0
]
Edit:
To your second point, i can shed some light there too:
in general, your are on the right path, but let me put together a more complete example for everyone:
First, define your GeoJson with an id:
var point = {
"type": "Feature",
"id": index,
"properties": {
...
},
"geometry": {
...
}
};
Then, add a listener to your MapController:
mapController.onFeatureTapped.add((id, point, coordinates) {
print(id);
}
The print(id) in the above handler will then print the id you defined in your GeoJson (or the id of a cluster, if applicable).
Hope that helps someone!

Related

How filter features by status

I want to show in my map in a cluster layer filtering by if is opened or not. How can do it? Should I create two layers?
One with filter: filter["has", "opened"] and other with filter: filter["!", ["has", "opened"]]?
export const clusterLayerOpened = {
id: "clusters",
type: "circle",
source: "earthquakes",
filter: ["has", "opened"],
paint: {
"circle-color": [ "step", ["get", "opened"], "#51bbd6",100,"#f1f075",750,"#f28cb1", ],
"circle-radius": ["step", ["get", "opened"], 20, 100, 30, 750, 40],
},
};
export const clusterLayerNoOpened = {
id: "clusters",
type: "circle",
source: "earthquakes",
filter: ["!", ["has", "opened"]],
paint: {
"circle-color": [ "step", ["get", "opened"], "#51bbd6",100,"#f1f075",750,"#f28cb1", ],
"circle-radius": ["step", ["get", "opened"], 20, 100, 30, 750, 40],
},
};
This is my geojson:
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"id": "ak16994521",
"mag": 2.3,
"time": 1507425650893,
"felt": null,
"tsunami": 0,
"opened": true
},
"geometry": {
"type": "Point",
"coordinates": [-151.5129, 63.1016, 0.0]
}
},
{
"type": "Feature",
"properties": {
"id": "ak16994519",
"mag": 1.7,
"time": 1507425289659,
"felt": null,
"tsunami": 0,
"opened": false
},
"geometry": {
"type": "Point",
"coordinates": [-150.4048, 63.1224, 105.5]
}
}
]
}
It's not necessary to create two separate layers to filter by whether the a point has been opened or not. Here is some code showing how to add a layer which displays all points with the property "opened": true, and hides all points with "opened": false:
map.addLayer({
'id': 'opened',
'type': 'circle',
'source': 'points',
'paint': {
'circle-radius': 10,
'circle-opacity': ["match", ["to-string", ["get", "opened"]], 'true', 1 , 'false', 0, 0]
}
});
To instead show all points with the property "opened": false, you can switch the 'circle-opacity' expression to read:
["match", ["to-string", ["get", "opened"]], 'true', 0 , 'false', 1, 0]
This code makes use of a few Mapbox expressions. I've linked the documentation to each relevant expression here: match, to-string, and get.
Here is a JSFiddle where two layers are added to the map: https://jsfiddle.net/hpkzrm4n/. The points with "opened": true are shown in red and the points with "opened": false are shown in blue. Note that you will need to add your own Mapbox access token where indicated in order to view the results. Here is a screenshot, as a preview:

How to set Mapbox heatmap color by data value?

I would like to display a heatmap of Bluetooth scans such that scans with strong signals appear green and scans with weak signal strength appear red. I have tried playing with all of the Mapbox heatmap properties (weight, intensity, radius, color, opacity) and have not been able to achieve this effect. Is there any advice on how to do this?
GeoJSON data format ("rssi" is the signal strength)
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-79.92068447220412,
43.259061411756505
]
},
"properties": {
"name": "heatmap",
"rssi": "55"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-79.92068446786702,
43.25906141184957
]
},
"properties": {
"name": "heatmap",
"rssi": "59"
}
},
...
]
}
Heatmap layer so far
map.addLayer({
id: 'heatmap_heatmap_layer_id',
type: 'heatmap',
source: 'heatmap_source_id',
maxzoom: 24,
paint: {
'heatmap-weight': {
property: 'rssi',
type: 'exponential',
stops: [
[0, 1],
[120, 10]
]
},
'heatmap-intensity': {
stops: [
[currentZoom, 1],
[24, 2]
]
},
'heatmap-color': [
'interpolate',
['linear'],
['heatmap-density'],
0, 'rgba(240,29,29,0)',
0.2, 'rgba(198,0,12,1)',
0.4, 'rgba(32,43,222,1)',
0.7, 'rgba(1,1,1,1)',
1.0, 'rgba(200,144,153,1)'
],
'heatmap-radius': {
stops: [
[currentZoom, 20],
[middleZoom, 30]
]
},
'heatmap-opacity': {
default: 1,
stops: [
[currentZoom, 1],
[24, 1]
]
},
}
});
This one's a bit tricky, as heatmaps automatically blend and add points in close proximity with one another. This means that a single point of strong signal will appear the same color, as many points of weak signal close together.
You may be better off visualizing the points as discrete circles, colored by RSSI.

Echarts 4 graph plot: specify symbol per category

I am trying to create a graph plot in Echarts 4, where each node belongs to one of two categories: https://codepen.io/autarkie/pen/LqqZjM:
var nodes = [{
"id": 1,
"category": 1
}, {
"id": 2,
"category": 0
}, {
"id": 3,
"category": 1
}, {
"id": 4,
"category": 0
}];
var links = [{
"source": "3",
"target": "1"
}, {
"source": "3",
"target": "2"
}, {
"source": "1",
"target": "2"
}, {
"source": "2",
"target": "4"
}];
var myChart = echarts.init(document.getElementById('chart'));
var option = {
backgroundColor: new echarts.graphic.RadialGradient(0.4, 0.4, 0.7, [{
offset: 0,
color: '#162436'
}, {
offset: 1,
color: '#000'
}]),
legend: {
data: ["Type 1", "Type 2"],
textStyle: {
color: '#fff'
},
icon: 'circle',
type: 'scroll',
orient: 'vertical',
left: 10,
top: 20,
bottom: 20,
itemWidth: 10,
itemHeight: 10
},
animationDurationUpdate: 300,
animationEasingUpdate: 'quinticInOut',
series: [{
type: 'graph',
layout: 'force',
// symbol: 'rect',
//symbolSize: 10,
lineStyle: {
normal: {
curveness: 0.1
}
},
roam: true,
focusNodeAdjacency: true,
legendHoverLink: true,
draggable: true,
force: {
repulsion: 30,
gravity: 0.03,
edgeLength: 50,
layoutAnimation: true
},
data: nodes,
links: links,
categories: [{
name: 'Type 1',
symbol: 'diamond', // !!! DOES NOT WORK !!!
symbolSize: 30, // !!! DOES NOT WORK !!!
itemStyle: {
color: '#79d2a6'
}
},
{
name: 'Type 2',
symbol: "rect", // DOES NOT WORK
symbolSize: 20, // DOES NOT WORK
itemStyle: {
color: '#ff9900'
}
}
],
}]
};
myChart.setOption(option);
Each category should have its own symbol. I know it is possible to specify the symbol for each node separately, like so:
var node_shaped = [{
"id": 1,
"symbol": "rect",
"category": 1
}]
but it this is quite inelegant. Echarts documentation (https://ecomfe.github.io/echarts-doc/public/en/option.html#series-graph.categories.symbol) specifies the option to include a symbol per category, like in the code above. However, that option has no effect whatsoever on the node shapes. Instead, the default circle shape is used. It is possible to change category color using a similar category-wide option, so I am at loss as to why the shape specification doesn't work. Thanks for taking a look.

Color only the edge of a circle mapbox gl js

I want to show the outline of a circle on an interactive map (no fill) however, the paint options in mapbox-gl-js seem limited to fill only.
https://www.mapbox.com/mapbox-gl-style-spec/#layers-circle
var styles = [{
"id": 'points',
"interactive": true,
"type": "circle",
"source": "geojson",
"paint": {
"circle-radius": 5,
"circle-color": "#000
},
"filter": ["in", "$type", "Point"]
}, {
"type": "line",
"source": "geojson",
"layout": {
"line-cap": "round",
"line-join": "round"
},
"paint": {
"line-color": "#000",
"line-width": 2.5
},
"filter": ["in", "$type", "LineString"]
}];
Am i missing something or is this just not possible?
This is now possible, with circle-opacity.
E.g.:
"paint": {
"circle-opacity": 0,
"circle-stroke-width": 1,
"circle-stroke-color": #000
}
Not currently possible. Current top workaround appears to be layering two circles of slightly different sizes.
https://github.com/mapbox/mapbox-gl-js/issues/1713
https://github.com/mapbox/mapbox-gl-style-spec/issues/379
I'm having trouble running custom color 'match' and having opacity controls running simultaneously.
I can get both working, but not at the same time. See code below.
var coorAddresses = [ [ -75.7040473, 45.418067,"Medium" ], [-75.7040473, 45.418067, "Medium"], [-79.32930440000001, 43.7730495, "Unknown"]]
$.getJSON(coodAddresses, function(data) {
for(var itemIndex in data) {
// push new feature to the collection
featureCollection.push({
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [data[itemIndex][0], data[itemIndex][1]]
},
"properties": {
"size_by": data[itemIndex][2],
"color_by": data[itemIndex][2]
},
});
}
});
map.on('load', function () {
map.addLayer({
"id": "points",
"type": "circle",
"source": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": featureCollection
}
},
"paint": {
"circle-color": [
'match',
['get', 'size_by'],
'Easy',
'#e4f400',
'Medium',
'#f48a00',
'Unknown',
'#6af400',
/* other */ '#00e4f4'
],
"circle-radius": [
'match',
['get', 'size_by'],
'Easy',
4,
'Medium',
7,
'Unknown',
2,
/* other */ 1000
],
// "circle-opacity": 0, // color does not show if i uncomment these lines
// "circle-stroke-width": 1, // do not get desired 'hollow' circle unless these lines run
}});
Trying to troubleshoot.

I am building a bubble chart in AM-Charts but facing issues in plotting String values on X-axis

I am new to AM-charts, I am building a bubble chart in AM-charts http://www.amcharts.com/demos/bubble-chart/.
I want to plot following data in bubble chart where name should be appear on X-axis and job should be on Y-axis.
[{"name":"abc","jobs":15, "value":63500},{{"name":"pqr","jobs":15, "value":33000}}]
My bubble chart configuration is as follows-
{
"type": "xy",
"theme": "light",
"titles": [
{
"text": title,
"size": 16
}
],
"balloon": {
"fixedPosition": true,
},
"dataProvider": [{"name":"abc","job":15, "value":63500},{{"name":"pqr","job":15, "value":33000}}],
"valueAxes": [
{
"position": "bottom",
"axisAlpha": 0
},
{
"minMaxMultiplier": 1.2,
"axisAlpha": 0,
"position": "left"
}
],
"startDuration": 1.5,
"graphs": [
{
"balloonText": "Name: <b>[[name]]</b> Jobs: <b>[[job]]</b><br>value: <b>[[value]]</b>",
"bullet": "round",
"bulletBorderAlpha": 0.2,
"bulletAlpha": 0.8,
"lineAlpha": 0,
"fillAlphas": 0,
"valueField": "value",
"xField": "name",
"yField": "job",
"maxBulletSize": 50,
"minBulletSize": 20
}
],
"marginLeft": 46,
"marginBottom": 35,
"export": {
"enabled": true
},
"chartScrollbar": {
"offset": 15,
"scrollbarHeight": 5
}
}
I am not able to see bubble chart with this configuration. No error or warning in console.
Can anyone please suggest me some solution to fix this issue?
Thanks in advance.