I want to replace the data behind an existing source. This is trivial in javascript:
map.getSource('trace').setData(data);
See https://docs.mapbox.com/mapbox-gl-js/example/live-update-feature/
That method does not exist in Android. Once I have set a value, I can't replace it (nothing changes if I do):
GeoJsonSource mySource;
mySource.setGeoJson("some json data");
To delete and readd the source, I'd have to remove the layer using the source first: https://github.com/mapbox/mapbox-gl-native/issues/12526
Since I'm getting a fully functioning Style object from the server, removing, recreating and readding the layer/source at the correct position is tedious to say the least.
Above code actually works, but to reset my layer I used:
mySource.setGeoJson("");
Setting the source to empty String breaks something. Afterwards the GeoJson can not be set to something meaningful again. So to reset data, I'll have to use the visibility attribute of a layer. Replacing meaningful GeoJson with meaningful GeoJson works just fine.
The setGeoJson methods work correctly with any valid Geometry to add data (e.g. Point, MultiPoint).
Then, to clear or initialize the source without "breaking" the layer you can use:
mySource.setGeoJson(FeatureCollection.fromFeatures(new ArrayList<Feature>()));
Related
Here is mapBox sample to draw a line geometry.
private void onStyleLoaded(Style style) {
initRouteCoordinates();
style.addSource(new GeoJsonSource("line-source",
FeatureCollection.fromFeatures(new Feature[]{
Feature.fromGeometry(LineString.fromLngLats(routeCoordinates))})));
style.addLayer(new LineLayer("lineLayer", "line-source")
.withProperties(PropertyFactory.lineDasharray(new Float[] {0.01f, 2f}),
PropertyFactory.lineCap(Property.LINE_CAP_ROUND),
PropertyFactory.lineJoin(Property.LINE_JOIN_ROUND),
PropertyFactory.lineWidth(5f),
PropertyFactory.lineColor(Color.parseColor("#e55e5e"))));
Point point = routeCoordinates.get(0);
mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(point.latitude(), point.longitude()), 17));
}
I need to add more points and update the line. As you can see in the example line geometry is given to the source layer at the construction time. I couldn't find any api to add a point to the current line later.
Should I remove this line and redraw a new one ? Isn't there a better approach ?
You can add the "line-source" source and corresponding "lineLayer" layer once, and set the data contained by the source each time you want to add more points to update the line. Namely, each time you want to update the data rendered by the LineLayer:
Add the newly acquired coordinate to your existing GeoJSON source, stored in a variable called data. (I'd recommend storing new GeoJsonSource("line-source", ... in a data variable rather than creating it inline within the call to style#addSource, so that you can access it later to update).
Execute style.getSourceAs("line-source").setGeoJson(data).
Alternatively, you could use geoJsonSource.setGeoJson(Feature.fromGeometry(LineString.fromLngLats(updatedRouteCoordinates))) rather than setGeoJson(data), which might be more convenient depending on your use case.
You can modify the implementation according to your specific needs, but the general idea is that you only need to update the existing source's data, and not its corresponding layer, each time you want to update the line. This concept is described in the modify properties documentation for the Mapbox Maps SDK for Android. To quote the documentation:
sources and layers aren't immutable so they can be modified anytime during the map render
I've been following this guide provided by Mapbox to familiarize myself with SymbolLayers and how to manipulate their properties on the map.
https://blog.mapbox.com/a-guide-to-the-android-symbollayer-api-5daac7b66f2c
The key step I'm having issues with is Step 5 where they update the iconSize property onMapClick. After they add a property to the selected Feature, the guide says to call source.setGeoJson(featureCollection); in order to reset the source of the layer.
The project I'm working with uses a VectorSource as the source of data for the SampleLayer, not a GeoJsonSource like the example uses. The problem is that VectorSource doesn't provide a method like setGeoJson so I'm not able to reset the layer source after I change the property.
What can I do to work around this without having to change all of our source data?
for (Feature feature : featureCollection.getFeatures() {
if (feature.getStringProperty("title").equals(selectedFeature.getStringProperty("title"))) {
feature.getProperties().addProperty("selected", true);
}
}
source.setGeoJson(featureCollection);
The full source of that example can be found here: https://github.com/mapbox/mapbox-android-demo/blob/286f33d848c9fea48de908b144682081961b986b/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/labs/SymbolLayerMapillaryActivity.java
For anyone coming across this issue in the future, the only possible approach here would be to remove and add layer again, with the updated source. This is however an ineffective solution, so it would really be better for you to use GeoJson source instead.
A Path object comes with many methods that changes it (moveTo(), lineTo(), cubicTo(), arcTo(), reset(), etc.).
Is there a way to freeze the object once you have it the way you want it, before you pass it onward?
Something along the line of CGPath in objective-c?
No. Immutable means that once the constructor for an object has completed execution that instance can't be altered.
Still, you can subclass Path and add pseudo-immutability yourself if that's really needed but there is no built-in mechanism out of the box.
Not ideal, but an alternative solution to the problem you are describing is to copy of the original Path using the constructor:
Path copy = new Path(originalPath);
Then, you can pass the copy the other thread without worrying if they change it while you are reading the original Path.
I use here-map sdk. I have db file with 16500 ! paths (coordinates of a point). I need to draw all paths on the map, when user activate function "show additional paths". But i think, if i try to fetch big number of path and add all poplilynes object on here map, it will take a huge amount of time.
Help to find the optimal solution.
I would filter your data based on the visible viewport and disable this functionality where it doesn't make much sense (continental or globe level).
So, let's assume you app shows the map on zoomlevel 16 or 17 (district level), you can retrieve the viewport as GeoBoundingBox from the Map instance (e.g. via mapView.getMap()) with getBoundingBox().
The GeoBoundingBox makes it easy for you now to check for collisions with your own objects, since it has several "contains()" methods.
So everything that collides with your viewport should be shown, everything else is ignored.
You can update whenever the map viewport changes with either listening for OnTransformListener in the Map class or register for the MapGesture events (get MapGesture via getMapGesture() and listen for zooming events via addOnGestureListener())
If the amount of data for filtering is still too big, you can also think about preparing your data for more efficient filtering, like partitioning (region based would be my first idea) so only a subset of your data needs to be filtered.
It seems that Custom Location Extension (https://developer.here.com/platform-extensions/documentation/custom-location/topics/what-is.html) can help with this case.
In short, it allows you to upload a custom data to the HERE backend and query it later.
There are scenarios in feature files wherein I've use the text "Foo" and on click its open a new page. this text sometime changes to "Foo1" or "Foo2" or to something else. to avoid line by line change in feature file for "Foo" to "Foo1" or "Foo2" is there any way that I can globally declare variable in top/bottom of the feature file where I can set the required text in variable on fly and I shall start executing my test instantly?
This change exist in many feature files and around 1000 lines in feature file. To get solution for this, I try on setting environment variables but I couldn't reach all the way till end this issue to solve. So can anyone help me on this?
Thanks in advance
What if you do the replacement in your step implementation instead? Then you could have the desired value in a separate file or pass it as arguments. That way you don't need to hard code the values.
Could scenario outlines help you in any way or is the value only changing depending on external changes?
My first thought was scenario outlines like #homaxto said.
Then I thought you might want to affect it by which system you are connected to. You can do this through configuration. I have done this with Fig_Newton.
You can either set an environment varaible or use one in the commandline. Or you can use #hook type tags. With a hook tag, you can have a tag at the top of a feature file that you can use to set a variable that affects how the steps operate (but it needs to be handled inside the step).