feat(fe): preserveSelectionHighlightFilter
feat(fe): preserveSelectionHighlightFilter
This commit is contained in:
@@ -95,10 +95,6 @@ import { useFilterUtilities } from '~/lib/viewer/composables/filtering/filtering
|
||||
import { useFilterColoringHelpers } from '~/lib/viewer/composables/filtering/coloringHelpers'
|
||||
import type { FilterData } from '~/lib/viewer/helpers/filters/types'
|
||||
import { FilterType } from '~/lib/viewer/helpers/filters/types'
|
||||
import {
|
||||
useHighlightedObjectsUtilities,
|
||||
useSelectionUtilities
|
||||
} from '~/lib/viewer/composables/ui'
|
||||
|
||||
const props = defineProps<{
|
||||
filter: FilterData
|
||||
@@ -112,8 +108,6 @@ const { removeActiveFilter, toggleFilterApplied, getPropertyName, filters } =
|
||||
useFilterUtilities()
|
||||
|
||||
const { toggleColorFilter } = useFilterColoringHelpers()
|
||||
const { clearHighlightedObjects } = useHighlightedObjectsUtilities()
|
||||
const { clearSelection } = useSelectionUtilities()
|
||||
|
||||
const emit = defineEmits<{
|
||||
swapProperty: [filterId: string]
|
||||
@@ -124,8 +118,6 @@ const isColoringActive = computed(() => {
|
||||
})
|
||||
|
||||
const removeFilter = () => {
|
||||
clearHighlightedObjects()
|
||||
clearSelection()
|
||||
removeActiveFilter(props.filter.id)
|
||||
}
|
||||
|
||||
@@ -134,8 +126,6 @@ const toggleVisibility = () => {
|
||||
}
|
||||
|
||||
const toggleColors = () => {
|
||||
clearHighlightedObjects()
|
||||
clearSelection()
|
||||
toggleColorFilter(props.filter.id)
|
||||
}
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ const { hideObjects, showObjects, isolateObjects, unIsolateObjects } =
|
||||
const { zoom } = useCameraUtilities()
|
||||
const { items } = useInjectedViewerRequestedResources()
|
||||
const { resourceItems } = useInjectedViewerLoadedResources()
|
||||
const { addToSelectionFromObjectIds, clearSelection } = useSelectionUtilities()
|
||||
const { addToSelectionFromObjectIds } = useSelectionUtilities()
|
||||
|
||||
const {
|
||||
viewer: {
|
||||
@@ -313,7 +313,6 @@ const handleClick = () => {
|
||||
if (!props.isExpanded) {
|
||||
emit('toggle-expansion')
|
||||
} else {
|
||||
clearSelection()
|
||||
addToSelectionFromObjectIds(modelObjectIds.value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import type { FilterData } from '~/lib/viewer/helpers/filters/types'
|
||||
import type { SpeckleObject } from '@speckle/viewer'
|
||||
import type { Raw } from 'vue'
|
||||
import { FilteringExtension } from '@speckle/viewer'
|
||||
import { FilteringExtension, SelectionExtension } from '@speckle/viewer'
|
||||
import { watchTriggerable } from '@vueuse/core'
|
||||
import { useInjectedViewerState } from '~/lib/viewer/composables/setup'
|
||||
import { useOnViewerLoadComplete } from '~/lib/viewer/composables/viewer'
|
||||
import { useFilteringDataStore } from '~/lib/viewer/composables/filtering/dataStore'
|
||||
import { HighlightExtension } from '~/lib/viewer/composables/setup/highlighting'
|
||||
|
||||
/**
|
||||
* Setup composable for filter-related state
|
||||
@@ -61,6 +62,39 @@ export const useManualFilteringPostSetup = () => {
|
||||
|
||||
const filteringExtension = () => instance.getExtension(FilteringExtension)
|
||||
|
||||
/**
|
||||
* Preserve selection and highlighting state during filtering operations
|
||||
* This replicates LegacyViewer's preserveSelectionHighlightFilter function
|
||||
*/
|
||||
const preserveSelectionHighlightFilter = <T>(filterFn: () => T): T => {
|
||||
const selectionExtension = instance.getExtension(SelectionExtension)
|
||||
const highlightExtension = instance.getExtension(HighlightExtension)
|
||||
|
||||
// 1. SAVE current state from viewer extensions
|
||||
const selectedObjects = selectionExtension
|
||||
.getSelectedObjects()
|
||||
.map((obj) => obj.id as string)
|
||||
const highlightedObjects =
|
||||
highlightExtension?.getSelectedObjects().map((obj) => obj.id as string) || []
|
||||
|
||||
// 2. CLEAR viewer extensions directly
|
||||
if (selectedObjects.length) selectionExtension.clearSelection()
|
||||
if (highlightedObjects.length && highlightExtension) {
|
||||
highlightExtension.clearSelection()
|
||||
}
|
||||
|
||||
// 3. EXECUTE the filtering operation
|
||||
const result = filterFn()
|
||||
|
||||
// 4. RESTORE to viewer extensions directly
|
||||
if (selectedObjects.length) selectionExtension.selectObjects(selectedObjects)
|
||||
if (highlightedObjects.length && highlightExtension) {
|
||||
highlightExtension.selectObjects(highlightedObjects)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch for changes to manually isolated object IDs
|
||||
*/
|
||||
@@ -69,17 +103,19 @@ export const useManualFilteringPostSetup = () => {
|
||||
(newIds, oldIds) => {
|
||||
if (!newIds || !oldIds) return
|
||||
|
||||
const extension = filteringExtension()
|
||||
preserveSelectionHighlightFilter(() => {
|
||||
const extension = filteringExtension()
|
||||
|
||||
const toIsolate = newIds.filter((id) => !oldIds.includes(id))
|
||||
if (toIsolate.length > 0) {
|
||||
extension.isolateObjects(toIsolate, 'manual-isolation', true, true)
|
||||
}
|
||||
const toIsolate = newIds.filter((id) => !oldIds.includes(id))
|
||||
if (toIsolate.length > 0) {
|
||||
extension.isolateObjects(toIsolate, 'manual-isolation', true, true)
|
||||
}
|
||||
|
||||
const toUnIsolate = oldIds.filter((id) => !newIds.includes(id))
|
||||
if (toUnIsolate.length > 0) {
|
||||
extension.unIsolateObjects(toUnIsolate, 'manual-isolation', true, true)
|
||||
}
|
||||
const toUnIsolate = oldIds.filter((id) => !newIds.includes(id))
|
||||
if (toUnIsolate.length > 0) {
|
||||
extension.unIsolateObjects(toUnIsolate, 'manual-isolation', true, true)
|
||||
}
|
||||
})
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
@@ -92,17 +128,19 @@ export const useManualFilteringPostSetup = () => {
|
||||
(newIds, oldIds) => {
|
||||
if (!newIds || !oldIds) return
|
||||
|
||||
const extension = filteringExtension()
|
||||
preserveSelectionHighlightFilter(() => {
|
||||
const extension = filteringExtension()
|
||||
|
||||
const toHide = newIds.filter((id) => !oldIds.includes(id))
|
||||
if (toHide.length > 0) {
|
||||
extension.hideObjects(toHide, 'manual-hiding', false, false)
|
||||
}
|
||||
const toHide = newIds.filter((id) => !oldIds.includes(id))
|
||||
if (toHide.length > 0) {
|
||||
extension.hideObjects(toHide, 'manual-hiding', false, false)
|
||||
}
|
||||
|
||||
const toShow = oldIds.filter((id) => !newIds.includes(id))
|
||||
if (toShow.length > 0) {
|
||||
extension.showObjects(toShow, 'manual-hiding', false)
|
||||
}
|
||||
const toShow = oldIds.filter((id) => !newIds.includes(id))
|
||||
if (toShow.length > 0) {
|
||||
extension.showObjects(toShow, 'manual-hiding', false)
|
||||
}
|
||||
})
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
@@ -15,7 +15,7 @@ import { ViewerRenderPageType } from '~/lib/viewer/helpers/state'
|
||||
* Highlighting extension that replicates LegacyViewer's HighlightExtension
|
||||
* Uses SelectionExtension but disables default events for UI-only highlighting
|
||||
*/
|
||||
class HighlightExtension extends SelectionExtension {
|
||||
export class HighlightExtension extends SelectionExtension {
|
||||
public constructor(viewer: IViewer, cameraProvider: CameraController) {
|
||||
super(viewer, cameraProvider)
|
||||
|
||||
@@ -51,20 +51,16 @@ export const useHighlightingPostSetup = () => {
|
||||
|
||||
if (pageType.value === ViewerRenderPageType.Presentation) return
|
||||
|
||||
const highlightExtension = ref<HighlightExtension | null>(null)
|
||||
// Create the highlighting extension once during setup
|
||||
instance.createExtension(HighlightExtension)
|
||||
|
||||
// Get the highlighting extension instance
|
||||
const getHighlightExtension = () => {
|
||||
if (!highlightExtension.value) {
|
||||
highlightExtension.value = instance.createExtension(HighlightExtension)
|
||||
}
|
||||
return highlightExtension.value
|
||||
}
|
||||
const getHighlightExtensionInstance = () => instance.getExtension(HighlightExtension)
|
||||
|
||||
useOnViewerLoadComplete(
|
||||
({ isInitial }) => {
|
||||
if (!isInitial) return
|
||||
getHighlightExtension()
|
||||
getHighlightExtensionInstance()
|
||||
},
|
||||
{ initialOnly: true }
|
||||
)
|
||||
@@ -73,7 +69,7 @@ export const useHighlightingPostSetup = () => {
|
||||
watch(
|
||||
highlightedObjectIds,
|
||||
(newIds, oldIds) => {
|
||||
const extension = getHighlightExtension()
|
||||
const extension = getHighlightExtensionInstance()
|
||||
if (!extension) return
|
||||
|
||||
// Clear all current highlights if new list is empty
|
||||
@@ -83,8 +79,6 @@ export const useHighlightingPostSetup = () => {
|
||||
}
|
||||
|
||||
if (oldIds && isEqual(newIds, oldIds)) return
|
||||
|
||||
// Clear and re-select to avoid accumulation
|
||||
extension.clearSelection()
|
||||
if (newIds.length > 0) {
|
||||
extension.selectObjects(newIds)
|
||||
|
||||
@@ -67,7 +67,10 @@ import {
|
||||
} from '~/lib/viewer/composables/setup/filters'
|
||||
import { useFilterUtilities } from '~/lib/viewer/composables/filtering/filtering'
|
||||
import { useFilteringSetup } from '~/lib/viewer/composables/filtering/setup'
|
||||
import { useHighlightingPostSetup } from '~/lib/viewer/composables/setup/highlighting'
|
||||
import {
|
||||
useHighlightingPostSetup,
|
||||
HighlightExtension
|
||||
} from '~/lib/viewer/composables/setup/highlighting'
|
||||
|
||||
function useViewerLoadCompleteEventHandler() {
|
||||
const state = useInjectedViewerState()
|
||||
@@ -566,12 +569,25 @@ function useViewerFiltersIntegration() {
|
||||
).filter(isNonNullable)
|
||||
if (arraysEqual(newIds, oldIds)) return
|
||||
|
||||
state.ui.highlightedObjectIds.value = []
|
||||
|
||||
const selectionExtension = instance.getExtension(SelectionExtension)
|
||||
const currentViewerSelection = selectionExtension
|
||||
.getSelectedObjects()
|
||||
.map((obj) => obj.id as string)
|
||||
|
||||
if (
|
||||
currentViewerSelection.length === newIds.length &&
|
||||
difference(currentViewerSelection, newIds).length === 0
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
state.ui.highlightedObjectIds.value = []
|
||||
const highlightExtension = instance.getExtension(HighlightExtension)
|
||||
if (highlightExtension) {
|
||||
highlightExtension.clearSelection()
|
||||
}
|
||||
|
||||
selectionExtension.clearSelection()
|
||||
|
||||
if (newVal.length > 0) {
|
||||
selectionExtension.selectObjects(newIds)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user