(Maps) Avoid camera to comeback to prior position when I add a new Pin - google-maps

I have an app that shows a Map and a Pin on the center of it(just like Uber and PedidosYa), I have a button that when I click it sends the location where the pin's on. And it makes to appear the closest stores around that pin.
My problem is that when the first time the map appears its centered in my location, I move the map around to locate the pin, and when I click the button I want the map to stay there, but its comeback to the prior location and THEN moves the camera to the location where I drop the pin. I want to avoid that moving.
The function I use when I click the button to drop the pin is something like this:
var CenterPos = customMap.GetMapCenterLocation();
var pinPersonal = new CustomPin()
{
Id = "000",
Position = new Position(CenterPos.Latitude, CenterPos.Longitude),
Label = "Mio",
Url = "Mío"
};
customMap.Pins.Add(pinPersonal);
This draws a pin where I click the button. If I keep it this way, it draws the pin, and the camera comesback to the prior location.
After I use something like this:
customMap.MoveToRegion(MapSpan.FromCenterAndRadius(
new Position(latitud, longitud), Distance.FromMiles(0.2)));
that makes the camera to move to the location I choose. But it comebacks always to the prior location and the moves to the new one.
Any idea? Im not sure from where this behavior comes.

Did you implement CustomMap according with Customizing a Map Pin - Xamarin?
Probably you should override OnMarkerClickListener.OnMarkerClick and return true in your custom renderer.
This means disable default behavior(centering map, open info-window) and you can implement your own behavior when pin clicked.
See this link.
Markers  |  Maps SDK for Android  |  Google Developers
/** Called when the user clicks a marker. */
#Override
public boolean onMarkerClick(final Marker marker) {
// Retrieve the data from the marker.
Integer clickCount = (Integer) marker.getTag();
// Check if a click count was set, then display the click count.
if (clickCount != null) {
clickCount = clickCount + 1;
marker.setTag(clickCount);
Toast.makeText(this,
marker.getTitle() +
" has been clicked " + clickCount + " times.",
Toast.LENGTH_SHORT).show();
}
// Return false to indicate that we have not consumed the event and that we wish
// for the default behavior to occur (which is for the camera to move such that the
// marker is centered and for the marker's info window to open, if it has one).
return false;
}

Related

Wrong code in tutorial for event listeners

