@@ -6,9 +6,11 @@ import android.graphics.Color
66import android.graphics.Matrix
77import android.graphics.Paint
88import android.graphics.RectF
9+ import android.graphics.Typeface
910import android.text.TextPaint
1011import android.text.TextUtils
1112import android.util.TypedValue
13+ import androidx.core.graphics.ColorUtils
1214import org.osmdroid.views.Projection
1315
1416internal class MarkerAnnotationRenderer (context : Context ) {
@@ -19,15 +21,20 @@ internal class MarkerAnnotationRenderer(context: Context) {
1921 val screenBounds : RectF
2022 )
2123
22- private val labelTextPaint = TextPaint (Paint .ANTI_ALIAS_FLAG ).apply {
24+ private val fillTextPaint = TextPaint (Paint .ANTI_ALIAS_FLAG ).apply {
2325 textSize = TypedValue .applyDimension(TypedValue .COMPLEX_UNIT_SP , 12f , context.resources.displayMetrics)
24- color = Color .BLACK
2526 textAlign = Paint .Align .CENTER
27+ typeface = Typeface .create(Typeface .DEFAULT , Typeface .BOLD )
2628 }
2729
28- private val backgroundPaint = Paint (Paint .ANTI_ALIAS_FLAG ).apply {
29- color = Color .WHITE
30- alpha = 220
30+ private val haloTextPaint = TextPaint (Paint .ANTI_ALIAS_FLAG ).apply {
31+ textSize = TypedValue .applyDimension(TypedValue .COMPLEX_UNIT_SP , 12f , context.resources.displayMetrics)
32+ textAlign = Paint .Align .CENTER
33+ style = Paint .Style .STROKE
34+ strokeWidth = TypedValue .applyDimension(TypedValue .COMPLEX_UNIT_DIP , 1.5f , context.resources.displayMetrics)
35+ strokeJoin = Paint .Join .ROUND
36+ strokeCap = Paint .Cap .ROUND
37+ typeface = Typeface .create(Typeface .DEFAULT , Typeface .BOLD )
3138 }
3239
3340 private val backgroundRect = RectF ()
@@ -40,12 +47,13 @@ internal class MarkerAnnotationRenderer(context: Context) {
4047 private val paddingHPx = 4f * density
4148 private val paddingVPx = 2f * density
4249 private val gapPx = 2f * density
43- private val cornerRadiusPx = 3f * density
50+ private val haloStrokeWidth = haloTextPaint.strokeWidth
4451
4552 private val futureIconSlotWidth = 0f
4653 private val iconTextGap = 4f * density
4754
4855 private var cachedLabelText: String? = null
56+ private var cachedMarkerColor: Int? = null
4957 private var cachedDisplayText = " "
5058 private var cachedTextWidth = 0f
5159 private var cachedTextHeight = 0f
@@ -71,9 +79,9 @@ internal class MarkerAnnotationRenderer(context: Context) {
7179 if (text == cachedLabelText) return
7280
7381 cachedLabelText = text
74- cachedDisplayText = TextUtils .ellipsize(text, labelTextPaint , maxLabelWidthPx, TextUtils .TruncateAt .END ).toString()
75- cachedTextWidth = labelTextPaint .measureText(cachedDisplayText)
76- labelTextPaint .getFontMetrics(cachedFontMetrics)
82+ cachedDisplayText = TextUtils .ellipsize(text, fillTextPaint , maxLabelWidthPx, TextUtils .TruncateAt .END ).toString()
83+ cachedTextWidth = fillTextPaint .measureText(cachedDisplayText)
84+ fillTextPaint .getFontMetrics(cachedFontMetrics)
7785 cachedTextHeight = cachedFontMetrics.descent - cachedFontMetrics.ascent
7886
7987 cachedContentWidth = if (cachedTextWidth > 0 && futureIconSlotWidth > 0 ) {
@@ -86,8 +94,24 @@ internal class MarkerAnnotationRenderer(context: Context) {
8694 cachedAnnotationHeight = cachedTextHeight + paddingVPx * 2
8795 }
8896
89- fun draw (canvas : Canvas , pj : Projection , x : Float , y : Float , text : String , iconHeight : Int , anchorV : Float , viewWidth : Int , viewHeight : Int ) {
97+ private fun updateColors (markerColor : Int ) {
98+ if (markerColor == cachedMarkerColor) return
99+ cachedMarkerColor = markerColor
100+ fillTextPaint.color = markerColor
101+ haloTextPaint.color = haloColorFor(markerColor)
102+ }
103+
104+ internal fun haloColorFor (markerColor : Int ): Int {
105+ return if (ColorUtils .calculateLuminance(markerColor) > 0.65 ) {
106+ Color .argb(210 , 32 , 32 , 32 )
107+ } else {
108+ Color .argb(230 , 255 , 255 , 255 )
109+ }
110+ }
111+
112+ fun draw (canvas : Canvas , pj : Projection , x : Float , y : Float , text : String , textColor : Int , iconHeight : Int , anchorV : Float , viewWidth : Int , viewHeight : Int ) {
90113 updateCache(text)
114+ updateColors(textColor)
91115
92116 val annotationBottomY = y - iconHeight * anchorV - gapPx
93117 val annotationLeft = x - cachedAnnotationWidth / 2
@@ -98,11 +122,12 @@ internal class MarkerAnnotationRenderer(context: Context) {
98122 // Rotation matrix
99123 annotationMatrix.setRotate(- pj.orientation, x, y)
100124
101- // Calculate transformed bounds for clamping
102- cornerPoints[0 ] = backgroundRect.left; cornerPoints[1 ] = backgroundRect.top
103- cornerPoints[2 ] = backgroundRect.right; cornerPoints[3 ] = backgroundRect.top
104- cornerPoints[4 ] = backgroundRect.right; cornerPoints[5 ] = backgroundRect.bottom
105- cornerPoints[6 ] = backgroundRect.left; cornerPoints[7 ] = backgroundRect.bottom
125+ // Calculate transformed bounds for clamping, including halo stroke
126+ val haloAllowance = haloStrokeWidth / 2f
127+ cornerPoints[0 ] = backgroundRect.left - haloAllowance; cornerPoints[1 ] = backgroundRect.top - haloAllowance
128+ cornerPoints[2 ] = backgroundRect.right + haloAllowance; cornerPoints[3 ] = backgroundRect.top - haloAllowance
129+ cornerPoints[4 ] = backgroundRect.right + haloAllowance; cornerPoints[5 ] = backgroundRect.bottom + haloAllowance
130+ cornerPoints[6 ] = backgroundRect.left - haloAllowance; cornerPoints[7 ] = backgroundRect.bottom + haloAllowance
106131
107132 annotationMatrix.mapPoints(transformedPoints, cornerPoints)
108133
@@ -140,12 +165,14 @@ internal class MarkerAnnotationRenderer(context: Context) {
140165 canvas.save()
141166 canvas.concat(annotationMatrix)
142167
143- canvas.drawRoundRect(backgroundRect, cornerRadiusPx, cornerRadiusPx, backgroundPaint)
168+ // canvas.drawRoundRect(backgroundRect, cornerRadiusPx, cornerRadiusPx, backgroundPaint) // Removed bubble
144169
145170 val textStartX = annotationLeft + paddingHPx + futureIconSlotWidth + (if (futureIconSlotWidth > 0 && cachedTextWidth > 0 ) iconTextGap else 0f )
146171 val textX = textStartX + cachedTextWidth / 2
147172 val textY = annotationTop + paddingVPx - cachedFontMetrics.ascent
148- canvas.drawText(cachedDisplayText, textX, textY, labelTextPaint)
173+
174+ canvas.drawText(cachedDisplayText, textX, textY, haloTextPaint)
175+ canvas.drawText(cachedDisplayText, textX, textY, fillTextPaint)
149176
150177 canvas.restore()
151178 isDrawn = true
0 commit comments