separate counts

This commit is contained in:
andrewwallacespeckle
2025-09-04 14:51:38 +01:00
parent 54714362c0
commit dfd304325e
4 changed files with 68 additions and 54 deletions
@@ -1,4 +1,4 @@
import { FilteringExtension, type PropertyInfo, ViewerEvent } from '@speckle/viewer'
import type { PropertyInfo } from '@speckle/viewer'
import { useInjectedViewerState } from '~~/lib/viewer/composables/setup'
import {
ExistenceFilterCondition,
@@ -6,66 +6,15 @@ import {
} from '~/lib/viewer/helpers/filters/types'
/**
* Get count of filtered objects directly from the viewer
* Uses viewer events to stay in sync with the viewer's internal state
* Get count of filtered objects from the viewer state.
*/
export function useFilteredObjectsCount() {
const {
viewer,
ui: { filters }
} = useInjectedViewerState()
const filteredObjectsCount = ref(0)
const updateCount = () => {
const filteringExtension = viewer.instance.getExtension(FilteringExtension)
if (!filteringExtension) return
const isolatedObjects = filteringExtension.filteringState.isolatedObjects
const hasAppliedFilters = filters.propertyFilters.value.some(
(f) =>
f.isApplied &&
(f.selectedValues.length > 0 ||
('isDefaultAllSelected' in f && f.isDefaultAllSelected))
)
if (!hasAppliedFilters) {
filteredObjectsCount.value = 0
return
}
const rawCount = isolatedObjects?.length || 0
// Ghost object that is used to represent objects that don't match the filter
const isGhostOnly = rawCount === 1 && isolatedObjects?.[0] === 'no-match-ghost-all'
if (isGhostOnly) {
filteredObjectsCount.value = 0
return
}
const realObjectCount =
isolatedObjects?.filter((id) => id !== 'no-match-ghost-all').length || 0
filteredObjectsCount.value = realObjectCount
}
onMounted(() => {
const filteringExtension = viewer.instance.getExtension(FilteringExtension)
filteringExtension.on(ViewerEvent.FilteringStateSet, updateCount)
updateCount()
})
onBeforeUnmount(() => {
const filteringExtension = viewer.instance?.getExtension(FilteringExtension)
if (filteringExtension) {
filteringExtension.removeListener(ViewerEvent.FilteringStateSet, updateCount)
}
})
return {
filteredObjectsCount: readonly(filteredObjectsCount)
filteredObjectsCount: readonly(filters.filteredObjectsCount)
}
}
@@ -321,6 +321,7 @@ export type InjectableViewerState = Readonly<{
// Multi-filter system
propertyFilters: Ref<FilterData[]>
filteredObjectsCount: Ref<number>
hasAnyFiltersApplied: ComputedRef<boolean>
activeColorFilterId: Ref<string | null>
}
@@ -1131,6 +1132,7 @@ function setupInterfaceState(
const selectedObjects = shallowRef<Raw<SpeckleObject>[]>([])
const propertyFilters = ref<FilterData[]>([])
const filteredObjectsCount = ref(0)
// Track which filter is currently applying colors (only one at a time)
const activeColorFilterId = ref<string | null>(null)
@@ -1238,6 +1240,7 @@ function setupInterfaceState(
selectedObjectIds,
isolatedObjectsSet,
propertyFilters,
filteredObjectsCount,
hasAnyFiltersApplied,
activeColorFilterId
},
@@ -0,0 +1,60 @@
import { FilteringExtension, ViewerEvent } from '@speckle/viewer'
import { useInjectedViewerState } from '~/lib/viewer/composables/setup'
import { useOnViewerLoadComplete } from '~/lib/viewer/composables/viewer'
/**
* Integration composable that manages filteredObjectsCount in the viewer state.
*/
export const useFilteredObjectsCountPostSetup = () => {
const {
ui: { filters },
viewer: { instance }
} = useInjectedViewerState()
const updateCount = () => {
const filteringExtension = instance.getExtension(FilteringExtension)
if (!filteringExtension) return
const isolatedObjects = filteringExtension.filteringState.isolatedObjects
const hasAppliedFilters = filters.propertyFilters.value.some(
(f) =>
f.isApplied &&
(f.selectedValues.length > 0 ||
('isDefaultAllSelected' in f && f.isDefaultAllSelected))
)
if (!hasAppliedFilters) {
filters.filteredObjectsCount.value = 0
return
}
const rawCount = isolatedObjects?.length || 0
// Ghost object that is used to represent objects that don't match the filter
const isGhostOnly = rawCount === 1 && isolatedObjects?.[0] === 'no-match-ghost-all'
if (isGhostOnly) {
filters.filteredObjectsCount.value = 0
return
}
const realObjectCount =
isolatedObjects?.filter((id) => id !== 'no-match-ghost-all').length || 0
filters.filteredObjectsCount.value = realObjectCount
}
useOnViewerLoadComplete(() => {
const filteringExtension = instance.getExtension(FilteringExtension)
filteringExtension.on(ViewerEvent.FilteringStateSet, updateCount)
updateCount()
})
onBeforeUnmount(() => {
const filteringExtension = instance?.getExtension(FilteringExtension)
if (filteringExtension) {
filteringExtension.removeListener(ViewerEvent.FilteringStateSet, updateCount)
}
})
}
@@ -59,6 +59,7 @@ import { useMeasurementsPostSetup } from '~/lib/viewer/composables/setup/measure
import { useFilterColoringPostSetup } from '~/lib/viewer/composables/setup/coloring'
import { usePropertyFilteringPostSetup } from '~/lib/viewer/composables/setup/propertyFiltering'
import { useManualFilteringPostSetup } from '~/lib/viewer/composables/setup/manualFiltering'
import { useFilteredObjectsCountPostSetup } from '~/lib/viewer/composables/setup/filteredObjectsCount'
import { useFilterUtilities } from '~/lib/viewer/composables/filtering/filtering'
import { cleanupFilteringDataStore } from '~/lib/viewer/composables/filtering/dataStore'
import { cleanupValueGroupCountCache } from '~/lib/viewer/composables/filtering/counts'
@@ -863,6 +864,7 @@ export function useViewerPostSetup() {
useFilterColoringPostSetup()
usePropertyFilteringPostSetup()
useManualFilteringPostSetup()
useFilteredObjectsCountPostSetup()
useDisableZoomOnEmbed()
useViewerCursorIntegration()
useViewerTreeIntegration()