简体   繁体   中英

GeoJSON onClickListener not working on Polygons

UPDATE:

The original question is below the line, but I have looked into this further and have some additional information to add.

Firstly, the reason the error occurs is because the GeoJSON file contains polygons which are classed as "MultiPolygons". They are basically multiple polygons defined together. (imagine you trying to represent a country like Greece as one unit in the file, the country itself is made up of many islands and therefore requires "MultiPolygons")

I have tried the code below with a GeoJSON file I made with a simple polygon defined as a "Polygon" (not "Multipolygon") and the code works as it should.

The question now becomes...is there a way to use the onclick method on MultiPolygons and if so how would this be implemented.

I will keep testing and post here should I have any luck, otherwise any input would be appreciated.


I have been looking into adding a geoJSON file to google maps and interacting with it in an android application.

Google has a maps utility library to help achieve this:

https://developers.google.com/maps/documentation/android-api/utility/geojson

I have managed to successfully import the geojson information (in this case MultiPolygons with properties), and can extract feature properties etc from within the java program.

The next step I wanted to take was to be able to click on a Polygon and extract the same property information or add a new polygonstyle to the clicked "feature".

I have found code in Google's "GeoJSONDemoActivity" which is supposed to display a toast with the property on-click. Except it throws an error instead.

I should point out I am very new to coding and I may be missing something obvious, but I really can't see it.

Here is the code that is the problem:

all_rough.setOnFeatureClickListener(new GeoJsonLayer.GeoJsonOnFeatureClickListener() {
            @Override
            public void onFeatureClick(GeoJsonFeature feature) {
                Toast.makeText(EuroMap.this,
                        "Feature clicked: " + feature.getProperty("geounit"),
                        Toast.LENGTH_SHORT).show();
            }
        });

I should also point out that if you remove:

+ feature.getProperty("geounit")

the code will work and on click you will get a toast with "Feature clicked: "

Here is the error:

09-11 11:20:48.759 2814-2814/com.thetestspecimen.worldmap E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.thetestspecimen.worldmap, PID: 2814
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.google.maps.android.geojson.GeoJsonFeature.getProperty(java.lang.String)' on a null object reference
at com.thetestspecimen.worldmap.EuroMap$1.onFeatureClick(EuroMap.java:135)
at com.google.maps.android.geojson.GeoJsonLayer$1.onPolygonClick(GeoJsonLayer.java:97)
at com.google.android.gms.maps.GoogleMap$14.zza(Unknown Source)
at com.google.android.gms.maps.internal.zzz$zza.onTransact(Unknown Source)
at android.os.Binder.transact(Binder.java:387)
at yr.a(:com.google.android.gms.DynamiteModulesB:82)
at maps.ad.Z.t(Unknown Source)
at maps.D.m.a(Unknown Source)
at maps.D.l.a(Unknown Source)
at maps.V.u.d(Unknown Source)
at maps.V.P.onSingleTapConfirmed(Unknown Source)
at maps.z.e$b.onSingleTapConfirmed(Unknown Source)
at maps.z.c$a.handleMessage(Unknown Source)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

I can also confirm that the feature "geounit" exists in the geojson and the property (in this case) is "England". I have tested this by using the following code and it works (the code changes the polygon colour, and outputs "Message: England" in the log):

for (GeoJsonFeature feature : all_rough.getFeatures()) {
           if (feature.getProperty("geounit").equals("England")) {
                feature.setPolygonStyle(englandStyle);
                String country = feature.getProperty("geounit");
                Log.d("myTag", "Message: " + country);

            } else {
                 Log.d("myTag", "Message: Failure");
            }
        }

Just to give you all the information you may need I have provided below the GeoJSON file and the full activity:

GeoJSON

