synw / geojson Goto Github PK
View Code? Open in Web Editor NEWUtilities to work with geojson data in Dart
License: MIT License
Utilities to work with geojson data in Dart
License: MIT License
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"@id": "way/7976148"
},
"geometry": {
"type": "LineString",
"coordinates": [
[
21.7348336,
63.1817371
],
[
21.7340174,
63.1803407
],
[
21.7337985,
63.1798165
],
[
21.7336701,
63.1796189
],
[
21.7334107,
63.1794366
],
[
21.7330768,
63.1792931
],
[
21.7327166,
63.1791148
],
[
21.7324248,
63.1789103
],
[
21.7321882,
63.1786912
],
[
21.7320196,
63.1784645
],
[
21.7318318,
63.1781472
],
[
21.7318127,
63.1779711
],
[
21.7318692,
63.1776682
],
[
21.73197,
63.1772627
]
]
},
"id": "way/7976148"
},
{
"type": "Feature",
"properties": {
"@id": "way/18617780"
},
"geometry": {
"type": "LineString",
"coordinates": [
[
27.4328496,
68.446057
],
[
27.432846,
68.4458408
],
[
27.4327912,
68.4456453
],
[
27.4324782,
68.4450891
],
[
27.4322655,
68.4448676
],
[
27.4320019,
68.4446877
],
[
27.4218151,
68.4387766
],
[
27.4198287,
68.4376428
],
[
27.4178822,
68.436524
]
]
},
"id": "way/18617780"
},
]
}
I'd like to be able to query the two closest polygon edges to a single point. Any ideas?
Use case: tell the user which country border they are closest to. "You are 15km from the France/Germany border!"
I have found it very easy to filter a list of points using a geofence with geojson
. Works great!
Unfortunately, my use case is trying to tell a user which geofence they are in. That means one point and multiple geo polygons. Best I've found so far is to search each geo polygon individually for the point using the filtering feature and see which one returns first.
Is there a better way to figure out which geofence a specific point is located in? We're seeing about a 0.8 second calculation time on a 27" iMac and we'd obviously like to bring that way down.
Is there a recommended way to achieve this with performance in mind?
Hi, I need to get the country by its current coordinates (longitude, latitude). Is this possible using your library?
I created this from mapshaper and a 500m simplification and it won't parse with geojson. I did one with a 50m and the same workflow and it did work. Here is the one that doesn't work.
Hi, I'm creating an app for my college work and I decided to use your library to be able to read a geojson. But when it comes to reading geojson when it comes to a part that has a type that the library can't understand inside geometry which is the GeometryCollection
It's all right when the type is Polygon, which I'm using. Is there any way to ignore this exception to continue running the application or any implementation for it?
{
"type": "Feature",
"geometry": {
"geometries": [
{
"type": "Polygon",
"coordinates": [
[
[coordinates]
]
]
},
{
"type": "Polygon",
"coordinates": [
[
[morecoordinates]
]
]
},
{
"type": "Polygon",
"coordinates": [
[
[anycoordinate]
]
]
},
{
"type": "Polygon",
"coordinates": [
[
[coordinate]
]
]
}
],
"type": "GeometryCollection"
},
"properties": {
"name": "Inexistente ou Baixo"
}
}
My code:
final polygons = <Polygon>[];
Future<bool> processData() async {
final geojson = GeoJson();
geojson.processedPolygons.listen((GeoJsonPolygon multiPolygon) {
for (final polygon in multiPolygon.geoSeries) {
final geoSerie = GeoSerie(
type: GeoSerieType.polygon,
name: polygon.name,
geoPoints: <GeoPoint>[]);
geoSerie.geoPoints.addAll(polygon.geoPoints);
final color =
Color((math.Random().nextDouble() * 0xFFFFFF).toInt() << 0)
.withOpacity(0.3);
Polygon poly = Polygon(
polygonId: PolygonId('Nice one'),
fillColor: color,
points: toLatLng(geoSerie.geoPoints, ignoreErrors: true),
);
setState(() => polygons.add(poly));
}
});
geojson.endSignal.listen((bool _) => geojson.dispose());
// The data is from https://datahub.io/core/geo-countries
final data = await rootBundle.loadString('assets/coordinates/map.geojson');
final nameProperty = "Name";
await geojson.parse(data, nameProperty: nameProperty, verbose: true);
return true;
}
Hello,
I have tried this library, but it seems that a NoSuchMethodError
exception is thrown if the type
of the geometry object is set to Polygon
.
Looking at the code it seems that the only two supported types at this time are:
But the RFC spec states that there are seven:
"Point", "MultiPoint", "LineString",
"MultiLineString", "Polygon", "MultiPolygon", and
"GeometryCollection"
GeoJson used
{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[9.183021763511533,45.28718757700191],[9.184502342887754,45.28750460520285],[9.186154583640928,45.28422856168324],[9.184706190772886,45.28394925889815]]]}}]}
geojson validated with http://geojson.io
Please add a doc that state the current supported types and use an exception more meaningful (or do not return values for unsupported types, your choose)
Execution time of featuresFromGeoJson may be very long if json will be too big.
Try to split internal body of featuresFromGeoJson to little futures to avoid freezing of main Isolate and also return Furute from featuresFromGeoJson in general.
I haven't tried this plugin yet but I would love to have something like this on web. If it is already compatible please update the docs so I can give it a try.
Hello
I'm developing a proyect, and I need to represent on the map some lines that comes in GeoJson format.
In Android platform I can do this well, but in the Web this is not working.
I've implemented the featuresFromGeoJsonMainThread () funtion but returns empty values.
Please can you help me?
With the latest update I can't use Polygon from the poly package and neither Point from dart.math because geojson contains both of those Classes and thus confuses the namespace. This is my example script which worked fine before, but now don't. Could you make geojsons internal classes which are not part of the api private?
import 'dart:ffi';
import 'dart:io';
import 'package:geojson/geojson.dart';
import 'package:poly/poly.dart';
void main() async {
polygons();
}
bool polygonContains(Polygon poli, Point target){
return poli.contains(target.x, target.y);
}
void polygons() async {
final file = File("ecorregiones.geojson");
final geoSeries = await featuresFromGeoJsonFile(file);
Point target = Point(-59.797841999254999, -19.72303808501668);
List<Point> pointList = [];
List<List<Point>> pointSeries = [];
for (final geoSerie in geoSeries) {
//print("${geoSerie.name}: ${geoSerie.geoPoints.length} geopoints");
pointList = [];
for (final geoPoint in geoSerie.geoPoints){
double x = geoPoint.latitude;
double y = geoPoint.longitude;
Point p = Point(x, y);
pointList.add(p);
}
Polygon poli = Polygon(pointList);
bool contains = polygonContains(poli, target);
if(contains){
print('YES! $target is contained in ${geoSerie.name}.');
}
else print('nope!');
}
}
I can create a polygon with empty space. For create i use https://geoman.io/geojson-editor
created data
{ "type": "FeatureCollection", "features": [{ "id": "b30cc812-c8ba-41d0-98a7-76b3d7f5ec28", "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [ [ [-113.52572, 53.644638], [-113.593727, 53.623059], [-113.652804, 53.590059], [-113.661735, 53.5709], [-113.658987, 53.524799], [-113.661735, 53.482325], [-113.655552, 53.474561], [-113.612275, 53.45862], [-113.592354, 53.432856], [-113.562128, 53.427128], [-113.505112, 53.436128], [-113.450844, 53.435719], [-113.372533, 53.43531], [-113.342307, 53.448398], [-113.343889, 53.510918], [-113.343681, 53.570492], [-113.345259, 53.592097], [-113.356046, 53.612062], [-113.372038, 53.625095], [-113.397446, 53.637311], [-113.449626, 53.647487], [-113.52572, 53.644638] ], [ [-113.537341, 53.53893], [-113.534078, 53.539899], [-113.52884, 53.53944], [-113.523001, 53.538828], [-113.519567, 53.537502], [-113.515445, 53.536176], [-113.511495, 53.534135], [-113.509263, 53.534135], [-113.509949, 53.531585], [-113.501105, 53.530003], [-113.502565, 53.526125], [-113.506171, 53.524289], [-113.511495, 53.524085], [-113.513127, 53.525411], [-113.517506, 53.526636], [-113.520082, 53.528166], [-113.524547, 53.529799], [-113.529871, 53.530513], [-113.538372, 53.532809], [-113.539831, 53.535411], [-113.537341, 53.53893] ] ], "city_id": 1, "city_name": "Edmonton" }, "properties": { "name": "Edmonton", "shape": "Polygon", "category": "default" } }, { "id": "83af9f01-abb7-458d-9f18-fe8dac645a89", "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [ [ [-113.705187, 53.535819], [-113.859748, 53.521533], [-113.892034, 53.477831], [-113.8886, 53.431628], [-113.808228, 53.409123], [-113.701752, 53.434901], [-113.695569, 53.488454], [-113.705187, 53.535819] ], [ [-113.842575, 53.479081], [-113.835706, 53.516185], [-113.745717, 53.519446], [-113.74709, 53.474186], [-113.842575, 53.479081] ], [ [-113.846009, 53.455343], [-113.762889, 53.463501], [-113.758277, 53.435567], [-113.841877, 53.42784], [-113.846009, 53.455343] ] ], "city_id": 1, "city_name": "Edmonton" }, "properties": { "name": "Unnamed Layer", "shape": "Polygon", "category": "default" } }, { "id": "5c988165-fad6-4726-a90d-fc3ddd8cd0f9", "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [ [ [-113.321896, 53.466796], [-113.18176, 53.466796], [-113.18176, 53.54398], [-113.321896, 53.54398], [-113.321896, 53.466796] ] ], "city_id": 1, "city_name": "Edmonton" }, "properties": { "name": "Unnamed Layer", "shape": "Rectangle", "category": "default" } }, { "id": "b8952823-dbd0-425a-99ec-a63037bdf3e3", "type": "Feature", "geometry": { "type": "Point", "coordinates": [-113.293045, 53.581092], "city_id": 1, "city_name": "Edmonton" }, "properties": { "name": "Unnamed Layer", "shape": "Circle", "radius": 2909.9754362977806, "category": "default" } }] }
In web page I see
code i use in my app:
geo.processedPolygons.listen((GeoJsonPolygon multiPolygon) { geoJsonPolygons.add({ 'poligon': multiPolygon, 'city_id': cityId, }); for (final polygon in multiPolygon.geoSeries) { final geoSerie = GeoSerie( type: GeoSerieType.polygon, name: polygon.name, geoPoints: <GeoPoint>[]); geoSerie.geoPoints.addAll(polygon.geoPoints); Polygon poly = Polygon( consumeTapEvents: true, onTap: () { _onPolygonTapped(PolygonId( "${(math.Random().nextDouble() * 0xFFFFFF).toInt() << 0}")); }, strokeColor: Colors.orange, polygonId: PolygonId( "${(math.Random().nextDouble() * 0xFFFFFF).toInt() << 0}"), fillColor: Color.fromRGBO(75, 178, 68, 0.20), points: toLatLng(geoSerie.geoPoints, ignoreErrors: true), strokeWidth: 2, ); GeoJsonPolygon(geoSeries: [geoSerie]); polygons.add(poly); notifyListeners(); pointInsideCheck(); } }); for (var i = 0; i < polygonsData.length; i++) { if (polygonsData[i]['area_geojson'] != null) { var currentCityId = polygonsData[i]['city_id']; cityId = currentCityId; await geo.parse( json.encode(polygonsData[i]['area_geojson']), nameProperty: currentCityId.toString(), verbose: true, ); } }
How do I generate a new geojson from e.g. Google Map polygons?
To be compatible with the standard json serialisation/deserialisation feature of dart and the JsonSerializableGenerator, each geojson object (GeoJsonPoint, GeoJsonMultiPoint, GeoJsonLine...) of this lib should declare and expose a 'toJson()' and 'fromJson()' functions
i have multiple adresses from api with coordinates and i want to display their geojson data on the map like this
import 'dart:async';
import 'package:map_controller/map_controller.dart';
class Mapboxtest extends StatefulWidget {
final double lat;
final double lon;
final Object data;
Mapboxtest ({ Key key, @required this.lat,@required this.lon,this.data }): super(key: key);
@OverRide
_MapboxtestState createState() => new _MapboxtestState();
}
class _MapboxtestState extends State {
MapController mapController;
StatefulMapController statefulMapController;
StreamSubscription sub;
final lines = [];
Future parseAndDrawAssetsOnMap() async {
final geo = GeoJson();
geo.processedLines.listen((GeoJsonLine line) {
setState(() => lines.add(Polyline(
borderColor: Colors.red,
strokeWidth: 4.0, color: primarycolor, points: line.geoSerie.toLatLng())));
});
geo.endSignal.listen((_) => geo.dispose());
final data = widget.data;
await geo.parse(data, verbose: true);
}
@OverRide
void initState() {
mapController = MapController();
statefulMapController = StatefulMapController(mapController: mapController);
statefulMapController.onReady.then((_) => parseAndDrawAssetsOnMap());
sub = statefulMapController.changeFeed.listen((change) => setState(() {}));
super.initState();
}
@OverRide
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
FlutterMap(
options:
MapOptions(
center: LatLng( widget.lon , widget.lat), zoom: 15,
minZoom: 3.0,
maxZoom: 20.0,
interactive: true, ),
layers: [
TileLayerOptions(
urlTemplate:
'https://api.mapbox.com/styles/v1/adnanefouham/cka1mwzas5g9k1iou3qn3odle/tiles/256/{z}/{x}/{y}@2x?access_token=TOKEN_KEY', additionalOptions: {
'accessToken':
'TOKEN_KEY',
'id': 'mapbox.mapbox-stretts-v8',
}),
MarkerLayerOptions(markers: [
Marker(
width: 45.0,
height: 45.0,
point: LatLng(widget.lon , widget.lat),
builder: (context) => Container(
child: IconButton(
icon: Icon(Icons.location_on),
color: primarycolor,
iconSize: 45.0,
onPressed: () {
parseAndDrawAssetsOnMap();
print('Marker tapped');
},
),
))
]),
PolylineLayerOptions(
polylines: statefulMapController.lines,
),
]),
],
));
}
}
Some classes in this library have nullable type member variables, and it is not apparent why.
For example...
/// A line
class GeoJsonLine {
/// Default constructor
GeoJsonLine({this.geoSerie, this.name});
/// The geometry data
GeoSerie? geoSerie;
/// The name of the line
String? name;
/// Serialize to a geojson feature string
String? serializeFeature(Map<String, dynamic>? properties) =>
geoSerie?.toGeoJsonFeatureString(properties);
}
Why is GeoSerie nullable? Does a GeoJsonLine make sense without a GeoSerie? Under what circumstances would this be null? Should this even be null?
If this member is never null, it should be typed as such. Libraries should try to never expose nullable types unless there is very good reason.
class GeoJsonFeatureCollection {
...
String serialize() {
final buffer = StringBuffer()
..write('{"type": "FeatureCollection", "name": "$name",')
..write('"features": [');
If name is null (which is common) then the output json is polluted with meaningless "name": "null"
If we try to deserialize it again now we have name = `null' which is not good.
I am trying to load and parse simple geojson:
Future<void> parse() async {
final geojson = GeoJson();
String json="{\n" +
" \"type\": \"Point\",\n" +
" \"coordinates\": [\n" +
" -105.01621,\n" +
" 39.57422\n" +
" ]\n" +
"}";
await geojson.parse(json);
}
and I am getting exception:
NoSuchMethodError: The getter 'iterator' was called on null.
Receiver: null
Tried calling: iterator
JSON is valid, what am I doing wrong?
Hello, I am using flutter_map, wanting to upgrade from v4 > v6, but I am getting this error:
Because geojson >=1.0.0 depends on geopoint ^1.0.0 which depends on latlong2 ^0.8.0, geojson >=1.0.0 requires latlong2 ^0.8.0. So, because <project> depends on both geojson ^1.0.0 and latlong2 ^0.9.0, version solving failed.
Can the latlong2 package can be upgraded? The repository looks like it is archived. Not sure what that means in terms of further development.
Thank you.
Does geojson package create new geojson file from points, or just parsing geojson files?
I am new to GeoJson, but I notice that the GeoJsonFeature GeoJsonMultiLine when serialized the value of the Type is Line
, however, when parsing a geojson collection that includes as feature with Type Line
an exception is throw.
The serialization code is in src/models.dart at line 241:
/// Serialize to a geojson feature string
String serializeFeature(Map<String, dynamic>? properties) {
final geoSeries = <GeoSerie?>[];
for (final line in lines) {
geoSeries.add(line.geoSerie);
}
return _buildGeoJsonFeature(
geoSeries, "Line", properties ?? <String, dynamic>{"name": name});
}
As you can notice, the type value is set to Line
.
Looking at the code, in the file src/geojson.dart at line 498:
case "MultiLineString":
if (query != null) {
if (query.geometryType != null) {
if (query.geometryType != GeoJsonFeatureType.multiline) {
continue;
}
}
}
feature = _processGeometry(geometry, properties, nameProperty);
break;
A case for MultiLineString is evaluated but there is no case for Line
type.
So, the questions are:
Thanks in advance for your attention to this issue!!
all geometry classes (GeojsonPoint, GeojsonLine, GeojsonMultiLine, GeojsonPolygon, ...) should extend the same GeojsonGeometry abstract class to respect the geojson hierarchy and allow to point to a generic geojson geometry in our code if needed (for example if I want to define a class attribute as a geojson geometry without specifying the type because it is variable or unknown yet, I can't with the current lib implementation)
When dealing with a large geoJson having a way to fetch each feature after it's parsing is good, but when you deal on a very little geoJson (with only one feature, for instance) it's an overkill.
Can you add a way to parse the geoJson synchronously?
String serialize() {
assert(type != null, "The feature type can not be null for serialization");
String featStr;
switch (type) {
case GeoJsonFeatureType.point:
final geom = geometry as GeoJsonPoint;
featStr = geom.serializeFeature();
break;
case GeoJsonFeatureType.multipoint:
final geom = geometry as GeoJsonMultiPoint;
featStr = geom.serializeFeature();
break;
case GeoJsonFeatureType.line:
final geom = geometry as GeoJsonLine;
featStr = geom.serializeFeature();
break;
case GeoJsonFeatureType.multiline:
final geom = geometry as GeoJsonMultiLine;
featStr = geom.serializeFeature(properties);
break;
case GeoJsonFeatureType.polygon:
final geom = geometry as GeoJsonPolygon;
featStr = geom.serializeFeature(properties);
break;
case GeoJsonFeatureType.multipolygon:
final geom = geometry as GeoJsonMultiPolygon;
featStr = geom.serializeFeature();
break;
}
return featStr;
}
You can see that only multiline
and polygon
make use of properties.
I do need them at least for point
Whenever you call this on the web, while the code runs the features added to the sink don't appear to trigger the the listen.
I added a simple sample project for an example: https://github.com/ATeal/web_geojson
Additionally if you do a little hacking on the example project from the map_controller package and enable their implementation of the geojson read on web (they actually have it disabled on web, I'm assuming because it's not functioning) then you can see it not working there as well: https://github.com/synw/map_controller/tree/master/example
Feel free to let me know if I'm doing something wrong, or if I can help in anyway!
Could you please migrate to Dart's new null safety? https://dart.dev/null-safety/migration-guide
The exceptions have a generic name, I would like to request that we get them a more 'namespaced' name, such as GeoJsonFeatureNotSupported
instead of FeatureNotSupported
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.