/*
* Copyright (C) 2013 Maciej Górski
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package pl.mg6.android.maps.extensions;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.support.v4.util.LruCache;
import com.google.android.gms.R;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import java.util.List;
public class DefaultClusterOptionsProvider implements ClusterOptionsProvider {
private final LruCache<Integer, BitmapDescriptor> cache = new LruCache<Integer, BitmapDescriptor>(128);
private final ClusterOptions clusterOptions = new ClusterOptions().anchor(0.5f, 0.5f);
private final int[] colors;
private final Paint circlePaint;
private final Paint circleShadowPaint;
private final Paint textPaint;
private final Rect bounds = new Rect();
private float blurRadius;
private float textPadding;
private float shadowBlurRadius;
private float shadowOffsetX;
private float shadowOffsetY;
public DefaultClusterOptionsProvider(Resources resources) {
colors = new int[] {
resources.getColor(R.color.ame_default_cluster_circle_color_small),
resources.getColor(R.color.ame_default_cluster_circle_color_medium),
resources.getColor(R.color.ame_default_cluster_circle_color_large),
resources.getColor(R.color.ame_default_cluster_circle_color_extra_large),
};
circlePaint = createCirclePaint(resources);
circleShadowPaint = createCircleShadowPaint(resources);
textPaint = createTextPaint(resources);
textPadding = resources.getDimension(R.dimen.ame_default_cluster_text_padding);
}
private Paint createCirclePaint(Resources resources) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
blurRadius = resources.getDimension(R.dimen.ame_default_cluster_circle_blur_radius);
if (blurRadius > 0.0f) {
BlurMaskFilter maskFilter = new BlurMaskFilter(blurRadius, BlurMaskFilter.Blur.SOLID);
paint.setMaskFilter(maskFilter);
}
return paint;
}
private Paint createCircleShadowPaint(Resources resources) {
Paint paint = null;
float circleShadowBlurRadius = resources.getDimension(R.dimen.ame_default_cluster_circle_shadow_blur_radius);
if (circleShadowBlurRadius > 0.0f) {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
float offsetX = resources.getDimension(R.dimen.ame_default_cluster_circle_shadow_offset_x);
float offsetY = resources.getDimension(R.dimen.ame_default_cluster_circle_shadow_offset_y);
int color = resources.getColor(R.color.ame_default_cluster_circle_shadow_color);
paint.setShadowLayer(circleShadowBlurRadius, offsetX, offsetY, color);
}
return paint;
}
private Paint createTextPaint(Resources resources) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(resources.getColor(R.color.ame_default_cluster_text_color));
shadowBlurRadius = resources.getDimension(R.dimen.ame_default_cluster_text_shadow_blur_radius);
if (shadowBlurRadius > 0.0f) {
shadowOffsetX = resources.getDimension(R.dimen.ame_default_cluster_text_shadow_offset_x);
shadowOffsetY = resources.getDimension(R.dimen.ame_default_cluster_text_shadow_offset_y);
int shadowColor = resources.getColor(R.color.ame_default_cluster_text_shadow_color);
paint.setShadowLayer(shadowBlurRadius, shadowOffsetX, shadowOffsetY, shadowColor);
}
paint.setTextSize(resources.getDimension(R.dimen.ame_default_cluster_text_size));
paint.setTypeface(Typeface.DEFAULT_BOLD);
return paint;
}
@Override
public ClusterOptions getClusterOptions(List<Marker> markers) {
int count = markers.size();
BitmapDescriptor icon = cache.get(count);
if (icon == null) {
icon = createIcon(count);
cache.put(count, icon);
}
clusterOptions.icon(icon);
return clusterOptions;
}
private BitmapDescriptor createIcon(int count) {
String text = String.valueOf(count);
calculateTextSize(text);
int iconSize = calculateIconSize();
Bitmap bitmap = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawCircle(canvas, count, iconSize);
drawText(canvas, text, iconSize);
return BitmapDescriptorFactory.fromBitmap(bitmap);
}
private void calculateTextSize(String text) {
textPaint.getTextBounds(text, 0, text.length(), bounds);
}
private int calculateIconSize() {
int w = bounds.width();
int h = bounds.height();
return (int) Math.ceil(2 * (textPadding + blurRadius) + Math.sqrt(w * w + h * h));
}
private void drawCircle(Canvas canvas, int count, float iconSize) {
canvas.drawCircle(iconSize / 2, iconSize / 2, iconSize / 2 - blurRadius, circleShadowPaint);
for (int i = colors.length - 1; i >= 0; i--) {
if (count >= Math.pow(10, i)) {
circlePaint.setColor(colors[i]);
break;
}
}
canvas.drawCircle(iconSize / 2, iconSize / 2, iconSize / 2 - blurRadius, circlePaint);
}
private void drawText(Canvas canvas, String text, int iconSize) {
int x = Math.round((iconSize - bounds.width()) / 2 - bounds.left - shadowOffsetX / 2);
int y = Math.round((iconSize - bounds.height()) / 2 - bounds.top - shadowOffsetY / 2);
canvas.drawText(text, x, y, textPaint);
}
}