From bf44ead2778f9a067debe539062a39c17cdca470 Mon Sep 17 00:00:00 2001 From: Mike Tasset Date: Thu, 14 Nov 2024 06:45:23 +0000 Subject: [PATCH] Clean up code, added comments, styled UI --- src/App.vue | 2 + src/assets/SpeckleViewer2.vue | 110 ------------------------ src/components/ControlPanel.vue | 62 ++++++++------ src/components/SelectionPanel.vue | 31 +++++++ src/components/SpeckleViewer.vue | 21 +++-- src/components/icon/IconCog.vue | 21 ----- src/components/ui/BaseButton.vue | 5 ++ src/composables/viewer.ts | 135 ++++++++++++++++++++++++++++++ src/composables/viewer/actions.ts | 48 ----------- src/composables/viewer/viewer.ts | 71 ---------------- 10 files changed, 225 insertions(+), 281 deletions(-) delete mode 100644 src/assets/SpeckleViewer2.vue create mode 100644 src/components/SelectionPanel.vue delete mode 100644 src/components/icon/IconCog.vue create mode 100644 src/components/ui/BaseButton.vue create mode 100644 src/composables/viewer.ts delete mode 100644 src/composables/viewer/actions.ts delete mode 100644 src/composables/viewer/viewer.ts diff --git a/src/App.vue b/src/App.vue index 64705cd..3211bb1 100644 --- a/src/App.vue +++ b/src/App.vue @@ -2,10 +2,12 @@
+
diff --git a/src/assets/SpeckleViewer2.vue b/src/assets/SpeckleViewer2.vue deleted file mode 100644 index 5e5d0ae..0000000 --- a/src/assets/SpeckleViewer2.vue +++ /dev/null @@ -1,110 +0,0 @@ - - - diff --git a/src/components/ControlPanel.vue b/src/components/ControlPanel.vue index a8d42b5..6f74f6b 100644 --- a/src/components/ControlPanel.vue +++ b/src/components/ControlPanel.vue @@ -1,25 +1,24 @@ 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 @@ + + + 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 - } -}