How to compute a GeoJson geometry area in dart / flutter - flutter

I'm building a flutter mobile app and I need to compute an area of some GeoJson geometries.
Say we have a GeoJson-like object:
final geo = {
"type": "Polygon",
"coordinates": [[
[-122.085, 37.423],
[-122.083, 37.423],
[-122.083, 37.421],
[-122.085, 37.421],
[-122.085, 37.423]
]]
};
Assuming the projection is EPSG:4326, how do we get the actual area of the geometry using flutter or dart?
Tried to use dart-simple-features, but this is no longer maintained and requires SDK < 2.0.0.
Another option that came to my mind is to use some JavaScript library in combination with flutter_webview_plugin, but oh my... That seems like an overkill!
Also there is a possibility to use platform-specific code, but for the sake of development experience: let's avoid testing on multiple platforms if possible...
Any ideas? Or recommendations?

Okay, no reply for almost a week... Created my first dart package:
https://pub.dev/packages/area
Simple to use:
import 'package:area/area.dart';
main() {
const world = {
'type': 'Polygon',
'coordinates': [
[
[-180, -90],
[-180, 90],
[180, 90],
[180, -90],
[-180, -90]
]
]
};
print("The world area is: ${area(world)} m²");
}
Feel free to use, hate or love ;)

You can use geojson_vi:
const world = {
'type': 'Polygon',
'coordinates': [
[
[-180, -90],
[-180, 90],
[180, 90],
[180, -90],
[-180, -90]
]
]
};
final geoJSONPolygon = GeoJSONPolygon.fromMap(world);
print(geoJSONPolygon.area);

Related

Change state of mapbox map upon loading

I'm working on a web app with Mapbox and I want to change the state of a created polygon to be selected without clicking upon loading.
I appreciate any help!
draw.add({
'id': 'polygon',
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'Polygon',
'coordinates': [coordinates],
}
});
Current state
Desired state
You can use this to enter direct selection mode:
draw.changeMode('direct_select', { featureId: myFeatureId })
See the API docs for more info. https://github.com/mapbox/mapbox-gl-draw/blob/main/docs/API.md

How to write a Mapbox paint expression that accounts for zoom, feature-state, and data-driven styling?

