package com.hiringhall.map import android.graphics.* import android.support.annotation.ColorInt import android.support.v4.content.ContextCompat import android.util.TypedValue import com.facebook.react.uimanager.ThemedReactContext import com.google.android.gms.maps.MapView import com.hiringhall.R import com.squareup.picasso.Picasso import java.io.IOException /** * Created by saionara1 on 8/1/17. */ class MarkerDrawingManager(val context: ThemedReactContext?, val mapView: MapView) { companion object { const val PIN_ASPECT = 1.3f; } private val BITMAP_CONFIG: Bitmap.Config = Bitmap.Config.ARGB_8888 private val TEXT_PADDING_X_PX = 15f private val TEXT_PADDING_Y_PX = 20f private val RELATIVE_TEXT_SIZE = 0.38f private var PROFESSION_COLORS: IntArray val RADIUS_MARGIN = 1.15 val MARKER_DEFAULT_SIZE = 36 private val mPin = BitmapFactory.decodeResource(context?.resources, R.drawable.ic_pin_yellow) private val textBounds = Rect() private val markerBackgroundPaint = Paint() private val textPaint = Paint() private val iconBackgroundPaint = Paint() private val bitmapTintPaint = Paint() private var circlePaint = Paint() private var whiteFilter: PorterDuffColorFilter private var blackFilter: PorterDuffColorFilter init { markerBackgroundPaint.color = ContextCompat.getColor(context, R.color.brand_yellow); markerBackgroundPaint.isAntiAlias = true; iconBackgroundPaint.isDither = true; iconBackgroundPaint.style = Paint.Style.FILL; iconBackgroundPaint.isAntiAlias = true; iconBackgroundPaint.isDither = true; circlePaint.isAntiAlias = true; bitmapTintPaint.isAntiAlias = true; bitmapTintPaint.isFilterBitmap = true; bitmapTintPaint.isDither = true; PROFESSION_COLORS = context?.resources!!.getIntArray(R.array.profession_colors) whiteFilter = PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP); blackFilter = PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.SRC_ATOP); } private fun drawIcon(canvas: Canvas, cx: Int, cy: Int, iconUrl: String, radius: Int, clicked: Boolean) { try { iconTarget.onLoaded = { bitmapTintPaint.colorFilter = if (clicked) blackFilter else whiteFilter canvas.drawBitmap(it, null, RectF((cx - radius).toFloat(), (cy - radius).toFloat(), (cx + radius).toFloat(), (cy + radius).toFloat()), bitmapTintPaint) } Picasso.with(mapView.context).load(iconUrl).into(iconTarget) } catch (e: IOException) { // ignore } } @ColorInt private fun getProfessionColor(name: String): Int { return PROFESSION_COLORS[Math.abs(name.hashCode()) % PROFESSION_COLORS.size] } private fun drawText(canvas: Canvas, topMargin: Int, centerX: Int, textBounds: Rect, text: String, selected: Boolean?) { textPaint.color = Color.BLACK val left = centerX - textBounds.width() / 2f val right = centerX + textBounds.width() / 2f val top = topMargin.toFloat() val bottom = top + textBounds.height() val rect = RectF(left - TEXT_PADDING_X_PX, top - TEXT_PADDING_Y_PX, right + TEXT_PADDING_X_PX, bottom + TEXT_PADDING_Y_PX) canvas.drawRoundRect(rect, 5f, 5f, markerBackgroundPaint) canvas.drawText(text, // Text to display centerX - textBounds.width() / 2f, (topMargin + textBounds.height()).toFloat(), textPaint ) } private fun measureText(outBounds: Rect, text: String, paint: Paint) { val textBounds = Rect() paint.getTextBounds(text, 0, text.length, textBounds) outBounds.set(0, 0, paint.measureText(text).toInt(), textBounds.height()) } fun drawJobMarker(iconUrl: String, jobRate: String, profession: String, clicked: Boolean): Bitmap { val rateString = jobRate val professionName = profession val rate = java.lang.Float.parseFloat(rateString) val text = "$rate/hr" val requestedSideSize = dpToPx(MARKER_DEFAULT_SIZE); markerBackgroundPaint.color = ContextCompat .getColor(mapView.context, if (clicked) R.color.feed_blue else R.color.brand_yellow) textPaint.textSize = requestedSideSize * RELATIVE_TEXT_SIZE measureText(textBounds, text, textPaint) val width = Math.max(textBounds.width() + TEXT_PADDING_X_PX.toInt() * 2, requestedSideSize) val height = requestedSideSize + textBounds.height() + TEXT_PADDING_Y_PX.toInt() * 2 val bitmap = Bitmap.createBitmap(width, height, BITMAP_CONFIG) val canvas = Canvas(bitmap) val radius = requestedSideSize / 2 @ColorInt val circleColor = if (clicked) ContextCompat.getColor(mapView.context, R.color.brand_yellow) else getProfessionColor(professionName) iconBackgroundPaint.color = circleColor circlePaint.color = circleColor val yellowCircleRadius = (radius * RADIUS_MARGIN).toInt() val cx = width / 2 val cy = yellowCircleRadius drawColorCircle(canvas, cx, cy, yellowCircleRadius, markerBackgroundPaint) drawText(canvas, (requestedSideSize * 1.1).toInt(), cx, textBounds, text, clicked) drawColorCircle(canvas, cx, cy, radius, iconBackgroundPaint) drawIcon(canvas, cx, cy, iconUrl, radius, clicked) return bitmap } fun drawWorkerMarker(iconUrl: String, name: String, profession: String, clicked: Boolean): Bitmap { val requestedSideSize = dpToPx(if (clicked) 48 else 30) val pinWidth = (requestedSideSize * 1.2).toInt() val pinHeight = (pinWidth * PIN_ASPECT).toInt() val text = name val radius = requestedSideSize / 2 textPaint.setTextSize(requestedSideSize * RELATIVE_TEXT_SIZE) measureText(textBounds, text, textPaint) val width = if (clicked) Math.max(textBounds.width() + TEXT_PADDING_X_PX.toInt() * 2, requestedSideSize) else pinWidth val height = Math.max(pinHeight, requestedSideSize + textBounds.height() + TEXT_PADDING_Y_PX.toInt() * 2) val bitmap = Bitmap.createBitmap(width, height, BITMAP_CONFIG) val canvas = Canvas(bitmap) val yellowCircleRadius = (radius * RADIUS_MARGIN).toInt() val cx = width / 2 val cy = yellowCircleRadius @ColorInt val color = if (clicked) ContextCompat.getColor(context, R.color.brand_yellow) else getProfessionColor(profession) iconBackgroundPaint.setColor(color) markerBackgroundPaint.setColor(ContextCompat.getColor(context, if (clicked) R.color.feed_blue else R.color.brand_yellow)) if (clicked) { drawColorCircle(canvas, cx, cy, (radius * RADIUS_MARGIN).toInt(), markerBackgroundPaint) drawText(canvas, (requestedSideSize * 1.1).toInt(), cx, textBounds, text, true) } else { val pin = Bitmap.createScaledBitmap(mPin, pinWidth, pinHeight, true) canvas.drawBitmap(pin, 0f, 0f, markerBackgroundPaint) } drawColorCircle(canvas, cx, cy, radius, iconBackgroundPaint) drawIcon(canvas, cx, cy, iconUrl, radius, clicked) return bitmap } private fun dpToPx(sizeDp: Int): Int { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, sizeDp.toFloat(), mapView.context.resources.getDisplayMetrics()).toInt() } private fun drawColorCircle(canvas: Canvas, cx: Int, cy: Int, radius: Int, paint: Paint) { canvas.drawCircle(cx.toFloat(), cy.toFloat(), radius.toFloat(), paint) } }