I am currently creating a map which updates based on users selection and displays 5 location closest to them. This works however when the user changes their selection the map updates and displays the 5 NEW locations as well as the 5 OLD locations.
I am not sure how to remove the old symbols.
public void displayResults(ArrayList allLocation) {
SymbolManager sm = new SymbolManager(mapView,map,styleMap);
sm.deleteAll();
SymList.clear();
sm.setIconAllowOverlap(true);
sm.setIconIgnorePlacement(true);
int count = 1;
for (LocationDetails a : allLocation
) {
// gets the distance from user to Location
double LocationLat = Double.parseDouble(a.getLatitude());
double LocationLng = Double.parseDouble(a.getLongitude());
float[] disResult = new float[1];
Location.distanceBetween(lat, lng, LocationLat, LocationLng, disResult);
results.append(count + ": " + a.getName() + " " + "\n");
distanceResults.append(Math.round(disResult[0]) + "m" + "\n");
SymbolOptions symbolOptions = new SymbolOptions()
.withLatLng(new LatLng(LocationLat, LocationLng))
.withIconImage("marker-11")
.withTextField(""+count)
.withIconColor("black")
.withIconSize(2.5f);
SymList.add(symbolOptions);
count++;
}
LatLngBounds latLngBounds = new LatLngBounds.Builder()
.include(SymList.get(0).getLatLng())
.include(SymList.get(1).getLatLng())
.include(SymList.get(2).getLatLng())
.include(SymList.get(3).getLatLng())
.include(SymList.get(4).getLatLng())
.build();
map.animateCamera(CameraUpdateFactory.newLatLngBounds(latLngBounds, 50), 2000);
for(SymbolOptions a : SymList){
sm.create(a);
}
SymList.clear();
}
I have been using mapbox for 3 months. After hours of research I discovered that on Android the only way to remove a Symbol or any element on the map was to reload all the elements from scratch. Unfortunately, there is currently no method to remove a single element.
So I suggest you create a container class in which to save your items.
If your use case only requires showing about five markers on the map at a time, it might be easier to use native sources and SymbolLayers rather than relying on the abstraction provided by the SymbolManager.
For example, this icon updates based on API response Android demo shows how to add a GeoJSON source and corresponding layer to the map, then update said source to get a different visual result. Basically all of the logic you will need is encapsulated here, but your GeoJSON will be a FeatureCollection of multiple (namely, 5) features rather than just one point.
So, you can set up your symbols similarly to how it's done in the linked example:
private void initSpaceStationSymbolLayer(#NonNull Style style) {
style.addImage("space-station-icon-id",
BitmapFactory.decodeResource(
this.getResources(), R.drawable.iss));
style.addSource(new GeoJsonSource("source-id"));
style.addLayer(new SymbolLayer("layer-id", "source-id").withProperties(
iconImage("space-station-icon-id"),
iconIgnorePlacement(true),
iconAllowOverlap(true),
iconSize(.7f)
));
}
, and then update the source's GeoJSON to the new locations closest to the user's position, similar to the updateMarkerPostion method:
private void updateMarkerPosition(LatLng position) {
// This method is where we update the marker position once we have new coordinates. First we
// check if this is the first time we are executing this handler, the best way to do this is
// check if marker is null;
if (map.getStyle() != null) {
GeoJsonSource spaceStationSource = map.getStyle().getSourceAs("source-id");
if (spaceStationSource != null) {
spaceStationSource.setGeoJson(FeatureCollection.fromFeature(
Feature.fromGeometry(Point.fromLngLat(position.getLongitude(), position.getLatitude()))));
}
}
// Lastly, animate the camera to the new position so the user
// wont have to search for the marker and then return.
map.animateCamera(CameraUpdateFactory.newLatLng(position));
}
A few modifications will need to be made, of course, but this option might be more direct for your implementation specifically.
Related
I work for my school project on MPAndroidChart especially a realtime graph, i would like to display Time of the value.
I set a IndexAxisValueFormatter with a "getFormattedValue", it work but refresh every label and not just the last, I try to have for each entry in my graph a XLabel who show the time, I really don't know how to do that you're help would be welcome.
Code for create an entry and display it :
void creaGraph() {
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
if (boxCO2.isChecked()) {
A_CO2.add(new Entry(indice, listData.recup_data(indice - 1).getCO2()));
LineDataSet setCO2 = new LineDataSet(A_CO2, "CO2");
setCO2.setAxisDependency(YAxis.AxisDependency.LEFT);
paramSet(setCO2);
setCO2.setColor(Color.RED);
setCO2.setCircleColor(Color.RED);
dataSets.add(setCO2);
}
LineData data = new LineData(dataSets);
graph.setData(data);
data.notifyDataChanged();
graph.notifyDataSetChanged();
graph.invalidate();
}
The override of getFormattedValue
#Override
public String getFormattedValue(float value) {
return listData.recup_data(GraphPage.indice - 1).getTemps();
}
And a picture of my issue
Every label are refresh when a new entry come
Also, I see after the 7th values entry no longer have a time values
You never use value in getFormattedValue. The string you construct there should be based on value or it will show the same thing for every axis entry.
Something like this:
#Override
public String getFormattedValue(float value) {
return makeDateStringAt(value);
}
For example, if you have a chart with axis values at 0, 1, 2, 3 then getFormattedValue will be called 4 times with 0f, 1f, 1f, and 3f as its arguments and you should use those inputs to create the appropriate string to show at those positions on the axis.
1) I'm practicing stuff with graphs in order to add that feture to my app, I want the upper labels ( the xAxis base ) to be shown only where entries occur.
I haven't found a suitable solution online yet, and currently it appears on every xAxis from first entry to last entry as in the picture below:
I want it to be without the one sI deleted, as shown in the picture below:
2) and the second question I'm struggling with it is that I want to be able to draw for example in (x=5, y=7) and after it to draw at (x=1, y =3), but it wont let me add an entry with a smaller x that any other entry that already in the graph.
You have to extend from ValueFormatter class.
for more detail take a look at link
You can pick your desired logic to make the label disappear with returning "".
for example:
public String getFormattedValue(float value) {
if ((int)value <= 0) //your logic to evaluate correctness
return ""; // make lable go away
//...
}
UPDATE 2 (in Kotlin):
There is another overload for getFormattedValue which have a AxisBase parameter and you can use mEntryCount or mEntries.
override fun getFormattedValue(value: Float, axis: AxisBase?): String {
if (axis?.mEntryCount!! <= 0)
return ""
}
I create plots based on worldguard regions. I am looking for a good method of checking if there is no other region within a radius of 50 counts in each direction. My point is that someone does not create a plot and someone else's plot. Currently, I checked it in a strange way for me, but it practically worked.
Location p3 = p.getLocation();
p3.setX(p3.getBlockX());
p3.setY(60);
p3.setZ(p3.getBlockZ()+size);
if(region.getApplicableRegions(p3).size() == 0) {
plotsCheck.put(p.getUniqueId(), plotsCheck.get(p.getUniqueId())+1);
}
Location p3a = p.getLocation();
p3a.setX(p3a.getBlockX());
p3a.setY(60);
p3a.setZ(p3a.getBlockZ()+10);
if(region.getApplicableRegions(p3a).size() == 0) {
plotsCheck.put(p.getUniqueId(), plotsCheck.get(p.getUniqueId())+1);
}
Location p4 = p.getLocation();
p4.setX(p4.getBlockX());
p4.setY(60);
p4.setZ(p4.getBlockZ()-size);
if(region.getApplicableRegions(p4).size() == 0) {
plotsCheck.put(p.getUniqueId(), plotsCheck.get(p.getUniqueId())+1);
}
In this way, I checked if it was empty. If so, I added 1 point to the hashmap.
Unfortunately, this does not always work and ends with the fact that several plot plots belong to 2 people. Does anyone of you propose a different solution for this?
WorldGuard already has some built in features for that.
RegionContainer container = getWorldGuard().getRegionContainer();
RegionManager manager = container.get(world);
Region newRegion = //create your region somehow
manager.addRegion(newRegion);
List<ProtectedRegion> regions = new ArrayList<ProtectedRegion>(manager.getRegions().values());
List<ProtectedRegion> overlappingRegions = newRegion.getIntersectingRegions(regions);
if (overlappingRegions.size() > 0) {
//delete region newRegion
} else {
//region is valid
}
This of course works only after the region has already been created.
Code has not been tested. Just searched through the WorldGuard API wiki.
https://worldguard.enginehub.org/en/latest/developer/regions/protected-region/#finding-intersecting-regions
I have a app that opens the map and zooms on my location with a marker
and then if i longClick on any place it saves that location in database
everything works fine but one thing i cannot manage is draw a line of path between two location markers.
these are three global variables
Location myLocation;
LatLng onmaplongclicklastlatlng;
private GoogleMap mMap;
mylocation is assigned by LocationListener and onmaplongclicklastlatlng is assigned when i long click on any place on the map.
placing the marker on both location is done i already have the two points i want to draw the line on.
i just need to draw a line between those two locations (my current location periodically updated in the myLocation variable)
and onmaplongclicklastlatlng changed whenever i long click on the map.
the whole code is done and i have a button that i want to use to draw the line
since i can access the two location variables from this button method, Other code need not be changed.
public void getLine(View view) {
// need to draw a line here from user gps posiution to the marker location
}
i have tried many tutorials but they do not work for some reason, any help would be really appreciated.
oh and last but not least
onmaplongclicklastlatlng
is a LatLng and
myLocation
is a Location
but they can be interchanged to fit the purpose
ex. Location maplocation = new Location(onmaplongclicklastlatlng
.latitude, onmaplongclicklastlatlng.longitude);
and
Latlng myLatLng = new LatLng(myLocation.getLatitude(), myLocation.getLongitude());
As i said any help would be really appreciated.
And let me know if anything else needed i will edit the question then.
To calculate accurate distance between two loaction you have to use Google Map Distance Matrix API. Construct your url like below.
https://maps.googleapis.com/maps/api/distancematrix/json?" +"origin=" + origin.latitude + "," + origin.longitude+ "&" +"destination=" + dest.latitude + "," + dest.longitude +"&sensor=false&units=metric&mode=driving" + "&" + key=YOUR_API_KEY
And to draw line between two location you have to first use the Google Map Direction Api, construct your url like below
https://maps.googleapis.com/maps/api/directions/json?" +"origin=" + origin.latitude + "," + origin.longitude+ "&" +"destination=" + dest.latitude + "," + dest.longitude +"&sensor=false&units=metric&mode=driving" + "&" + key=YOUR_API_KEY
above api call return a list of latlng add the list into polylines
Polyline polyline1 = googleMap.addPolyline(new PolylineOptions()
.clickable(true)
.addAll(latlngList));
hope it helps.
To add a polyline -
val polyline1 = map?.addPolyline(
PolylineOptions().clickable(true)
.add(LatLng(23.8103, 90.4125), LatLng(4.0383, 21.7587))
.geodesic(true) // this will turn this line to curve
)
// To add styles in the line
stylePolyline(polyline1)
private fun stylePolyline(polyline: Polyline?) {
polyline?.let {
it.color = ContextCompat.getColor(binding.mapPlaceholder.context, R.color.lineColor)
it.pattern = mutableListOf(Dot(), Gap(5F))
it.startCap = RoundCap()
it.jointType = JointType.ROUND
}
}
How about these:
https://github.com/zhenyanghua/MeasureTool-GoogleMaps-V3
http://zhenyanghua.github.io/google-maps/measure-tool/
Regards
PS: I am not the author of the software.
I am trying out the GraphView Library for creating charts on Android. It looks quite decent, but I am wondering if there is a way to add some space between the tick labels and the graph itself. As you can see, there is basically none:
I use the following code to set up the graph (very similar to the example):
GraphView graph = (GraphView)view.findViewById(R.id.graph);
LineGraphSeries<DataPoint> series = new LineGraphSeries<DataPoint>(new DataPoint[] {
new DataPoint(0, 1),
new DataPoint(1, 5),
new DataPoint(2, 3)
});
graph.addSeries(series);
I tried using graph.getGridLabelRenderer().setPadding(), but that just added padding around the whole graph.
So, is there a way to put some padding around those labels?
yes it is possible in the current version in github (will be released in 4.0.1).
There is the method:
graph.getGridLabelRenderer().setLabelsSpace(x)
Follow this example to give your graph a custom label formatter. By doing so, you can at least add space padding to your y-axis labels (if not newline spacing to your x-axis labels).
// GraphView 4.x
graph.getGridLabelRenderer().setLabelFormatter(
new DefaultLabelFormatter() {
#Override
public String formatLabel(double value, boolean isValueX) {
if (isValueX) {
// show normal x values
return super.formatLabel(value, isValueX);
} else {
// show currency for y values
return super.formatLabel(value, isValueX) + " €";
}
}
}
);
I pulled this example from the GraphView documentation.
Otherwise, I found it interesting that someone chose this answer as the best response for a similar question.