-
Notifications
You must be signed in to change notification settings - Fork 6
SceneView: AnalysisOverlayCollection #269
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
935ae8c
c678e65
6545487
6ffd4c2
fe6f3c2
4890151
14348d1
8db6b32
138bb36
5880166
b090235
f86c75b
2ada444
36fc514
9870bd9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,147 @@ | ||||||
/* | ||||||
* Copyright 2023 Esri | ||||||
* | ||||||
* 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 com.arcgismaps.toolkit.geocompose | ||||||
|
||||||
import androidx.compose.runtime.Composable | ||||||
import androidx.compose.runtime.LaunchedEffect | ||||||
import androidx.compose.runtime.Stable | ||||||
import androidx.compose.runtime.remember | ||||||
import com.arcgismaps.mapping.view.AnalysisOverlay | ||||||
import com.arcgismaps.mapping.view.SceneView | ||||||
import kotlinx.coroutines.channels.BufferOverflow | ||||||
import kotlinx.coroutines.flow.MutableSharedFlow | ||||||
import kotlinx.coroutines.flow.SharedFlow | ||||||
import kotlinx.coroutines.flow.asSharedFlow | ||||||
|
||||||
/** | ||||||
* A collection class to encapsulate the [AnalysisOverlay] list used by the [com.arcgismaps.toolkit.geocompose.SceneView] | ||||||
* | ||||||
* @since 200.4.0 | ||||||
*/ | ||||||
@Stable | ||||||
public class AnalysisOverlayCollection : Iterable<AnalysisOverlay> { | ||||||
|
||||||
private val analysisOverlays = mutableListOf<AnalysisOverlay>() | ||||||
|
||||||
private val _changed: MutableSharedFlow<ChangedEvent> = MutableSharedFlow( | ||||||
extraBufferCapacity = Int.MAX_VALUE, | ||||||
onBufferOverflow = BufferOverflow.DROP_OLDEST | ||||||
) | ||||||
|
||||||
/** | ||||||
* [SharedFlow] used to emit changes made to the [analysisOverlays] list | ||||||
*/ | ||||||
internal val changed: SharedFlow<ChangedEvent> = _changed.asSharedFlow() | ||||||
|
||||||
override fun iterator(): Iterator<AnalysisOverlay> { | ||||||
return analysisOverlays.iterator() | ||||||
} | ||||||
|
||||||
/** | ||||||
* Add a [analysisOverlay] to this AnalysisOverlayCollection. | ||||||
* | ||||||
* @return if the add operation succeeds, return true. | ||||||
* @since 200.4.0 | ||||||
*/ | ||||||
public fun add(analysisOverlay: AnalysisOverlay): Boolean { | ||||||
return if (analysisOverlays.add(analysisOverlay)) { | ||||||
_changed.tryEmit(ChangedEvent.Added(analysisOverlay)) | ||||||
true | ||||||
} else false | ||||||
} | ||||||
|
||||||
/** | ||||||
* Remove a [analysisOverlay] from this AnalysisOverlayCollection. | ||||||
* | ||||||
* @return if the remove operation succeeds, return true. | ||||||
* @since 200.4.0 | ||||||
*/ | ||||||
public fun remove(analysisOverlay: AnalysisOverlay): Boolean { | ||||||
return if (analysisOverlays.remove(analysisOverlay)) { | ||||||
_changed.tryEmit(ChangedEvent.Removed(analysisOverlay)) | ||||||
true | ||||||
} else false | ||||||
} | ||||||
|
||||||
/** | ||||||
* Returns the number of analysis overlays in this AnalysisOverlayCollection. | ||||||
* | ||||||
* @since 200.4.0 | ||||||
*/ | ||||||
public val size: Int | ||||||
get() = analysisOverlays.size | ||||||
|
||||||
/** | ||||||
* Clears all analysis overlays from this AnalysisOverlayCollection. | ||||||
* | ||||||
* @since 200.4.0 | ||||||
*/ | ||||||
public fun clear() { | ||||||
analysisOverlays.clear() | ||||||
_changed.tryEmit(ChangedEvent.Cleared) | ||||||
} | ||||||
|
||||||
/** | ||||||
* Sealed class used to notify the compose SceneView to update the AnalysisOverlays on the | ||||||
* type of [ChangedEvent]. | ||||||
* | ||||||
* @since 200.4.0 | ||||||
*/ | ||||||
internal sealed class ChangedEvent() { | ||||||
class Added(val element: AnalysisOverlay) : ChangedEvent() | ||||||
class Removed(val element: AnalysisOverlay) : ChangedEvent() | ||||||
object Cleared : ChangedEvent() | ||||||
} | ||||||
} | ||||||
|
||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. unnecessary newline |
||||||
/** | ||||||
* Update the view-based [geoView]'s analysisOverlays property to reflect changes made to the | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
* [analysisOverlayCollection] based on the type of [AnalysisOverlayCollection.ChangedEvent] | ||||||
* | ||||||
* @since 200.4.0 | ||||||
*/ | ||||||
@Composable | ||||||
internal fun AnalysisOverlaysUpdater( | ||||||
analysisOverlayCollection: AnalysisOverlayCollection, | ||||||
sceneView: SceneView | ||||||
) { | ||||||
LaunchedEffect(analysisOverlayCollection) { | ||||||
// sync up the GeoView with the new graphics overlays | ||||||
sceneView.analysisOverlays.clear() | ||||||
analysisOverlayCollection.forEach { | ||||||
sceneView.analysisOverlays.add(it) | ||||||
} | ||||||
// start observing analysisOverlays for subsequent changes | ||||||
analysisOverlayCollection.changed.collect { changedEvent -> | ||||||
when (changedEvent) { | ||||||
// On AnalysisOverlay added: | ||||||
is AnalysisOverlayCollection.ChangedEvent.Added -> | ||||||
sceneView.analysisOverlays.add(changedEvent.element) | ||||||
|
||||||
// On AnalysisOverlay removed: | ||||||
is AnalysisOverlayCollection.ChangedEvent.Removed -> | ||||||
sceneView.analysisOverlays.remove(changedEvent.element) | ||||||
|
||||||
// On AnalysisOverlays cleared: | ||||||
is AnalysisOverlayCollection.ChangedEvent.Cleared -> | ||||||
sceneView.analysisOverlays.clear() | ||||||
} | ||||||
} | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -66,6 +66,7 @@ import kotlinx.coroutines.launch | |||||
* @param selectionProperties the [SelectionProperties] used by the composable SceneView | ||||||
* @param attributionState specifies the attribution bar's visibility, text changed and layout changed events | ||||||
* @param cameraController the [CameraController] to manage the position, orientation, and movement of the camera | ||||||
* @param analysisOverlays a collection of analysis overlays that render the results of 3D visual analysis on the SceneView | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
* @param timeExtent the [TimeExtent] used by the composable SceneView | ||||||
* @param onTimeExtentChanged lambda invoked when the composable SceneView's [TimeExtent] is changed | ||||||
* @param onNavigationChanged lambda invoked when the navigation status of the composable SceneView has changed | ||||||
|
@@ -97,6 +98,7 @@ public fun SceneView( | |||||
selectionProperties: SelectionProperties = SelectionProperties(), | ||||||
attributionState: AttributionState = AttributionState(), | ||||||
cameraController: CameraController = GlobeCameraController(), | ||||||
analysisOverlays: AnalysisOverlayCollection = rememberAnalysisOverlayCollection(), | ||||||
timeExtent: TimeExtent? = null, | ||||||
onTimeExtentChanged: ((TimeExtent?) -> Unit)? = null, | ||||||
onNavigationChanged: ((isNavigating: Boolean) -> Unit)? = null, | ||||||
|
@@ -148,6 +150,7 @@ public fun SceneView( | |||||
ViewpointUpdater(sceneView, viewpointOperation) | ||||||
|
||||||
GraphicsOverlaysUpdater(graphicsOverlays, sceneView) | ||||||
AnalysisOverlaysUpdater(analysisOverlays, sceneView) | ||||||
|
||||||
AttributionStateHandler(sceneView, attributionState) | ||||||
ViewpointChangedStateHandler(sceneView, viewpointChangedState) | ||||||
|
@@ -304,3 +307,20 @@ private fun SceneViewEventHandler( | |||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
/** | ||||||
* Create and [remember] a [AnalysisOverlayCollection]. | ||||||
* [init] will be called when the [AnalysisOverlayCollection] is first created to configure its | ||||||
* initial state. | ||||||
* | ||||||
* @param key invalidates the remembered AnalysisOverlayCollection if different from the previous composition | ||||||
* @param init called when the [AnalysisOverlayCollection] is created to configure its initial state | ||||||
* @since 200.4.0 | ||||||
*/ | ||||||
@Composable | ||||||
public inline fun rememberAnalysisOverlayCollection( | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To be consistent, should the function be moved into the |
||||||
key: Any? = null, | ||||||
crossinline init: AnalysisOverlayCollection.() -> Unit = {} | ||||||
): AnalysisOverlayCollection = remember(key) { | ||||||
AnalysisOverlayCollection().apply(init) | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove the unused import