I'm building a map with a few dozen OverlayItems in a single ItemizedOverlay. My map is made to be viewed very close up (about zoom level 18+), with the OverlayItems in very close proximity to one another. The map looks good when zoomed in. However, if the user zooms out the icons begin to overlap and everything looks incredibly junky.
Is there a way to control the OverlayItem icon size so that it scales with the map? If not, is there a way to hide the icons once a specific zoom level is reached? Any other suggestions on how to approach this problem?
Joshc, fegruior, You folks may want to check out how Geobeagle does it. Specifically, this file: http://code.google.com/p/geobeagle/source/browse/trunk/GeoBeagle/src/com/google/code/geobeagle/activity/map/OverlayManager.java
They manage two overlays, one for when you're zoomed out, and one for when you're zoomed in.
Theoretically, you could have n (however many zoom levels there are) overlays that all have differently sized icons, and swap the visible one out as you zoom in and out. This could get heavy on the processing, but whether that's something you want to do is a decision you would need to make.
Related
I'm using a GoogleMap with lots of small markers loaded. We are talking perhaps 400-500 markers. Upon user interaction, I want to have a subset of those markers change color, perhaps 100-300 of them. I want to achieve this ideally in 30ms or under, but up to 50-60ms would be acceptable.
Right now I have code something like:
onUserInteraction... {
changeColors(getTheSubset)
}
changeColors(subset) {
getMarkersForSubset(subset).removeAllFromMap();
map.addNewMarkers(subset)
}
So I remove the old markers in some color (say, green), and add new markers for those locations (say, black). When the subset is no longer relevant, I do the opposite process.
On the busiest parts of the map I am seeing this take 500ms or more, and there's noticeable lag with different markers changing colors at different times. So I am curious if there is a better math-based way to draw small circles on a map and change their colors without removing/adding markers and while minimizing alloc/gc.
Have you considered using LevelListDrawables? Rather than removing and re-adding all of your markers when updating, you could have your various drawables with each color as the levels of a LevelListDrawable. Then you can call setLevel() to set the appropriate drawable with the color you want when you update your set of pins. I'm not 100% sure you can use a LevelListDrawable for the map pin, but it is worth a shot.
API: http://developer.android.com/reference/android/graphics/drawable/LevelListDrawable.html
Example: http://iserveandroid.blogspot.com/2010/10/progress-bar-implementation-using-level.html
So LevelListDrawables are not an option, due to Gmap's use of BitmapDescriptorFactory.
One solution I found was to draw a Marker on top of the old one with the new color, then delete the old one from underneath.
There were two issues to that.
One, google-maps-android-v2 doesn't support z-indexing for Markers.
Two, if you have a lot of Markers to change the color of, the performance of it causes artifacts.
Now, recently Google released an update that made Markers with a common Bitmap a lot faster to draw, but you can always throw more Markers at it and break it.
I also attempted to draw a Marker on top, but with its visibility set to false, and to then set it to true when that location got "selected". This didn't seem too much faster although in fairness I did not benchmark it.
The conclusion: Don't change Bitmaps on Markers. (For now)
I have numerous Overlays added to a MapView. When I move, zoom in, or zoom out of the MapView the overlays cause a significant lag before the map responds to the action. Is there any way I can minimize this delay?
I saw that someone else suggested combining all the overlays into one large overlay for a similar problem. If something like that would work, how would I combine my array of overlays into a single overlay?
I also saw that it may improve performance to draw all the lines specified in the overlays on a bitmap and then overlay the bitmap instead. If this is the best option, then how would I go about implementing it?
Any help would be greatly appreciated. If you need any more information or code, then please ask!
I have numerous Overlays added to a MapView. When I move, zoom in, or zoom out of the MapView the overlays cause a significant lag before the map responds to the action. Is there any way I can minimize this delay?
Have fewer and less-complicated overlays. Use Traceview to determine exactly where your problem is. If it is that one of your existing draw() methods is slow, you will need to fix that before worrying about combining overlays. If the excess time seems to be in overlay management in MapView, then consolidating your overlays into fewer overlays may have benefit.
how would I combine my array of overlays into a single overlay?
Refactor the code into a single overlay class. Beyond that, we cannot help you, since we do not know much of anything about your overlays, other than that they are "numerous".
If this is the best option, then how would I go about implementing it?
Create a bitmap-backed Canvas, draw your lines on it, then draw the resulting Bitmap in your overlay in draw(), I presume.
I'm trying to write an Android app that will allow a user to search for a generic destination (e.g., "gas station") and be presented with up to ~5 nearby locations to choose from. The screen results would display the user location in the center, and possible destination options would be indicated by markers.
The trick is that I don't want to rescale the map from its starting scale, and so some of the possible destinations may not be visible on the screen. I want to dynamically draw a clickable direction indicator (such as an arrow) that emanates from the user location and points to any off-screen destination. If there are multiple off-screen destinations, I'd probably want to scale the arrow lengths to indicate relative distances. If the user clicks on the arrow, they should be "teleported" to the off-screen location.
Any thoughts on how to best implement this? The only information I've found on overlays uses static files (Most overlays seem to be just .PNG files for markers; one example had a route that was drawn from an XML file). I'd need to calculate the arrow based on direction
to the destination (direction the arrow points) and the relative distance to that location (arrow length), so the overlay is something I'd have to come up with at run time.
I think the main challenge is drawing the clickable arrows, but another question that comes to mind is, should I search using the Google Maps API, or is this job more suited to the Google Places API?
Thanks!
I guess we should put the teleportation on hold until the problem of a dynamically-drawn, clickable overlay is solved then!
A dynamically-drawn, clickable overlay is merely a subclass of Overlay. You will override one or both of the draw() methods to render your arrows using the Canvas 2D drawing API. You will override onTap() to be notified of taps on the map, to see if they tapped on an arrow. You add the overlay to the MapView via addOverlays().add().
Most overlays seem to be just .PNG files for markers
Those are usually ItemizedOverlay classes. That's much simpler to implement, particularly if you are one of those developers (like me) who is all thumbs when it comes to Canvas. However, you cannot achieve what you want with an ItemizedOverlay, in all likelihood.
I'd need to calculate the arrow based on direction to the destination (direction the arrow points) and the relative distance to that location (arrow length), so the overlay is something I'd have to come up with at run time.
Correct. You can use a Projection to help convert between pixel space and geo-space (latitude and longitude), if needed.
Note that this all assumes you are trying to use MapActivity and MapView. You are also welcome to use WebView or a plain browser to bring up your own JavaScript-based maps, if you prefer.
I have faced some problems with the Android MapView API. I get OverlayItems from a database which I want to display in a MapView. If I'm displaying 100 Icons, I have no issues, but if it gets more - like 500 Items in one City - it first looks really bad, while second it slows down a lot. Unfortunately my goal is to display 10000 of them. I think one solution can be to register a listener to ZoomLevels to make them appear/dissapear, but I couldn't find that functionality. Second, I couldn't find a function to scale my Overlays with the Zoom of the Map.
Any Ideas are very welcome
There is a very strange behavior in ItemizedOverlay draw method. When you say: Draw line from (x,y) to (x1,y1) the draw method is called about 20-30-40 times - i don't know why. It is acceptable when you draw one line, but when you draw a thousands of lines,icons and so on...it is very very bad! To solve this problem you should create a cached overlay. This is overlay that catches the first draw, creates the object and then prevents the future draws that do the same draw.
A cluster is a dozen of icons behind one icon. For example if you have 1000 markers on the map, in a specific minimal zoom level you can not see each marker separately - it becomes a mess of icons and colors and so on. And instead of 100 markers that are very very close one by one you place a cluster marker. And on zoom in remove this cluster and create another clusters...do this until the markers became far enough away and you can seen them divided.
Check this: Cluster markers
Take the following approaches:
Create a cached overlay to prevent multiple drawing of same clusters;
Draw in thread;
Cluster your markers depending on zoom level and marker proximity.
Each time you draw in the overlay, check for sure is the current marker inside of the visible part of the screen. If it is not, do no draw it!
I had a similar problem with the icon size and zoom level in my application. What I ended up doing was having 2 sets of overlays containing the markers, one with a "zoomed in" icon and one with a "zoomed out" icon. Then just changed the overlay at a certain zoom level (using a zoom poller - On zoom event for google maps on android)
If a user does a "pinch zoom" on the map, my overlays don't properly size until the end. This has been noted in other posts, so i assume it is a known issue.
Problem is, my client finds it totally unacceptable, as I am tasked with making the android app look as good as the iphone version.
Is there any way to correct this, even if it is a horrible hack? For instance, can I subclass the mapview and handle drawing or override some other method?
The common solution is to not draw overlay during zoom animation.
UPDATED:
Sorry, I've confused zoom and move.
The problem with zoom is that you can't rely on zoom level. Instead you need to draw your overlay based on MapView.getProjection().