{
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name":    "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "scalerank": 1, "featurecla": "Admin-0  map unit", "labelrank": 5.0, "sovereignt": "United Kingdom", "sov_a3": "GB1", "adm0_dif": 1.0, "level": 3.0, "type": "Geo unit", "admin": "United Kingdom", "adm0_a3": "GBR", "geou_dif": 1.0, "geounit": "England", "gu_a3": "ENG", "su_dif": 0.0, "subunit": "England", "su_a3": "ENG", "brk_diff": 0.0, "name": "England", "name_long": "England", "brk_a3": "ENG", "brk_name": "England", "brk_group": null, "abbrev": "Eng.", "postal": "EN", "formal_en": null, "formal_fr": null, "note_adm0": null, "note_brk": null, "name_sort": "England", "name_alt": null, "mapcolor7": 6.0, "mapcolor8": 6.0, "mapcolor9": 6.0, "mapcolor13": 3.0, "pop_est": 53013000.0, "gdp_md_est": 1696816.0, "pop_year": 2011.0, "lastcensus": -99.0, "gdp_year": 2009.0, "economy": "1. Developed region: G7", "income_grp": "1. High income: OECD", "wikipedia": -99.0, "fips_10": null, "iso_a2": "-99", "iso_a3": "-99", "iso_n3": "-99", "un_a3": "-099", "wb_a2": "-99", "wb_a3": "-99", "woe_id": -99.0, "adm0_a3_is": "-99", "adm0_a3_us": "GBR", "adm0_a3_un": -99.0, "adm0_a3_wb": -99.0, "continent": "Europe", "region_un": "Europe", "subregion": "Northern Europe", "region_wb": "Europe & Central Asia", "name_len": 7.0, "long_len": 7.0, "abbrev_len": 4.0, "tiny": -99.0, "homepart": 1.0 }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -3.422719467108379, 51.426848167406092 ], [ -3.391281786596835, 51.429795449954099 ], [ -2.668380868488896, 51.614064311432571 ], [ -2.674050679611185, 51.829517134084483 ], [ -3.104956324914895, 52.030795428930162 ], [ -3.067105906132781, 52.768956112129331 ], [ -2.723816560830244, 52.935063859856427 ], [ -3.093830673788716, 53.404547400669685 ], [ -3.092079637047107, 53.404440822963579 ], [ -2.945008510744344, 53.984999701546712 ], [ -3.614700825433033, 54.600936773292574 ], [ -3.229568912844513, 54.935834088586944 ], [ -2.264468454398525, 55.43625654852201 ], [ -2.228723992974551, 55.668595547777443 ], [ -2.005675679673857, 55.804902850350175 ], [ -1.11499101399221, 54.624986477265395 ], [ -0.4304849918542, 54.464376125702188 ], [ 0.184981316742039, 53.325014146531032 ], [ 0.469976840831805, 52.929999498092002 ], [ 1.681530795914682, 52.739520168664001 ], [ 1.559987827164321, 52.099998480836007 ], [ 1.050561557630942, 51.806760565795685 ], [ 1.449865349950244, 51.289427802121907 ], [ 0.550333693045502, 50.765738837275876 ], [ -0.787517462558696, 50.77498891865622 ], [ -2.489997524414434, 50.500018622431242 ], [ -2.956273972984093, 50.696879991247044 ], [ -3.617448085942385, 50.228355617872751 ], [ -4.542507900399244, 50.341837063185665 ], [ -5.245023159191135, 49.959999904981089 ], [ -5.776566941745273, 50.159677639356858 ], [ -4.309989793301895, 51.210001125689189 ], [ -3.414850633142123, 51.42600861266925 ], [ -3.422719467108379, 51.426848167406092 ] ] ] ] } }
]
}

Activity

import android.graphics.Color;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMapOptions;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polygon;
import com.google.maps.android.geojson.GeoJsonFeature;
import com.google.maps.android.geojson.GeoJsonGeometry;
import com.google.maps.android.geojson.GeoJsonLayer;
import com.google.maps.android.geojson.GeoJsonPolygon;
import com.google.maps.android.geojson.GeoJsonPolygonStyle;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class EuroMap extends FragmentActivity implements OnMapReadyCallback {

private GoogleMap mMap;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_euro_map);
    // Obtain the SupportMapFragment and get notified when the map is ready to be used.
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
}

@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;

    mMap.setMapType(GoogleMap.MAP_TYPE_NONE);


    LatLngBounds EUROPEBOUNDS = new LatLngBounds(
            new LatLng(34, -15), new LatLng(65, 40));
    LatLngBounds EUROPE_M_BOUNDS = new LatLngBounds(
            new LatLng(45, 0), new LatLng(65, 21));

    mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(EUROPEBOUNDS, 100,100,0));
    mMap.animateCamera(CameraUpdateFactory.zoomTo(4),1000,null);
    mMap.setLatLngBoundsForCameraTarget(EUROPE_M_BOUNDS);


    try{
        final GeoJsonLayer all_rough = new GeoJsonLayer(googleMap, R.raw.england, getApplicationContext());


        final GeoJsonPolygonStyle myPolygonStyle = all_rough.getDefaultPolygonStyle();
        myPolygonStyle.setFillColor(Color.parseColor("#ffffff"));
        myPolygonStyle.setStrokeColor(Color.parseColor("#8a8a8a"));
        myPolygonStyle.setStrokeWidth(2);
        myPolygonStyle.setZIndex(2);

        final GeoJsonPolygonStyle englandStyle = new GeoJsonPolygonStyle();
        englandStyle.setFillColor(Color.parseColor("#FF5733"));
        englandStyle.setStrokeColor(Color.parseColor("#42C0FB"));
        englandStyle.setStrokeWidth(2);
        englandStyle.setZIndex(3);

        all_rough.addLayerToMap();

        all_rough.setOnFeatureClickListener(new GeoJsonLayer.GeoJsonOnFeatureClickListener() {
            @Override
            public void onFeatureClick(GeoJsonFeature feature) {
                Toast.makeText(EuroMap.this,
                        "Feature clicked: " + feature.getProperty("geounit"),
                        Toast.LENGTH_SHORT).show();
            }
        });




    } catch (JSONException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }


}
}

If you need any more information, let me know. Any help that can be provided would be greatly appreciated as I am currently against a wall in terms of moving forward.

I look forward to any responses...and thanks!

OK so I have been looking further into this and I now have a solution that works.

Unfortunately, it does not provide a solution for loading in a MultiPolygon and using a clicklistener, so there is more room for alternative solutions on this.

My solution:

Basically, I took the GeoJSON file I had, and split the MultiPolygons down into Polygons (all the individual "split" polygons have the same feature "properties"). This allows the geometry and property information to be loaded correctly and clicked in the program. To do this I used a program called QGIS ( http://www.qgis.org/en/site/ ) which is free and open source and the suggestions here:

https://gis.stackexchange.com/questions/64214/saving-of-multipolygon-shape-file-into-a-individual-polygon-shape-files

One of the drawbacks is that Greece, for example, is now made up of many geometries, so if one of them is clicked they don't all change together, only the one you clicked. Obviously it should be possible (I would hope) to make this happen with extra code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM