Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e73d392013 | |||
| dd7f3fe95d | |||
| fdcc1f2cef | |||
| 5e2f108e49 | |||
| df334e95a2 | |||
| ce733d1ced |
@@ -89,6 +89,9 @@
|
||||
"properties": {
|
||||
"defaultViewMode": {
|
||||
"type": { "text": true }
|
||||
},
|
||||
"navbarHidden": {
|
||||
"type": { "bool": true }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Generated
+5
-4
@@ -5367,9 +5367,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001689",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001689.tgz",
|
||||
"integrity": "sha512-CmeR2VBycfa+5/jOfnp/NpWPGd06nf1XYiefUvhXFfZE4GkRc9jv+eGPS4nT558WS/8lYCzV8SlANCIPvbWP1g==",
|
||||
"version": "1.0.30001726",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001726.tgz",
|
||||
"integrity": "sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -5383,7 +5383,8 @@
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
]
|
||||
],
|
||||
"license": "CC-BY-4.0"
|
||||
},
|
||||
"node_modules/chai": {
|
||||
"version": "5.1.2",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="border">
|
||||
<transition name="slide-fade">
|
||||
<nav
|
||||
v-show="!isNavbarCollapsed"
|
||||
v-show="!visualStore.isNavbarHidden"
|
||||
class="fixed top-0 h-9 flex items-center bg-foundation border border-outline-2 w-full transition z-20 cursor-default"
|
||||
>
|
||||
<div class="flex items-center transition-all justify-between w-full">
|
||||
@@ -46,7 +46,7 @@
|
||||
<button
|
||||
class="text-gray-400 hover:text-gray-700 transition"
|
||||
title="Hide navbar"
|
||||
@click="isNavbarCollapsed = true"
|
||||
@click="visualStore.toggleNavbar()"
|
||||
>
|
||||
<ChevronUpIcon class="w-4 h-4" />
|
||||
</button>
|
||||
@@ -58,17 +58,17 @@
|
||||
<div
|
||||
v-if="!isInteractive"
|
||||
class="absolute left-1/2 -translate-x-1/2 z-20 bg-white bg-opacity-70 text-black text-center text-xs px-4 py-1 rounded shadow font-medium cursor-default transition-all duration-300"
|
||||
:class="isNavbarCollapsed ? 'top-1' : 'top-11'"
|
||||
:class="visualStore.isNavbarHidden ? 'top-1' : 'top-11'"
|
||||
>
|
||||
<strong>Object IDs</strong>
|
||||
field is needed for interactivity with other visuals.
|
||||
</div>
|
||||
|
||||
<div v-if="isNavbarCollapsed" class="fixed top-0 right-0 z-20">
|
||||
<div v-if="visualStore.isNavbarHidden" class="fixed top-0 right-0 z-20">
|
||||
<button
|
||||
class="transition opacity-50 hover:opacity-100"
|
||||
title="Show navbar"
|
||||
@click="isNavbarCollapsed = false"
|
||||
@click="visualStore.toggleNavbar()"
|
||||
>
|
||||
<ChevronDownIcon class="w-4 h-4 text-gray-400" />
|
||||
</button>
|
||||
@@ -76,7 +76,7 @@
|
||||
|
||||
<transition name="slide-left">
|
||||
<ViewerControls
|
||||
v-show="!isNavbarCollapsed"
|
||||
v-show="!visualStore.isNavbarHidden"
|
||||
v-model:section-box="bboxActive"
|
||||
:views="views"
|
||||
class="fixed top-11 left-2 z-30"
|
||||
@@ -152,8 +152,6 @@ const container = ref<HTMLElement>()
|
||||
let bboxActive = ref(false)
|
||||
let views: Ref<SpeckleView[]> = ref([])
|
||||
|
||||
const isNavbarCollapsed = ref(false)
|
||||
|
||||
const isInteractive = computed(
|
||||
() => visualStore.fieldInputState.rootObjectId && visualStore.fieldInputState.objectIds
|
||||
)
|
||||
|
||||
@@ -52,6 +52,7 @@ export interface IViewerEvents {
|
||||
toggleProjection: () => void
|
||||
toggleGhostHidden: (ghost: boolean) => void
|
||||
loadObjects: (objects: object[]) => void
|
||||
objectsLoaded: () => void
|
||||
}
|
||||
|
||||
export type ColorBy = {
|
||||
@@ -81,6 +82,7 @@ export class ViewerHandler {
|
||||
this.emitter.on('zoomExtends', this.zoomExtends)
|
||||
this.emitter.on('zoomObjects', this.zoomObjects)
|
||||
this.emitter.on('loadObjects', this.loadObjects)
|
||||
this.emitter.on('objectsLoaded', this.handleObjectsLoaded)
|
||||
this.emitter.on('toggleProjection', this.toggleProjection)
|
||||
this.emitter.on('toggleGhostHidden', this.toggleGhostHidden)
|
||||
}
|
||||
@@ -219,7 +221,8 @@ export class ViewerHandler {
|
||||
const store = useVisualStore()
|
||||
const speckleViews = []
|
||||
|
||||
modelObjects.forEach(async (objects) => {
|
||||
// Use for...of loop to properly handle async operations
|
||||
for (const objects of modelObjects) {
|
||||
//@ts-ignore
|
||||
const loader = new SpeckleObjectsOfflineLoader(this.viewer.getWorldTree(), objects)
|
||||
|
||||
@@ -232,7 +235,7 @@ export class ViewerHandler {
|
||||
// Since you are setting another camera position, maybe you want the second argument to false
|
||||
await this.viewer.loadObject(loader, true)
|
||||
this.viewer.getRenderer().shadowcatcher.shadowcatcherMesh.visible = false // works fine only right after loadObjects
|
||||
})
|
||||
}
|
||||
|
||||
store.setSpeckleViews(speckleViews)
|
||||
if (store.defaultViewModeInFile) {
|
||||
@@ -257,12 +260,22 @@ export class ViewerHandler {
|
||||
)
|
||||
this.cameraControls.setCameraView({ position, target }, true)
|
||||
}
|
||||
|
||||
// Emit objects loaded event to trigger update
|
||||
this.emit('objectsLoaded')
|
||||
}
|
||||
|
||||
private handlePing = (message: string) => {
|
||||
console.log(message)
|
||||
}
|
||||
|
||||
private handleObjectsLoaded = () => {
|
||||
console.log('🎯 Objects loaded - triggering update')
|
||||
const store = useVisualStore()
|
||||
// Handle state restoration after objects are loaded
|
||||
store.handleObjectsLoadedComplete()
|
||||
}
|
||||
|
||||
private pickViewableHit(hits: Hit[]): Hit | null {
|
||||
// The current filtering state
|
||||
const filteringState = this.filtering.filteringState
|
||||
|
||||
@@ -35,6 +35,7 @@ export const useVisualStore = defineStore('visualStore', () => {
|
||||
const isBrandingHidden = ref<boolean>(false)
|
||||
const isOrthoProjection = ref<boolean>(false)
|
||||
const isGhostActive = ref<boolean>(true)
|
||||
const isNavbarHidden = ref<boolean>(false)
|
||||
|
||||
const commonError = ref<string>(undefined)
|
||||
|
||||
@@ -168,7 +169,13 @@ export const useVisualStore = defineStore('visualStore', () => {
|
||||
} else {
|
||||
isFilterActive.value = false
|
||||
latestColorBy.value = dataInput.value.colorByIds
|
||||
viewerEmit.value('resetFilter', dataInput.value.objectIds, isGhostActive.value)
|
||||
// Only apply filtering if object IDs are available, otherwise show all objects normally
|
||||
if (fieldInputState.value.objectIds && dataInput.value.objectIds && dataInput.value.objectIds.length > 0) {
|
||||
viewerEmit.value('resetFilter', dataInput.value.objectIds, isGhostActive.value)
|
||||
} else {
|
||||
// No object IDs provided - show all objects without any filtering
|
||||
viewerEmit.value('unIsolateObjects')
|
||||
}
|
||||
}
|
||||
viewerEmit.value('colorObjectsByGroup', dataInput.value.colorByIds)
|
||||
}
|
||||
@@ -272,6 +279,22 @@ export const useVisualStore = defineStore('visualStore', () => {
|
||||
})
|
||||
}
|
||||
|
||||
const writeNavbarVisibilityToFile = (navbarHidden: boolean) => {
|
||||
// NOTE: need skipping the update function, it resets the viewer state unneccessarily.
|
||||
postFileSaveSkipNeeded.value = true
|
||||
host.value.persistProperties({
|
||||
merge: [
|
||||
{
|
||||
objectName: 'viewMode',
|
||||
properties: {
|
||||
navbarHidden: navbarHidden
|
||||
},
|
||||
selector: null
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
const writeCameraPositionToFile = (position: Vector3, target: Vector3) => {
|
||||
// NOTE: need skipping the update function, it resets the viewer state unneccessarily.
|
||||
postFileSaveSkipNeeded.value = true
|
||||
@@ -313,6 +336,15 @@ export const useVisualStore = defineStore('visualStore', () => {
|
||||
isBrandingHidden.value = val
|
||||
}
|
||||
|
||||
const setNavbarHidden = (val: boolean) => {
|
||||
isNavbarHidden.value = val
|
||||
}
|
||||
|
||||
const toggleNavbar = () => {
|
||||
isNavbarHidden.value = !isNavbarHidden.value
|
||||
writeNavbarVisibilityToFile(isNavbarHidden.value)
|
||||
}
|
||||
|
||||
const setIsOrthoProjection = (val: boolean) => {
|
||||
isOrthoProjection.value = val
|
||||
}
|
||||
@@ -332,7 +364,13 @@ export const useVisualStore = defineStore('visualStore', () => {
|
||||
(formattingSettings.value = newFormattingSettings)
|
||||
|
||||
const resetFilters = () => {
|
||||
viewerEmit.value('resetFilter', dataInput.value.objectIds, isGhostActive.value)
|
||||
// Only apply filtering if object IDs are available, otherwise show all objects normally
|
||||
if (fieldInputState.value.objectIds && dataInput.value && dataInput.value.objectIds && dataInput.value.objectIds.length > 0) {
|
||||
viewerEmit.value('resetFilter', dataInput.value.objectIds, isGhostActive.value)
|
||||
} else {
|
||||
// No object IDs provided - show all objects without any filtering
|
||||
viewerEmit.value('unIsolateObjects')
|
||||
}
|
||||
if (latestColorBy.value !== null) {
|
||||
viewerEmit.value('colorObjectsByGroup', latestColorBy.value)
|
||||
}
|
||||
@@ -347,6 +385,37 @@ export const useVisualStore = defineStore('visualStore', () => {
|
||||
commonError.value = error
|
||||
}
|
||||
|
||||
const handleObjectsLoadedComplete = () => {
|
||||
console.log('🔄 Objects loaded - handling state restoration')
|
||||
|
||||
// If we have current data input with selections, restore them
|
||||
if (dataInput.value) {
|
||||
console.log('🔄 Restoring selection state after object load')
|
||||
|
||||
// Restore selection filters if they exist
|
||||
if (dataInput.value.selectedIds.length > 0) {
|
||||
isFilterActive.value = true
|
||||
viewerEmit.value('filterSelection', dataInput.value.selectedIds, isGhostActive.value)
|
||||
} else {
|
||||
isFilterActive.value = false
|
||||
latestColorBy.value = dataInput.value.colorByIds
|
||||
// Only apply filtering if object IDs are available, otherwise show all objects normally
|
||||
if (fieldInputState.value.objectIds && dataInput.value.objectIds && dataInput.value.objectIds.length > 0) {
|
||||
viewerEmit.value('resetFilter', dataInput.value.objectIds, isGhostActive.value)
|
||||
} else {
|
||||
// No object IDs provided - show all objects without any filtering
|
||||
viewerEmit.value('unIsolateObjects')
|
||||
}
|
||||
}
|
||||
|
||||
// Restore color grouping
|
||||
viewerEmit.value('colorObjectsByGroup', dataInput.value.colorByIds)
|
||||
}
|
||||
|
||||
// Trigger host data refresh to synchronize with Power BI
|
||||
host.value.refreshHostData()
|
||||
}
|
||||
|
||||
return {
|
||||
host,
|
||||
receiveInfo,
|
||||
@@ -373,6 +442,7 @@ export const useVisualStore = defineStore('visualStore', () => {
|
||||
isBrandingHidden,
|
||||
isOrthoProjection,
|
||||
isGhostActive,
|
||||
isNavbarHidden,
|
||||
latestAvailableVersion,
|
||||
isConnectorUpToDate,
|
||||
commonError,
|
||||
@@ -382,6 +452,7 @@ export const useVisualStore = defineStore('visualStore', () => {
|
||||
setIsGhost,
|
||||
setFormattingSettings,
|
||||
setBrandingHidden,
|
||||
setNavbarHidden,
|
||||
setPostClickSkipNeeded,
|
||||
setPostFileSaveSkipNeeded,
|
||||
setCameraPositionInFile,
|
||||
@@ -399,7 +470,9 @@ export const useVisualStore = defineStore('visualStore', () => {
|
||||
writeViewModeToFile,
|
||||
writeCameraPositionToFile,
|
||||
writeHideBrandingToFile,
|
||||
writeNavbarVisibilityToFile,
|
||||
toggleBranding,
|
||||
toggleNavbar,
|
||||
setViewerEmitter,
|
||||
setDataInput,
|
||||
setFieldInputState,
|
||||
@@ -409,6 +482,7 @@ export const useVisualStore = defineStore('visualStore', () => {
|
||||
clearLoadingProgress,
|
||||
setIsLoadingFromFile,
|
||||
resetFilters,
|
||||
downloadLatestVersion
|
||||
downloadLatestVersion,
|
||||
handleObjectsLoadedComplete
|
||||
}
|
||||
})
|
||||
|
||||
@@ -148,6 +148,18 @@ export class Visual implements IVisual {
|
||||
)
|
||||
}
|
||||
|
||||
if (options.dataViews[0].metadata.objects.viewMode?.navbarHidden as boolean) {
|
||||
console.log(
|
||||
`Navbar Hidden: ${
|
||||
options.dataViews[0].metadata.objects.viewMode?.navbarHidden as boolean
|
||||
}`
|
||||
)
|
||||
|
||||
visualStore.setNavbarHidden(
|
||||
options.dataViews[0].metadata.objects.viewMode?.navbarHidden as boolean
|
||||
)
|
||||
}
|
||||
|
||||
if (options.dataViews[0].metadata.objects.cameraPosition?.positionX as string) {
|
||||
console.log(`Stored camera position is found`)
|
||||
visualStore.setCameraPositionInFile([
|
||||
|
||||
Reference in New Issue
Block a user