I have a layer that renders point features in a geojson source as circles. Here's an example of one of the features:
{
type: 'Feature',
properties: {
color: 'red',
red: true,
green: false
},
geometry: {
type: 'Point',
coordinates: [-77.038659, 38.931567]
}
};
I want circle-opacity to be a product of 3 factors (some properties on the features, map zoom, and a boolean in feature-state for whether that feature should be hidden). I can't figure out a way to write an expression that accounts for all three. Restrictions around zoom rules seem to be the issue.
Here's the logic I am trying to write:
if (feature-state.hidden) {
opacity = 0;
} else if (properties.red) {
opacity = 1;
} else if (properties.green and zoom >= 10) {
opacity = 1;
} else if (zoom >= 15) {
opacity = 1;
} else {
opacity = 0;
}
I tried writing an opacity expression like this:
'circle-opacity': [
'case',
['to-boolean', ['feature-state', 'hidden']], 0,
['to-boolean', ['get', 'red']], 1,
['to-boolean', ['get', 'green']], ['case', ['>=', ['zoom'], 10], 1, 0], // I could also write a permutation of this using an ['all'] rule
['>=', ['zoom'], 15], 1,
0,
],
That gets rejected with this message: "Error: layers.places.paint.circle-opacity: "zoom" expression may only be used as input to a top-level "step" or "interpolate" expression."
So then I tried something like this:
'circle-opacity': [
'step',
['zoom'],
0,
[
'case',
['to-boolean', ['get', 'red'], false], 1,
['to-boolean', ['get', 'green'], false], 10,
15
],
1
]
That gets rejected with this message: "Error: layers.places.paint.circle-opacity[3]: Input/output pairs for "step" expressions must be defined using literal numeric values (not computed expressions) for the input values."
As you can see, I hadn't even gotten around to adding the feature-state checks yet.
Here's a JSFiddle to play with: https://jsfiddle.net/rognstad/px4c8tbe/17/
I think I can make it work by breaking each color out into its own layer with a minZoom property and then only using an opacity expression for feature-state, but that feels really clunky and will result in worse performance.
It seems like there has to be a better way. Do you have any better suggestions for how to achieve this? Thanks!
You're really close. You're getting this error:
Error: layers.places.paint.circle-opacity[3]: Input/output pairs for "step" expressions must be defined using literal numeric values (not computed expressions) for the input values.
Because you've got the order of arguments in your ['step'] expression slightly wrong. It needs to go:
['step', ['zoom'], <value at zoom 0>, <X>, <value at zoom X>, <Y>, <value at zoom Y>
So you don't want that first 0 there.
If we refactor your pseudo code a bit you should be able to get there:
step
zoom
// zoom 0 to 10
if (!feature-state.hidden && properties.red) {
1
} else {
0
}
10 // zoom level 10+
if (!feature-state.hidden && (properties.red || properties.green) {
1
} else {
0
}
15 // zoom level 15+
if (!feature-state.hidden) {
1
} else {
0
}
The expression code will look something like this. You'll have to add appropriate type conversions probably. (I haven't tested it).
['step', ['zoom'],
['case', ['all', ['!', ['feature-state', 'hidden']], ['get', 'red'], 1, 0],
10,
['case', ['all', ['!', ['feature-state', 'hidden']], ['any', ['get', 'red'], ['get', 'green']], 1, 0],
15,
['case', [['!', ['feature-state', 'hidden']], 1, 0]],

Mapbox GL JS: Some coordinates are not rendered

I'm processing a multi-polygon geojson, but some polygons are not rendered with mapbox-gl-js, generating some gaps. The use of mapbox-js features renders correctly.
This problem only occurs with the mapbox-gl-js API.
This problem also occurs in Mapbox Studio when rederizing a tileset in a style even though the polygon exists in the dataset.
That's the link to the geojson:
geojson
This is the code snippet where I add the layer, with mapbox-gl-js:
map.addSource( < id > , {
type: 'vector',
url: < url >
});
map.addLayer({
"id": < id > ,
"type": "fill",
"source": < id > ,
"source-layer": < id > ,
"layout": {},
"paint": {
"fill-color": ["interpolate", ["linear"],
["get", "title"], 0.00, "red", 0.30, "#8aac75", 0.60, "#00e6e6", 0.90, "#00c0cc", 1.20, "#00a5cc", 1.50, "#007fcc", 1.80, "#000066", 2.10, "#0018cc", 2.40, "#0000ba", 2.70, "#000099", 3.00, "#000076", 3.30, "#000066", 3.60, "purple"
]
}
}, < layerId > );
This is the code snippet where I add the layer, with mapbox-js:
var featureLayer = L.mapbox.featureLayer().addTo(tmap);
featureLayer.loadURL('/geojson');
Would anyone know what may be generating this error?

Not able to implement AmCharts Gauge type in SAPUI5

I am trying to add a Gauge chart in my UI5 app. I am successfully able to implement the chart with "Series" type. So I am able to load the libs from manifest.json file. But When I am trying to implement the gauge chart. I am getting below mentioned error.
amcharts.js? eval:174 Uncaught TypeError: d.AmAngularGauge is not a constructor
I am using this code :
var gaugeChart = AmCharts.makeChart( "chartdiv", {
"type": "gauge",
"theme": "light",
"axes": [ {
"axisThickness": 1,
"axisAlpha": 0.2,
"tickAlpha": 0.2,
"valueInterval": 20,
"bands": [ {
"color": "#84b761",
"endValue": 90,
"startValue": 0
}, {
"color": "#fdd400",
"endValue": 130,
"startValue": 90
}, {
"color": "#cc4748",
"endValue": 220,
"innerRadius": "95%",
"startValue": 130
} ],
"bottomText": "0 km/h",
"bottomTextYOffset": -20,
"endValue": 220
} ],
"arrows": [ {} ],
"export": {
"enabled": true
}
} );
In my View , I am rendering the map in VBox.
Regards,
MS
You're not implementing a series chart in your code, you're implementing a gauge chart. The error is telling you that you didn't include the gauge.js file. amcharts.js isn't enough as it's the base library and serial.js does not contain the gauge chart classes. Make sure the following is included for your gauge chart:
<script type="text/javascript" src="https://www.amcharts.com/lib/3/amcharts.js"></script>
<script type="text/javascript" src="https://www.amcharts.com/lib/3/gauge.js"></script>
<!-- if you need other charts like pie, radar, and series include those js files -->
<!-- plugins such as export and dataloader also come after the chart includes -->
You can see what chart libraries need to be included for each type by looking at AmCharts' demos page.

Empty results from analytics reporting api when requesting audience dimensions

I'm trying to get some GA metrics broken down over age bracket or gender, but the results come up empty.
If I try to break down sessions over browsers, I get results:
{"reportRequests": [
{"dimensions": [{"name": "ga:browser"}],
"metrics": [{"expression": "ga:sessions"}],
"viewId": "111459828"}]}
returns what I expect: a huge breakdown of the number of sessions per browser. When I request the age bracket dimensions, though:
{"reportRequests": [
{"dimensions": [{"name": "ga:userAgeBracket"}],
"metrics": [{"expression": "ga:sessions"}],
"viewId": "111459828"}]}
I get an empty result:
{'reports': [
{'columnHeader': {'dimensions': ['ga:userAgeBracket'],
'metricHeader': {'metricHeaderEntries': [
{'name': 'ga:sessions',
'type': 'INTEGER'}]}},
'data': {'totals': [{'values': ['0']}]}}]}
The same happens for ga:userGender and whether I pass includeEmptyRows or not. My OAuth scope is https://www.googleapis.com/auth/analytics, as I think it's supposed to be and i'm using v4 of the API. What am I doing wrong?