-
Control Panel
+ Levels
-
-
-
-
-
+
+ Get levels
+ Categorize levels
+ Uncategorize levels
+
+
+
+
+
@@ -27,18 +26,33 @@
diff --git a/src/components/SelectionPanel.vue b/src/components/SelectionPanel.vue
new file mode 100644
index 0000000..b5cc554
--- /dev/null
+++ b/src/components/SelectionPanel.vue
@@ -0,0 +1,31 @@
+
+
+
+
+
Selection info
+
+
+
+
+ ID: {{ selectionInfo.id }}
+
+
+ Category: {{ selectionInfo.category }}
+
+
+ Level: {{ selectionInfo.level.name }}
+
+
+
No selection
+
+
+
+
+
+
diff --git a/src/components/SpeckleViewer.vue b/src/components/SpeckleViewer.vue
index f000f13..32d6c94 100644
--- a/src/components/SpeckleViewer.vue
+++ b/src/components/SpeckleViewer.vue
@@ -6,16 +6,23 @@
diff --git a/src/components/icon/IconCog.vue b/src/components/icon/IconCog.vue
deleted file mode 100644
index 85fb9d6..0000000
--- a/src/components/icon/IconCog.vue
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
diff --git a/src/components/ui/BaseButton.vue b/src/components/ui/BaseButton.vue
new file mode 100644
index 0000000..ab55a6f
--- /dev/null
+++ b/src/components/ui/BaseButton.vue
@@ -0,0 +1,5 @@
+
+
+
diff --git a/src/composables/viewer.ts b/src/composables/viewer.ts
new file mode 100644
index 0000000..ce6d5c8
--- /dev/null
+++ b/src/composables/viewer.ts
@@ -0,0 +1,135 @@
+import {
+ CameraController,
+ DefaultViewerParams,
+ SelectionExtension,
+ FilteringExtension,
+ SpeckleLoader,
+ UrlHelper,
+ Viewer,
+ ViewerEvent,
+ type SelectionEvent,
+ type PropertyInfo
+} from '@speckle/viewer'
+import { Catalogue, type CatalogueOptions } from '@/extensions/Catalogue'
+import { ref } from 'vue'
+
+export let viewer: Viewer | undefined = undefined
+export let properties: PropertyInfo[] | undefined = undefined
+
+const selectionInfo = ref(null)
+
+export default function useViewer() {
+ /**
+ * Initialize the viewer
+ * @param element - DOM element to initialize the viewer on
+ */
+ async function init(element: HTMLDivElement) {
+ const params = {
+ ...DefaultViewerParams,
+ showStats: false,
+ verbose: true
+ }
+
+ viewer = new Viewer(element, params)
+ await viewer.init()
+
+ // Get the object properties after the model has loaded
+ // This will cache them and allow faster access later
+ viewer.on(ViewerEvent.LoadComplete, async() => {
+ properties = await viewer.getObjectProperties()
+ })
+
+ // Handle object clicks in the viewer
+ viewer.on(ViewerEvent.ObjectClicked, (event: SelectionEvent | null) => {
+ // If there are no nodes, the click was not on an object
+ if (event) {
+ const nodes = viewer.getWorldTree().findId(event.hits[0].node.model.id)
+ if (nodes && nodes.length > 0) {
+ selectionInfo.value = nodes[0].model.raw
+ }
+ } else {
+ selectionInfo.value = null
+ }
+ })
+ }
+
+ /**
+ * The viewer can be extended with additional functionality by adding extensions
+ * You can use extensions provided by the viewer, or create your own
+ */
+ function addExtensions() {
+ if (!viewer) return
+ viewer.createExtension(CameraController)
+ viewer.createExtension(SelectionExtension)
+ viewer.createExtension(FilteringExtension)
+ viewer.createExtension(Catalogue)
+ }
+
+ /**
+ * Load a model from a Speckle URL
+ * @param url - The URL of the Speckle model
+ * @param authToken - This is required if the model is private
+ */
+ const loadModelFromUrl = async (url: string, authToken?: string) => {
+ const urls = await UrlHelper.getResourceUrls(url, authToken)
+ urls.forEach(async (url) => {
+ if (!viewer) return
+ const loader = new SpeckleLoader(viewer.getWorldTree(), url, '')
+ await viewer.loadObject(loader, true)
+ })
+ }
+
+ /**
+ * Isolate objects in the viewer
+ * @param ids - List of IDs to isolate
+ */
+ const isolate = async (ids: Array
) => {
+ if (!viewer) return
+ const filter = viewer.getExtension(FilteringExtension)
+ filter.resetFilters()
+ filter.isolateObjects(ids)
+ }
+
+ /**
+ * Categorize a certain property in the viewer
+ * @param input - ids to categorize
+ * @param options - options for the catalogue
+ */
+ const categorize = async (
+ input: Array<{ ids: Array; value: string }>,
+ options?: CatalogueOptions
+ ) => {
+ if (!viewer) return
+ const catalogue = viewer.getExtension(Catalogue)
+ catalogue.categorize(input, options)
+ }
+
+ /**
+ * Use the catalogue extension to animate the objects
+ * @param options - option to reverse the animation
+ */
+ const animate = async (options?:{ reverse?: boolean }) => {
+ const { reverse } = options || {}
+ if (!viewer) return
+ const catalogue = viewer.getExtension(Catalogue)
+ catalogue.animate(reverse)
+ }
+
+ // Reset the filtering extension
+ const resetFilters = async () => {
+ if (!viewer) return
+ const filter = viewer.getExtension(FilteringExtension)
+ filter.resetFilters()
+ }
+
+ return {
+ init,
+ loadModelFromUrl,
+ addExtensions,
+ selectionInfo,
+ isolate,
+ categorize,
+ animate,
+ resetFilters
+ }
+}
diff --git a/src/composables/viewer/actions.ts b/src/composables/viewer/actions.ts
deleted file mode 100644
index 23f10de..0000000
--- a/src/composables/viewer/actions.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import useViewer from '@/composables/viewer/viewer'
-import { Catalogue, type CatalogueOptions } from '@/extensions/Catalogue'
-import { FilteringExtension } from '@speckle/viewer'
-import { viewer } from '@/composables/viewer/viewer'
-
-export default function useViewerActions() {
- /**
- * Get the properties of the objects in the viewer
- * The exact properties returned depends on the objects in the viewer
- * @returns - List of properties in the viewer
- */
- const getObjectProperties = async () => {
- console.log(viewer)
- if (!viewer) return
- return await viewer.getObjectProperties()
- }
-
- /**
- * Categorize and animate a certain property in the viewer
- * @param input - ids to categorize
- * @param options - options for the catalogue
- */
- const categorize = async (
- input: Array<{ ids: Array; value: string }>,
- options?: CatalogueOptions
- ) => {
- if (!viewer) return
- const catalogue = viewer.getExtension(Catalogue)
- catalogue.categorize(input, options)
- catalogue.animate()
- }
-
- /**
- * Isolate objects in the viewer
- * @param ids - List of IDs to isolate
- */
- const isolate = async (ids: Array) => {
- if (!viewer) return
- const filter = viewer.getExtension(FilteringExtension)
- filter.isolateObjects(ids)
- }
-
- return {
- getObjectProperties,
- categorize,
- isolate
- }
-}
diff --git a/src/composables/viewer/viewer.ts b/src/composables/viewer/viewer.ts
deleted file mode 100644
index bc9ef1a..0000000
--- a/src/composables/viewer/viewer.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import {
- CameraController,
- DefaultViewerParams,
- SelectionExtension,
- FilteringExtension,
- SpeckleLoader,
- UrlHelper,
- Viewer,
- ViewerEvent
-} from '@speckle/viewer'
-import { Catalogue } from '@/extensions/Catalogue'
-
-export let viewer: Viewer | undefined = undefined
-
-export default function useViewer() {
- /**
- * Initialize the viewer
- * @param element - DOM element to initialize the viewer on
- */
- async function init(element: HTMLDivElement) {
- const params = {
- ...DefaultViewerParams,
- showStats: false,
- verbose: true
- }
-
- viewer = new Viewer(element, params)
- await viewer.init()
-
- viewer.on(ViewerEvent.LoadComplete, async() => {
- const properties = await viewer.getObjectProperties()
- console.log('properties', properties)
-
- // material.value = properties.find(property => property.key === 'renderMaterial.name')
- // console.log('material', material.value)
- })
- }
-
- /**
- * The viewer can be extended with additional functionality by adding extensions
- * You can use extensions provided by the viewer, or create your own
- */
- function addExtensions() {
- if (!viewer) return
- viewer.createExtension(CameraController)
- viewer.createExtension(SelectionExtension)
- viewer.createExtension(FilteringExtension)
- // Example of a custom extension
- viewer.createExtension(Catalogue)
- }
-
- /**
- * Load a model from a Speckle URL
- * @param url - The URL of the Speckle model
- * @param authToken - This is required if the model is private
- */
- const loadModelFromUrl = async (url: string, authToken?: string) => {
- const urls = await UrlHelper.getResourceUrls(url, authToken)
- urls.forEach(async (url) => {
- if (!viewer) return
- const loader = new SpeckleLoader(viewer.getWorldTree(), url, '')
- await viewer.loadObject(loader, true)
- })
- }
-
- return {
- init,
- loadModelFromUrl,
- addExtensions
- }
-}