使用 osmdroid 根据簇大小更改簇颜色
Changing cluster color based on cluster size using osmdroid
我正在尝试根据簇大小在我的地图上设置不同颜色的簇。
为此,我 subclassed MarkerClusterer 并根据我的要求更改了代码。
代码如下
public class CustomMarkerClusterer extends MarkerClusterer {
protected int mMaxClusteringZoomLevel = 17;
protected int mRadiusInPixels = 100;
protected double mRadiusInMeters;
protected Paint mTextPaint;
private ArrayList<Marker> mClonedMarkers;
private Context context;
/**
* cluster icon anchor
*/
public float mAnchorU = Marker.ANCHOR_CENTER, mAnchorV = Marker.ANCHOR_CENTER;
/**
* anchor point to draw the number of markers inside the cluster icon
*/
public float mTextAnchorU = Marker.ANCHOR_CENTER, mTextAnchorV = Marker.ANCHOR_CENTER;
public CustomMarkerClusterer(Context ctx) {
super();
mTextPaint = new Paint();
mTextPaint.setColor(Color.BLACK);
mTextPaint.setTextSize(15 * ctx.getResources().getDisplayMetrics().density);
mTextPaint.setFakeBoldText(true);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setAntiAlias(true);
this.context = ctx;
Drawable clusterIconD = ctx.getResources().getDrawable(R.drawable.cluster2);
Bitmap clusterIcon = ((BitmapDrawable) clusterIconD).getBitmap();
setIcon(clusterIcon);
}
/**
* If you want to change the default text paint (color, size, font)
*/
public Paint getTextPaint() {
return mTextPaint;
}
/**
* Set the radius of clustering in pixels. Default is 100px.
*/
public void setRadius(int radius) {
mRadiusInPixels = radius;
}
/**
* Set max zoom level with clustering. When zoom is higher or equal to this level, clustering is disabled.
* You can put a high value to disable this feature.
*/
public void setMaxClusteringZoomLevel(int zoom) {
mMaxClusteringZoomLevel = zoom;
}
/**
* Radius-Based clustering algorithm
*/
@Override
public ArrayList<StaticCluster> clusterer(MapView mapView) {
ArrayList<StaticCluster> clusters = new ArrayList<StaticCluster>();
convertRadiusToMeters(mapView);
mClonedMarkers = new ArrayList<Marker>(mItems); //shallow copy
while (!mClonedMarkers.isEmpty()) {
Marker m = mClonedMarkers.get(0);
StaticCluster cluster = createCluster(m, mapView);
clusters.add(cluster);
}
return clusters;
}
private StaticCluster createCluster(Marker m, MapView mapView) {
GeoPoint clusterPosition = m.getPosition();
StaticCluster cluster = new StaticCluster(clusterPosition);
cluster.add(m);
mClonedMarkers.remove(m);
if (mapView.getZoomLevel() > mMaxClusteringZoomLevel) {
//above max level => block clustering:
return cluster;
}
Iterator<Marker> it = mClonedMarkers.iterator();
while (it.hasNext()) {
Marker neighbour = it.next();
double distance = clusterPosition.distanceToAsDouble(neighbour.getPosition());
if (distance <= mRadiusInMeters) {
cluster.add(neighbour);
it.remove();
}
}
return cluster;
}
@Override
public Marker buildClusterMarker(StaticCluster cluster, MapView mapView) {
Marker m = new Marker(mapView);
m.setPosition(cluster.getPosition());
m.setInfoWindow(null);
m.setAnchor(mAnchorU, mAnchorV);
Bitmap mutableBitmap=null;
if (cluster.getSize() < 10) {
Bitmap icon = Bitmap.createBitmap(((BitmapDrawable) context.getResources().getDrawable(R.drawable.cluster1)).getBitmap());
mutableBitmap = icon.copy(Bitmap.Config.ARGB_8888, true);
Canvas iconCanvas = new Canvas(mutableBitmap);
iconCanvas.drawBitmap(mClusterIcon, 0, 0, null);
String text = "" + cluster.getSize();
int textHeight = (int) (mTextPaint.descent() + mTextPaint.ascent());
iconCanvas.drawText(text,
mTextAnchorU * icon.getWidth(),
mTextAnchorV * icon.getHeight() - textHeight / 2,
mTextPaint);
// m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), mutableBitmap));
} else if (cluster.getSize() > 10 && cluster.getSize() < 100) {
Bitmap icon = Bitmap.createBitmap(((BitmapDrawable) context.getResources().getDrawable(R.drawable.cluster3)).getBitmap());
mutableBitmap = icon.copy(Bitmap.Config.ARGB_8888, true);
Canvas iconCanvas = new Canvas(mutableBitmap);
iconCanvas.drawBitmap(mClusterIcon, 0, 0, null);
String text = "" + cluster.getSize();
int textHeight = (int) (mTextPaint.descent() + mTextPaint.ascent());
iconCanvas.drawText(text,
mTextAnchorU * icon.getWidth(),
mTextAnchorV * icon.getHeight() - textHeight / 2,
mTextPaint);
// m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), mutableBitmap));
} else if (cluster.getSize() > 100) {
Bitmap icon = Bitmap.createBitmap(((BitmapDrawable) context.getResources().getDrawable(R.drawable.cluster2)).getBitmap());
mutableBitmap = icon.copy(Bitmap.Config.ARGB_8888, true);
Canvas iconCanvas = new Canvas(mutableBitmap);
iconCanvas.drawBitmap(mClusterIcon, 0, 0, null);
String text = "" + cluster.getSize();
int textHeight = (int) (mTextPaint.descent() + mTextPaint.ascent());
iconCanvas.drawText(text,
mTextAnchorU * icon.getWidth(),
mTextAnchorV * icon.getHeight() - textHeight / 2,
mTextPaint);
// m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), mutableBitmap));
}
m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), mutableBitmap));
return m;
}
@Override
public void renderer(ArrayList<StaticCluster> clusters, Canvas canvas, MapView mapView) {
for (StaticCluster cluster : clusters) {
if (cluster.getSize() == 1) {
//cluster has only 1 marker => use it as it is:
cluster.setMarker(cluster.getItem(0));
} else {
//only draw 1 Marker at Cluster center, displaying number of Markers contained
Marker m = buildClusterMarker(cluster, mapView);
cluster.setMarker(m);
}
}
}
private void convertRadiusToMeters(MapView mapView) {
Rect mScreenRect = mapView.getIntrinsicScreenRect(null);
int screenWidth = mScreenRect.right - mScreenRect.left;
int screenHeight = mScreenRect.bottom - mScreenRect.top;
BoundingBox bb = mapView.getBoundingBox();
double diagonalInMeters = bb.getDiagonalLengthInMeters();
double diagonalInPixels = Math.sqrt(screenWidth * screenWidth + screenHeight * screenHeight);
double metersInPixel = diagonalInMeters / diagonalInPixels;
mRadiusInMeters = mRadiusInPixels * metersInPixel;
}}
buildClusterMarker() 是我尝试根据集群的大小为集群分配不同图像的方法。
当我调试代码时,它工作正常,但它只设置在 class 的构造函数中定义的单色簇。如果我在那里更改图像,它会更改,但对于所有集群。
如果buildClusterMakerMethod()
中的代码有3个类似的分支,这里是第一个:
Bitmap icon = Bitmap.createBitmap(((BitmapDrawable) context.getResources().getDrawable(R.drawable.cluster1)).getBitmap());
mutableBitmap = icon.copy(Bitmap.Config.ARGB_8888, true);
Canvas iconCanvas = new Canvas(mutableBitmap);
iconCanvas.drawBitmap(mClusterIcon, 0, 0, null); //<=== HERE
...
让我们逐行查看代码。
1) 有一个位图从drawable R.drawable.cluster1
创建并存储在icon
变量中。
2) 图标的副本存储在 mutableBitmap
变量中。
3) mutableBitmap
用于创建canvas。这意味着,在 canvas 上执行的所有操作都将绘制到此位图中。
4) 原始图标(存储在 mClusterIcon
文件中)绘制在 canvas over 所需的位图上,然后用icon/bitmap 在构造函数中设置。
所有 3 个分支都会发生这种情况。
您可以删除所有出现的行 (iconCanvas.drawBitmap(mClusterIcon, 0, 0, null);
以解决问题。
我正在尝试根据簇大小在我的地图上设置不同颜色的簇。
为此,我 subclassed MarkerClusterer 并根据我的要求更改了代码。
代码如下
public class CustomMarkerClusterer extends MarkerClusterer {
protected int mMaxClusteringZoomLevel = 17;
protected int mRadiusInPixels = 100;
protected double mRadiusInMeters;
protected Paint mTextPaint;
private ArrayList<Marker> mClonedMarkers;
private Context context;
/**
* cluster icon anchor
*/
public float mAnchorU = Marker.ANCHOR_CENTER, mAnchorV = Marker.ANCHOR_CENTER;
/**
* anchor point to draw the number of markers inside the cluster icon
*/
public float mTextAnchorU = Marker.ANCHOR_CENTER, mTextAnchorV = Marker.ANCHOR_CENTER;
public CustomMarkerClusterer(Context ctx) {
super();
mTextPaint = new Paint();
mTextPaint.setColor(Color.BLACK);
mTextPaint.setTextSize(15 * ctx.getResources().getDisplayMetrics().density);
mTextPaint.setFakeBoldText(true);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setAntiAlias(true);
this.context = ctx;
Drawable clusterIconD = ctx.getResources().getDrawable(R.drawable.cluster2);
Bitmap clusterIcon = ((BitmapDrawable) clusterIconD).getBitmap();
setIcon(clusterIcon);
}
/**
* If you want to change the default text paint (color, size, font)
*/
public Paint getTextPaint() {
return mTextPaint;
}
/**
* Set the radius of clustering in pixels. Default is 100px.
*/
public void setRadius(int radius) {
mRadiusInPixels = radius;
}
/**
* Set max zoom level with clustering. When zoom is higher or equal to this level, clustering is disabled.
* You can put a high value to disable this feature.
*/
public void setMaxClusteringZoomLevel(int zoom) {
mMaxClusteringZoomLevel = zoom;
}
/**
* Radius-Based clustering algorithm
*/
@Override
public ArrayList<StaticCluster> clusterer(MapView mapView) {
ArrayList<StaticCluster> clusters = new ArrayList<StaticCluster>();
convertRadiusToMeters(mapView);
mClonedMarkers = new ArrayList<Marker>(mItems); //shallow copy
while (!mClonedMarkers.isEmpty()) {
Marker m = mClonedMarkers.get(0);
StaticCluster cluster = createCluster(m, mapView);
clusters.add(cluster);
}
return clusters;
}
private StaticCluster createCluster(Marker m, MapView mapView) {
GeoPoint clusterPosition = m.getPosition();
StaticCluster cluster = new StaticCluster(clusterPosition);
cluster.add(m);
mClonedMarkers.remove(m);
if (mapView.getZoomLevel() > mMaxClusteringZoomLevel) {
//above max level => block clustering:
return cluster;
}
Iterator<Marker> it = mClonedMarkers.iterator();
while (it.hasNext()) {
Marker neighbour = it.next();
double distance = clusterPosition.distanceToAsDouble(neighbour.getPosition());
if (distance <= mRadiusInMeters) {
cluster.add(neighbour);
it.remove();
}
}
return cluster;
}
@Override
public Marker buildClusterMarker(StaticCluster cluster, MapView mapView) {
Marker m = new Marker(mapView);
m.setPosition(cluster.getPosition());
m.setInfoWindow(null);
m.setAnchor(mAnchorU, mAnchorV);
Bitmap mutableBitmap=null;
if (cluster.getSize() < 10) {
Bitmap icon = Bitmap.createBitmap(((BitmapDrawable) context.getResources().getDrawable(R.drawable.cluster1)).getBitmap());
mutableBitmap = icon.copy(Bitmap.Config.ARGB_8888, true);
Canvas iconCanvas = new Canvas(mutableBitmap);
iconCanvas.drawBitmap(mClusterIcon, 0, 0, null);
String text = "" + cluster.getSize();
int textHeight = (int) (mTextPaint.descent() + mTextPaint.ascent());
iconCanvas.drawText(text,
mTextAnchorU * icon.getWidth(),
mTextAnchorV * icon.getHeight() - textHeight / 2,
mTextPaint);
// m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), mutableBitmap));
} else if (cluster.getSize() > 10 && cluster.getSize() < 100) {
Bitmap icon = Bitmap.createBitmap(((BitmapDrawable) context.getResources().getDrawable(R.drawable.cluster3)).getBitmap());
mutableBitmap = icon.copy(Bitmap.Config.ARGB_8888, true);
Canvas iconCanvas = new Canvas(mutableBitmap);
iconCanvas.drawBitmap(mClusterIcon, 0, 0, null);
String text = "" + cluster.getSize();
int textHeight = (int) (mTextPaint.descent() + mTextPaint.ascent());
iconCanvas.drawText(text,
mTextAnchorU * icon.getWidth(),
mTextAnchorV * icon.getHeight() - textHeight / 2,
mTextPaint);
// m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), mutableBitmap));
} else if (cluster.getSize() > 100) {
Bitmap icon = Bitmap.createBitmap(((BitmapDrawable) context.getResources().getDrawable(R.drawable.cluster2)).getBitmap());
mutableBitmap = icon.copy(Bitmap.Config.ARGB_8888, true);
Canvas iconCanvas = new Canvas(mutableBitmap);
iconCanvas.drawBitmap(mClusterIcon, 0, 0, null);
String text = "" + cluster.getSize();
int textHeight = (int) (mTextPaint.descent() + mTextPaint.ascent());
iconCanvas.drawText(text,
mTextAnchorU * icon.getWidth(),
mTextAnchorV * icon.getHeight() - textHeight / 2,
mTextPaint);
// m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), mutableBitmap));
}
m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), mutableBitmap));
return m;
}
@Override
public void renderer(ArrayList<StaticCluster> clusters, Canvas canvas, MapView mapView) {
for (StaticCluster cluster : clusters) {
if (cluster.getSize() == 1) {
//cluster has only 1 marker => use it as it is:
cluster.setMarker(cluster.getItem(0));
} else {
//only draw 1 Marker at Cluster center, displaying number of Markers contained
Marker m = buildClusterMarker(cluster, mapView);
cluster.setMarker(m);
}
}
}
private void convertRadiusToMeters(MapView mapView) {
Rect mScreenRect = mapView.getIntrinsicScreenRect(null);
int screenWidth = mScreenRect.right - mScreenRect.left;
int screenHeight = mScreenRect.bottom - mScreenRect.top;
BoundingBox bb = mapView.getBoundingBox();
double diagonalInMeters = bb.getDiagonalLengthInMeters();
double diagonalInPixels = Math.sqrt(screenWidth * screenWidth + screenHeight * screenHeight);
double metersInPixel = diagonalInMeters / diagonalInPixels;
mRadiusInMeters = mRadiusInPixels * metersInPixel;
}}
buildClusterMarker() 是我尝试根据集群的大小为集群分配不同图像的方法。
当我调试代码时,它工作正常,但它只设置在 class 的构造函数中定义的单色簇。如果我在那里更改图像,它会更改,但对于所有集群。
如果buildClusterMakerMethod()
中的代码有3个类似的分支,这里是第一个:
Bitmap icon = Bitmap.createBitmap(((BitmapDrawable) context.getResources().getDrawable(R.drawable.cluster1)).getBitmap());
mutableBitmap = icon.copy(Bitmap.Config.ARGB_8888, true);
Canvas iconCanvas = new Canvas(mutableBitmap);
iconCanvas.drawBitmap(mClusterIcon, 0, 0, null); //<=== HERE
...
让我们逐行查看代码。
1) 有一个位图从drawable R.drawable.cluster1
创建并存储在icon
变量中。
2) 图标的副本存储在 mutableBitmap
变量中。
3) mutableBitmap
用于创建canvas。这意味着,在 canvas 上执行的所有操作都将绘制到此位图中。
4) 原始图标(存储在 mClusterIcon
文件中)绘制在 canvas over 所需的位图上,然后用icon/bitmap 在构造函数中设置。
所有 3 个分支都会发生这种情况。
您可以删除所有出现的行 (iconCanvas.drawBitmap(mClusterIcon, 0, 0, null);
以解决问题。