I am following this tutorial to build a store locator page with a Mapbox map.
I don't want to add custom markers because I already have custom map labels (symbols?), which means I don't need the optional last section of the tutorial and stop right after Add Event Listeners.
Once this is completed, the page should react to clicks in the side panel list, as well as on the map (2 event listeners). However, in the demo provided in the tutorial for that particular step, you can tell the code for the second event listener, the one making the map clickable, is not functioning, which makes me believe there is a mistake in the provided code:
// Add an event listener for when a user clicks on the map
map.on('click', function(e) {
// Query all the rendered points in the view
var features = map.queryRenderedFeatures(e.point, { layers: ['locations'] });
if (features.length) {
var clickedPoint = features[0];
// 1. Fly to the point
flyToStore(clickedPoint);
// 2. Close all other popups and display popup for clicked store
createPopUp(clickedPoint);
// 3. Highlight listing in sidebar (and remove highlight for all other listings)
var activeItem = document.getElementsByClassName('active');
if (activeItem[0]) {
activeItem[0].classList.remove('active');
}
// Find the index of the store.features that corresponds to the clickedPoint that fired the event listener
var selectedFeature = clickedPoint.properties.address;
for (var i = 0; i < stores.features.length; i++) {
if (stores.features[i].properties.address === selectedFeature) {
selectedFeatureIndex = i;
}
}
// Select the correct list item using the found index and add the active class
var listing = document.getElementById('listing-' + selectedFeatureIndex);
listing.classList.add('active');
}
});
Would anyone be able to tell what is wrong with this code?
Turns out the code is incomplete in that the cursor doesn't change to a pointer as you hover over a map label/marker so it doesn't clue you into realising you can click on it, hence my assumption it wasn't working at all. I assume the general users who would then face the map would be equally deceived unless the pointer shows up. So in the tutorial, if you do go ahead and click the marker, it will have the expected behaviour and display the popup, although no pointer is shown.
Here is how to create the pointer, based on this fiddle: https://jsfiddle.net/Twalsh88/5j70wm8n/25/
map.on('mouseenter', 'locations', function(e) {
// Change the cursor style as a UI indicator.
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'locations', function() {
map.getCanvas().style.cursor = '';
});

How to check if a marker is in a cluster?

With Leaflet.Markercluster, how is it possible to check if a marker is in a cluster?
Use Leaflet's hasLayer() function
Regular visible markers technically exist as layers in the map. Leaflet also has a function hasLayer() that returns true/false whether a given reference, like a stored marker, currently exists (ie "is visible") in the map as a layer.
For my specific problem, I gave a special visual decoration to a selected map marker (e.g. red border), and this decoration remained even after that marker went in-and-out of a cluster. I needed the selected marker to deselect itself if it entered a cluster.
Below is rough logic that allows me to check whether a given marker reference is visible to the user after a cluster event (that may occur for any reason, like zoom events or non-user driven movements in the map).
Relevant abbreviated code:
I hold my clustering like this...
this.markersClustered = L.markerClusterGroup({ // Lots of stuff here... } })
In my click event for individual markers, I store the marker in a "selectedItem" object (which I use for all kinds of other logic in my app)...
onEachFeature(feature, marker) {
marker.on("click", e => {
// ... (lots of code) ...
// Save instance of the marker; I call it "layer" only
// because I only use this for the hasLayer() check
this.selectedItem.layer = marker
// Here do other stuff too, whatever you need...
//this.selectedItem.target = e.target
//this.selectedItem.latlng = e.latlng
//this.selectedItem.id = e.target.feature.id
//this.selectedItem.icon = layer._icon
// ... (lots of code) ...
})
}
When cluster animations end, using hasLayer(), check whether the selected marker is in a cluster, and do stuff.
Note: the check is done at the END of clustering animation in my use case, because I didn't want the user to see the selected marker lose it's special visual decoration while the clustering animation was happening (it would appear buggy).
this.markersClustered.on('animationend', (e) => {
// Check visibility of selected marker
if(this.map.hasLayer(this.selectedItem.layer)) {
// True: Not in a cluster (ie marker is visible on map)
} else {
// False: In a cluster (ie marker is not visible on map)
}
console.log("Selected marker visible?:" + this.map.hasLayer(this.selectedItem.layer))
})

URLImage on MapContainer not displayed on actual device and flickering in simulator

My app features a map, on which the user's avatar is displayed in the center and where markers including photo should be added when the user moves the map.
On the simulator, the markers are added but the images disappear as soon as I release the pointer then only the placeholders remain (this is what I call flickering). On the device, nothing is shown apart from the user's avatar.
As you can see the image does not remain on the map, only the placeholder does. The user icon is southern on the map but it is shown.
Please note: I am not receiving 404 errors and there is only one listener on the map (see below):
Here is how I trigger the map update:
googleMap.addMapListener((source, zoom, center) -> {
showReportsOnMap(googleMap, center, theme, currentForm, selectCategoryButton.getWidth());
});
And here is how I add the reports the map:
public void showReportsOnMap(
MapContainer currentMap,
Coord center,
Resources theme,
Form f,
int reportImageWidth) {
/**
* Get the map borders (CAUTION : it can be NaN)
*/
Coord NE = currentMap.getCoordAtPosition(currentMap.getAbsoluteX() + currentMap.getWidth(), currentMap.getAbsoluteY());
Coord SW = currentMap.getCoordAtPosition(currentMap.getAbsoluteX(), currentMap.getAbsoluteY() + currentMap.getHeight());
boolean bordersKnownAndValid = false;
// Checks that the borders does not contain NaN as longitudes and latitudes
if (!Double.isNaN(NE.getLatitude())
&& !Double.isNaN(NE.getLongitude())
&& !Double.isNaN(SW.getLatitude())
&& !Double.isNaN(SW.getLongitude())) {
// The borders can be used
bordersKnownAndValid = true;
}
if (bordersKnownAndValid) {
ArrayList<Report> localReports = (ArrayList<Report>) (Report.getReportsWithinBoundingBounds(NE, SW, selectedCategoryIdToBeShownOnMap).get(1));
// Revalidate only if we have something new to show
if (localReports.size() > 0) {
currentMap.clearMapLayers();
currentMap.addMarker(ParametresGeneraux.getCurrentUser().getUserIcon(),
new Coord(ParametresGeneraux.getCurrentUser().getCurrentUserLocation().getLatitude(),
ParametresGeneraux.getCurrentUser().getCurrentUserLocation().getLongitude()),
ParametresGeneraux.getCurrentUser().getUserNickname(), "", null);
Image tempPlaceholder = Image.createImage(
reportImageWidth,
reportImageWidth,
ParametresGeneraux.accentColor);
Graphics gr = tempPlaceholder.getGraphics();
gr.setAntiAliased(true);
gr.setColor(ParametresGeneraux.accentColor);
gr.fillArc(0, 0, reportImageWidth, reportImageWidth, 0, 360);
EncodedImage roundPlaceholder = EncodedImage.createFromImage(tempPlaceholder, true);
// Add the report on the map
for (Report report : localReports) {
String photoFilenameInStorage = Report.getFilename(report.getPhotoPath())
+ ParametresGeneraux.SUFFIX_ON_MAP_IMAGE;
EncodedImage reportIcon = EncodedImage.createFromImage(URLImage.createToStorage(roundPlaceholder,
photoFilenameInStorage,
report.getPhotoPath(),
ParametresGeneraux.RESIZE_SCALE_WITH_ROUND_MASK
),
false); // we want transparency png otherwise it shows black edges
currentMap.addMarker(reportIcon,
new Coord(report.getLocation().getLatitude(), report.getLocation().getLongitude()
),
report.getCategory().getName(), "",
(evt) -> {
// Opens the detail form about this report
new ReportDetailsForm(theme, report, f.getClass()).show();
});
}
currentMap.setCameraPosition(new Coord(center.getLatitude(), center.getLongitude()));
currentMap.zoom(new Coord(center.getLatitude(),
center.getLongitude()),
ParametresGeneraux.getUserZoomLevelOnMap());
currentMap.animate();
//f.forceRevalidate();
}
}
}
So I guess that the flickering in the simulator is a kind of slow motion of what happens on the device although the device does not show the placeholder.
What should I do to make the markers appear with an image?
EDIT March 8th 2017
On simulator, if I show a Dialog just before adding the marker to the map with this code :
Dialog.show("Photo", report.getAddress(), Dialog.TYPE_INFO, reportIcon, "OK", null);
The icon is well displayed in the Dialog (see screen capture below)
and then the image appears on the map without flickering any more as depicted below :
However on an actual Android device even the Dialog does not appear.
Finally I don't know why the Dialog makes then the markers behave as expected on the simulator but not on the device, so I am a bit at lost!
Any help would be precious.
The problem is that URLImage may not have finished downloading by the time you added it as a marker. If you call EncodedImage.createFromImage(urlImage) before URLImage has finished downloading, then you'll be creating an encoded image of the urlImage's placeholder.
the com.codename1.io.Util class includes quite a few methods for downloading images from URLs. Some are blocking, and some use a callback. Either way you just need to ensure that the image is actually downloaded before adding it to a map.
NOTE: Normally this wouldn't be an issue with URLImage - e.g. if you were adding it to a Button or a Label. It is only a problem here because the MapContainer is native, and it actually needs to pass the image data to the native layer at the time that setMarker() is called.

Android Google Map how to check if user is in marker circle region

I am using Google Maps, and want to be able to detect if a user is in the radius of a Marker (placed on map), using the users current location. I have the users current location coordinates (latitude and longitude) and the marker's coordinates, but do not know how to calculate whether the user is in the area. The picture below might best describe what I want to do.
I have an algorithm like this:
map.OnInfoWindowClickListener(new OnInfoWindowClickListener()){
public void isUserInArea(Marker marker){
float[] distance = new float[2];
//users current location
Location.distanceBetween(currentLocation.getLatitude(),currentLocatiocation.getLongitude(),
marker.getPosition().latitude, marker.getPosition().longitude, distance);
}
Which doesn't find if the current location is within marker region because I can't get hold of the markers circle. It's the closest i've got to it however. Would appreciate help.
To help, I add a circle to a map like this
// adding circle to map
circleOptions = new CircleOptions();
circleOptions.center(new LatLng(locationlist.get(i)
.getLatitude(), locationlist.get(i).getLongitude()));
circleOptions.radius(20);
circleOptions.strokeColor(Color.BLUE);
circleOptions.fillColor(Color.BLUE);
map.addCircle(circleOptions);
//check that all tasks are in circle radius
Marker locationMarker = map.addMarker(markerOp);
locationMarker.showInfoWindow();
I use this:
Location.distanceBetween(mMarker.getPosition().latitude,
mMarker.getPosition().longitude, mCircle.getCenter().latitude,
mCircle.getCenter().longitude, distance);
if (distance[0] > mCircle.getRadius()) {
//Do what you need
}else if (distance[0] < mCircle.getRadius()) {
//Do what you need
}
Why don't you use proximity alerts?
This is what you can do: instead of drawing a circle, place a Marker on the map like so:
map.addMarker(new MarkerOptions()
.title(name)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.gpsmap))
.position(coordinates)
.flat(true)
.rotation(90));
and then add a proximity alert to it calling the following method:
// Proximity alert
private void addProximityAlert(double lat, double lng, int id){
Intent intent = new Intent(PROX_ALERT_INTENT);
PendingIntent proximityIntent = PendingIntent.getBroadcast(this, id, intent, Intent.FLAG_ACTIVITY_NEW_TASK);
locationManager.addProximityAlert(lat, lng, POINT_RADIUS, EXPIRATION, proximityIntent);
}
where EXPIRATION = -1 (so the proximity alert doesn't expire) and POINT_RADIUS takes the values of the radius of your previous circle.
Then you need to add a proximity alert listener to the map:
IntentFilter filter = new IntentFilter(PROX_ALERT_INTENT);
registerReceiver(new ProximityIntentReceiver(), filter);
where PROX_ALERT_INTENT = "yourProjectPackageName.ProximityActivity";
Hope this helps
This tutorial can help your requirement.
User entry exit proximity alert
all the best.

Click placemarker using touchscreen X and Y

I'm using the Google Maps API and trying to drive the GE Plugin from a touch screen. I get back an X, and Y for a given touch and can do something like:
var targetElement = document.elementFromPoint(data.x, scaledY);
if (null != targetElement) {
var event = $.Event ("click");
$(targetElement).trigger (event);
}
to raise an event for a button on the screen but this does not click on placemarkers within the GE Plugin. Is there an easy way to fire a click event on these markers?
Many thanks for any help you can provide.
AFAIK you can't manually raise any events for any of the objects in the Google Earth Api, you can only add an event listener for them as either a named or anonymous method.
However you could certainly simulate the default click behaviour (opening the balloon, fly to, etc) for placemarks using a custom method.
I have done this before and it simply required that each feature had a unique ID within the plugin (set either via the api or in kml). I then used this as a way to target the feature based on it's id.
In your example presuming targetEvement could also have a corresponding ID set, then you could use this technique to simulate a 'click' like so.
var targetElement = document.elementFromPoint(data.x, scaledY);
if (null != targetElement) {
var event = $.Event ("click");
$(targetElement).trigger (event);
simulateClick(targetElement);
}
var simulateClick = function (element) {
// presuming 'ge' references the plugin
// we create a feature balloon based on the placemark
var id = element.attr('id');
var placemark = ge.getElementById(id); // corresponding placemark
var balloon = ge.createFeatureBalloon();
balloon.setFeature(placemark);
ge.setBalloon(balloon);
// Update the view in Google Earth to the placemark.
// if no abstract view is defined you could also use the placemarks
// latitude and longitude to construct a KmlCamera object.
ge.getView().setAbstractView(placemark.getAbstractView());
}