diff --git a/api/android-for-arcgis.api b/api/android-for-arcgis.api index dc7901e..f9080b7 100644 --- a/api/android-for-arcgis.api +++ b/api/android-for-arcgis.api @@ -115,13 +115,15 @@ public final class com.mapconductor.arcgis.ArcGISGeoViewHolder$DefaultImpls { public final class com.mapconductor.arcgis.ArcGISGraphicsZIndex { public com.mapconductor.arcgis.ArcGISGraphicsZIndex(); public final synchronized void place(com.arcgismaps.mapping.view.Graphic, java.lang.Integer); + public final synchronized void placeAt(com.arcgismaps.mapping.view.Graphic, double); + public final synchronized void replaceAll(kotlin.jvm.functions.Function1); public final synchronized void forget(com.arcgismaps.mapping.view.Graphic); public final synchronized int getSize(); } final class com.mapconductor.arcgis.ArcGISGraphicsZIndex$Entry { public final com.arcgismaps.mapping.view.Graphic getGraphic(); - public final int getZIndex(); - public final void setZIndex(int); + public final double getZIndex(); + public final void setZIndex(double); public final long getSeq(); public final int getRank(); public final void setRank(int); @@ -520,6 +522,7 @@ public final class com.mapconductor.arcgis.marker.ArcGISMarkerRenderer extends c public void setMarkerVisible(com.mapconductor.core.marker.MarkerEntityInterface, boolean); public void setMarkerPosition(com.mapconductor.core.marker.MarkerEntityInterface, com.mapconductor.core.features.GeoPoint); public java.lang.Object onAdd(java.util.List, kotlin.coroutines.Continuation>); + protected java.lang.Object applyDrawOrder(java.util.List>, kotlin.coroutines.Continuation); public java.lang.Object onRemove(java.util.List>, kotlin.coroutines.Continuation); public java.lang.Object onPostProcess(kotlin.coroutines.Continuation); public java.lang.Object onChange(java.util.List>, kotlin.coroutines.Continuation>); diff --git a/src/main/java/com/mapconductor/arcgis/ArcGISGraphicsZIndex.kt b/src/main/java/com/mapconductor/arcgis/ArcGISGraphicsZIndex.kt index 991b8d4..48260fb 100644 --- a/src/main/java/com/mapconductor/arcgis/ArcGISGraphicsZIndex.kt +++ b/src/main/java/com/mapconductor/arcgis/ArcGISGraphicsZIndex.kt @@ -25,7 +25,7 @@ import java.util.IdentityHashMap internal class ArcGISGraphicsZIndex { private class Entry( val graphic: Graphic, - var zIndex: Int, + var zIndex: Double, val seq: Long, var rank: Int, ) @@ -43,8 +43,19 @@ internal class ArcGISGraphicsZIndex { fun place( graphic: Graphic, zIndex: Int?, + ) = placeAt(graphic, (zIndex ?: 0).toDouble()) + + /** + * [graphic] を描く順の値 [order](大きいほど上)の位置に置く。マーカーが使う + * (`MarkerDrawOrder` の値: zIndex が第 1 キー、同じなら南・西が上)。値が同じものの + * 間だけ、最初に渡された順になる。 + */ + @Synchronized + fun placeAt( + graphic: Graphic, + order: Double, ) { - val z = zIndex ?: 0 + val z = order val existing = byGraphic[graphic] val entry = if (existing != null) { @@ -60,6 +71,19 @@ internal class ArcGISGraphicsZIndex { assignRanksFrom(at) } + /** + * 置いている Graphic の値をまとめて付け直す(地図が回ったときのマーカー)。 + * + * 1 つずつ [placeAt] するとずらしが重なるので、並べ替えて順位を振り直す。 + * [orderOf] が null を返した Graphic は値を変えない。 + */ + @Synchronized + fun replaceAll(orderOf: (Graphic) -> Double?) { + entries.forEach { entry -> orderOf(entry.graphic)?.let { entry.zIndex = it } } + entries.sortWith(::compare) + assignRanksFrom(0) + } + /** [graphic] を外す。順位は詰めない(残りの並びはそのまま正しい)。 */ @Synchronized fun forget(graphic: Graphic) { diff --git a/src/main/java/com/mapconductor/arcgis/marker/ArcGISMarkerRenderer.kt b/src/main/java/com/mapconductor/arcgis/marker/ArcGISMarkerRenderer.kt index 6e242e3..1f571cc 100644 --- a/src/main/java/com/mapconductor/arcgis/marker/ArcGISMarkerRenderer.kt +++ b/src/main/java/com/mapconductor/arcgis/marker/ArcGISMarkerRenderer.kt @@ -17,6 +17,7 @@ import com.mapconductor.core.features.GeoPoint import com.mapconductor.core.marker.AbstractMarkerOverlayRenderer import com.mapconductor.core.marker.MarkerEntityInterface import com.mapconductor.core.marker.MarkerOverlayRendererInterface +import java.util.IdentityHashMap import kotlin.math.abs import kotlin.math.cos import kotlin.math.max @@ -132,7 +133,7 @@ class ArcGISMarkerRenderer( it.attributes[BASE_HEIGHT_KEY] = height it.attributes[BASE_OFFSET_Y_KEY] = anchorY.toFloat() } - stackOrder.place(marker, params.state.zIndex) + stackOrder.placeAt(marker, drawOrderOf(params.state)) return@map marker }.also { markerLayer.graphics.addAll(it) @@ -141,6 +142,13 @@ class ArcGISMarkerRenderer( } } + // 地図が回ったら、今ある全マーカーの重なり順を付け直す。 + override suspend fun applyDrawOrder(entities: List>) { + val orders = IdentityHashMap() + entities.forEach { entity -> entity.marker?.let { orders[it] = drawOrderOf(entity.state) } } + withContext(coroutine.coroutineContext) { stackOrder.replaceAll { orders[it] } } + } + override suspend fun onRemove(data: List>) { coroutine.launch { val elements = data.map { params -> params.marker } @@ -211,7 +219,10 @@ class ArcGISMarkerRenderer( marker.geometry = GeoPoint.from(params.current.state.position).toViewPoint() // Always set visibility explicitly like Google Maps (remove conditional check) marker.isVisible = params.current.visible - stackOrder.place(marker, params.current.state.zIndex) + stackOrder.placeAt( + marker, + drawOrderOf(params.current.state), + ) // ArcGISはマーカーを再作成しなくてよいので、同じマーカーのインスタンスを返す marker