I am making a mashup where t开发者_运维知识库humbnails will be shown over a google map.
The problem is that many thumbnails will share the same coordinate. So if I plot them like markers, they will be one on top of the other.
Have you seen any creative solution for this problem? Thanks
Clustering is certainly useful, but it doesn't address the original question - which is how to display markers if they share the same exact coordinates. Google Maps API v3 simply doesn't do that. It just displays one of them.
Clustering solutions suggested by @RedBlueThing do not address this.
There are a couple of options. One was suggested by @Bryan - to do some pre-processing manually, and put descriptive information in the info window for the last marker.
Alternatively - which I prefer - is to pre-process the markers to just ever so slightly (10m or so) alter the coordinates of those that share the same exact location. If you can afford to give up that kind of level of precision. See one such solution here http://techxplorer.com/2010/02/05/managing-markers-with-the-same-coordinates-in-a-google-map/. I have further modified the code - see here https://gist.github.com/873142.
There are a few Javascript libraries that implement Clustering and are very easy to integrate into an existing mashup:
- MarkerClusterer - I used this for a mashup and found it easy to integrate, with a nice set of default icons.
- ClusterMarker - I haven't used this one, but it seems pretty functional.
You can also read this blog post which goes over the various alternatives.
You'll want to look up the term Clustering. You basically just show one marker that indicates there are actually more than one marker at that location. Then at an appropriate zoom level the markers start to appear separately.
If they are at the exact same coordinates and will never diverge, then you will need to implement something that pops-up on the screen when you hover over the clustered marker (like a floating DIV that contains a list of the thumbnails for the person to select/view, or even a context menu where they can right click the cluster and select an individual item)
Use clustering .make group of markers as cluster.one cluster will present many markers inside.
I've got an elegant and beautiful solution:
@Override
public boolean onClusterClick(Cluster<ProfileCardDTO> cluster)
{
if (inProcessOfClick.size() > 0)
{
changeRenderMarkerType(doctorMarkerRenderer.getMarkerType());
for (Polyline line : polylines)
{
line.remove();
}
polylines.clear();
}
boolean same = true;
ProfileCardDTO tmpProfile = null;
for (ProfileCardDTO profile : cluster.getItems())
{
if (tmpProfile != null)
{
if ((Math.abs(Float.parseFloat(tmpProfile.getPractice().getLatitude()) - Float
.parseFloat(profile
.getPractice()
.getLatitude())) > 0.00001f) || (Math.abs(Float.parseFloat(tmpProfile
.getPractice().getLongitude()) - Float.parseFloat(profile
.getPractice()
.getLongitude())) > 0.00001f))
{
same = false;
break;
}
}
tmpProfile = profile;
}
if (zoomLevel >= 12 && same)
{
inProcessOfClick.clear();
int count = cluster.getSize();
double a = 360.0 / count;
double radius = 0.0006;
if (zoomLevel < 17.7)
{
radius = 0.0005;
} else if (zoomLevel < 18.7)
{
radius = 0.0003;
} else if (zoomLevel < 19.7)
{
radius = 0.00015;
} else if (zoomLevel <= 20.7)
{
radius = 0.00007;
} else if (zoomLevel > 20.7)
{
radius = 0.00005;
}
int i = 0;
final long duration = 500;
final long start = SystemClock.uptimeMillis();
final Interpolator interpolator = new LinearInterpolator();
for (ProfileCardDTO profile : cluster.getItems())
{
MarkerOptions mrk = new MarkerOptions();
double x = radius * Math.cos((a * i) / 180 * Math.PI);
double y = radius * Math.sin((a * i) / 180 * Math.PI);
LatLng latLngEnd = new LatLng(profile.getPosition().latitude + x, profile
.getPosition().longitude + y);
LatLng latLngStart = profile.getPosition();
mrk.position(latLngStart);
doctorMarkerRenderer.onBeforeClusterItemRendered(profile, mrk);
Marker tmpMrk = clusterManager.getMarkerCollection().addMarker(mrk);
Handler handler = new Handler();
handler.post(new Runnable()
{
@Override
public void run()
{
long elapsed = SystemClock.uptimeMillis() - start;
if (elapsed > duration)
elapsed = duration;
float t = interpolator.getInterpolation((float) elapsed / duration);
double lng = t * latLngEnd.longitude + (1 - t) * latLngStart.longitude;
double lat = t * latLngEnd.latitude + (1 - t) * latLngStart.latitude;
tmpMrk.setPosition(new LatLng(lat, lng));
if (t < 1.0)
{
handler.postDelayed(this, 10);
} else
{
PolylineOptions line =
new PolylineOptions().add(cluster.getPosition(),
cluster.getPosition(),
latLngEnd,
latLngEnd)
.width(5).color(Color.BLACK);
polylines.add(getGoogleMap().addPolyline(line));
}
}
});
doctorMarkerRenderer.getmMarkerCache().put(profile, tmpMrk);
clusterManager.addItem(profile);
inProcessOfClick.add(profile);
i++;
}
tmpCluster = cluster;
bringMarkerToTop(selectedDoctorMiniProfile);
new Handler().postDelayed(() ->
{
if (doctorMarkerRenderer.getMarker(cluster) != null)
doctorMarkerRenderer.getMarker(cluster).setAlpha(0.5f);
}, 250);
} else
{
LatLngBounds.Builder builder = new LatLngBounds.Builder();
for (ProfileCardDTO profile : cluster.getItems())
{
Practice2 location = profile.getLocation();
LatLng latLng = new LatLng(Double.parseDouble(location.getLatitude()), Double.parseDouble(location
.getLongitude()));
builder.include(latLng);
}
LatLngBounds latLngBounds = builder.build();
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(latLngBounds, getResources().getDimensionPixelSize(R.dimen.map_padding));
getGoogleMap().animateCamera(cameraUpdate, ANIMATE_DURATION_MS, new GoogleMap.CancelableCallback()
{
@Override
public void onFinish()
{
changeRenderMarkerType(doctorMarkerRenderer.getMarkerType());
}
@Override
public void onCancel()
{
}
});
}
return true;
}
Full code of Fragment: https://github.com/master255/MapFragment
精彩评论