mirror of
https://github.com/yeicor-3d/yet-another-cad-viewer.git
synced 2025-12-19 22:24:17 +01:00
optimized build size again (icons & camera)
This commit is contained in:
@@ -11,13 +11,15 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gltf-transform/core": "^3.10.0",
|
"@gltf-transform/core": "^3.10.0",
|
||||||
"@google/model-viewer": "^3.4.0",
|
"@google/model-viewer": "^3.4.0",
|
||||||
|
"@jamescoyle/vue-icon": "^0.1.2",
|
||||||
|
"@mdi/js": "^7.4.47",
|
||||||
|
"@mdi/svg": "^7.4.47",
|
||||||
"three": "^0.160.1",
|
"three": "^0.160.1",
|
||||||
"three-orientation-gizmo": "https://github.com/jrj2211/three-orientation-gizmo",
|
"three-orientation-gizmo": "https://github.com/jrj2211/three-orientation-gizmo",
|
||||||
"vue": "^3.4.16",
|
"vue": "^3.4.16",
|
||||||
"vuetify": "^3.5.3"
|
"vuetify": "^3.5.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@mdi/font": "^7.4.47",
|
|
||||||
"@parcel/optimizer-data-url": "2.11.0",
|
"@parcel/optimizer-data-url": "2.11.0",
|
||||||
"@parcel/reporter-bundle-analyzer": "^2.11.0",
|
"@parcel/reporter-bundle-analyzer": "^2.11.0",
|
||||||
"@parcel/transformer-inline-string": "2.11.0",
|
"@parcel/transformer-inline-string": "2.11.0",
|
||||||
|
|||||||
10
src/App.vue
10
src/App.vue
@@ -1,13 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {defineAsyncComponent, ref, Ref} from "vue";
|
import {defineAsyncComponent, ref, Ref} from "vue";
|
||||||
import Sidebar from "./models/Sidebar.vue";
|
import Sidebar from "./misc/Sidebar.vue";
|
||||||
import Loading from "./viewer/Loading.vue";
|
import Loading from "./misc/Loading.vue";
|
||||||
import ModelViewerOverlay from "./viewer/ModelViewerOverlay.vue";
|
import ModelViewerOverlay from "./viewer/ModelViewerOverlay.vue";
|
||||||
import Tools from "./tools/Tools.vue";
|
import Tools from "./tools/Tools.vue";
|
||||||
import Models from "./models/Models.vue";
|
import Models from "./models/Models.vue";
|
||||||
import {VLayout, VMain, VToolbarTitle} from "vuetify/lib/components";
|
import {VLayout, VMain, VToolbarTitle} from "vuetify/lib/components";
|
||||||
import type {ModelViewerInfo} from "./viewer/ModelViewerWrapper.vue";
|
import type {ModelViewerInfo} from "./viewer/ModelViewerWrapper.vue";
|
||||||
import {settings} from "./tools/settings";
|
import {settings} from "./misc/settings";
|
||||||
|
|
||||||
// NOTE: The ModelViewer library is big (THREE.js), so we split it and import it asynchronously
|
// NOTE: The ModelViewer library is big (THREE.js), so we split it and import it asynchronously
|
||||||
const ModelViewerWrapper = defineAsyncComponent({
|
const ModelViewerWrapper = defineAsyncComponent({
|
||||||
@@ -23,11 +23,13 @@ let modelSrc: Ref<string | Uint8Array> = ref(settings.preloadModels[0]);
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-layout full-height>
|
<v-layout full-height>
|
||||||
|
|
||||||
<!-- The main content of the app is the model-viewer with the SVG "2D" overlay -->
|
<!-- The main content of the app is the model-viewer with the SVG "2D" overlay -->
|
||||||
<v-main id="main">
|
<v-main id="main">
|
||||||
<model-viewer-wrapper :src="modelSrc" @load-viewer="(args) => modelViewerInfo = args"/>
|
<model-viewer-wrapper :src="modelSrc" @load-viewer="(args) => modelViewerInfo = args"/>
|
||||||
<model-viewer-overlay v-if="modelViewerInfo"/>
|
<model-viewer-overlay v-if="modelViewerInfo"/>
|
||||||
</v-main>
|
</v-main>
|
||||||
|
|
||||||
<!-- The left collapsible sidebar has the list of models -->
|
<!-- The left collapsible sidebar has the list of models -->
|
||||||
<sidebar :opened-init="openSidebarsByDefault" side="left">
|
<sidebar :opened-init="openSidebarsByDefault" side="left">
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
@@ -35,6 +37,7 @@ let modelSrc: Ref<string | Uint8Array> = ref(settings.preloadModels[0]);
|
|||||||
</template>
|
</template>
|
||||||
<models :modelViewerInfo="modelViewerInfo"/>
|
<models :modelViewerInfo="modelViewerInfo"/>
|
||||||
</sidebar>
|
</sidebar>
|
||||||
|
|
||||||
<!-- The right collapsible sidebar has the list of tools -->
|
<!-- The right collapsible sidebar has the list of tools -->
|
||||||
<sidebar :opened-init="openSidebarsByDefault" side="right" :width="120">
|
<sidebar :opened-init="openSidebarsByDefault" side="right" :width="120">
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
@@ -42,6 +45,7 @@ let modelSrc: Ref<string | Uint8Array> = ref(settings.preloadModels[0]);
|
|||||||
</template>
|
</template>
|
||||||
<tools :modelViewerInfo="modelViewerInfo"/>
|
<tools :modelViewerInfo="modelViewerInfo"/>
|
||||||
</sidebar>
|
</sidebar>
|
||||||
|
|
||||||
</v-layout>
|
</v-layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,5 @@ const app = createApp(App)
|
|||||||
app.use(vuetify)
|
app.use(vuetify)
|
||||||
app.mount('body')
|
app.mount('body')
|
||||||
|
|
||||||
// Start non-blocking loading of Vuetify and icon styles
|
// Start non-blocking loading of Vuetify styles
|
||||||
import('vuetify/lib/styles/main.sass');
|
import('vuetify/lib/styles/main.sass');
|
||||||
import('@mdi/font/css/materialdesignicons.css');
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref} from "vue";
|
import {ref} from "vue";
|
||||||
import {VBtn, VNavigationDrawer, VToolbar, VToolbarItems} from "vuetify/lib/components";
|
import {VBtn, VNavigationDrawer, VToolbar, VToolbarItems} from "vuetify/lib/components";
|
||||||
|
import {mdiClose, mdiChevronRight, mdiChevronLeft} from '@mdi/js'
|
||||||
|
import SvgIcon from '@jamescoyle/vue-icon';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
openedInit: Boolean,
|
openedInit: Boolean,
|
||||||
@@ -9,22 +11,28 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
|
|
||||||
let opened = ref(props.openedInit);
|
let opened = ref(props.openedInit);
|
||||||
const openIcon = props.side === 'left' ? '$next' : '$prev';
|
const openIcon = props.side === 'left' ? mdiChevronRight : mdiChevronLeft;
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-btn :icon="openIcon" @click="opened = !opened" class="open-button" :class="side"/>
|
<v-btn icon="" @click="opened = !opened" class="open-button" :class="side">
|
||||||
|
<svg-icon type="mdi" :path="openIcon"/>
|
||||||
|
</v-btn>
|
||||||
<v-navigation-drawer v-model="opened" permanent :location="side" :width="props.width">
|
<v-navigation-drawer v-model="opened" permanent :location="side" :width="props.width">
|
||||||
<v-toolbar density="compact">
|
<v-toolbar density="compact">
|
||||||
<v-toolbar-items v-if="side == 'right'">
|
<v-toolbar-items v-if="side == 'right'">
|
||||||
<slot name="toolbar-items"></slot>
|
<slot name="toolbar-items"></slot>
|
||||||
<v-btn icon="$close" @click="opened = !opened"/>
|
<v-btn icon="" @click="opened = !opened">
|
||||||
|
<svg-icon type="mdi" :path="mdiClose"/>
|
||||||
|
</v-btn>
|
||||||
</v-toolbar-items>
|
</v-toolbar-items>
|
||||||
<slot name="toolbar"></slot>
|
<slot name="toolbar"></slot>
|
||||||
<v-toolbar-items v-if="side == 'left'">
|
<v-toolbar-items v-if="side == 'left'">
|
||||||
<slot name="toolbar-items"></slot>
|
<slot name="toolbar-items"></slot>
|
||||||
<v-btn icon="$close" @click="opened = !opened"/>
|
<v-btn icon="" @click="opened = !opened">
|
||||||
|
<svg-icon type="mdi" :path="mdiClose"/>
|
||||||
|
</v-btn>
|
||||||
</v-toolbar-items>
|
</v-toolbar-items>
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
<slot/>
|
<slot/>
|
||||||
@@ -3,16 +3,19 @@ import {VBtn, VIcon} from "vuetify/lib/components";
|
|||||||
import {ref} from "vue";
|
import {ref} from "vue";
|
||||||
import OrientationGizmo from "./OrientationGizmo.vue";
|
import OrientationGizmo from "./OrientationGizmo.vue";
|
||||||
import type {ModelScene} from "@google/model-viewer/lib/three-components/ModelScene";
|
import type {ModelScene} from "@google/model-viewer/lib/three-components/ModelScene";
|
||||||
import {OrthographicCamera} from "three";
|
import {OrthographicCamera} from "three/src/cameras/OrthographicCamera";
|
||||||
|
import {mdiCrosshairsGps, mdiProjector} from '@mdi/js'
|
||||||
|
import SvgIcon from '@jamescoyle/vue-icon';
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelViewerInfo: Object
|
const props = defineProps<{
|
||||||
});
|
modelViewerInfo: { scene: ModelScene } | null
|
||||||
|
}>();
|
||||||
|
|
||||||
|
|
||||||
function syncOrthoCamera(force: boolean) {
|
function syncOrthoCamera(force: boolean) {
|
||||||
if (!props.modelViewerInfo) return;
|
if (!props.modelViewerInfo) return;
|
||||||
let scene: ModelScene = props.modelViewerInfo.scene
|
let scene = props.modelViewerInfo.scene
|
||||||
let perspectiveCam = (scene as any).__perspectiveCamera;
|
let perspectiveCam = (scene as any).__perspectiveCamera;
|
||||||
if (force || perspectiveCam && scene.camera != perspectiveCam) {
|
if (force || perspectiveCam && scene.camera != perspectiveCam) {
|
||||||
// Get zoom level from perspective camera
|
// Get zoom level from perspective camera
|
||||||
@@ -29,7 +32,7 @@ function syncOrthoCamera(force: boolean) {
|
|||||||
let toggleProjectionText = ref('PERSP'); // Default to perspective camera
|
let toggleProjectionText = ref('PERSP'); // Default to perspective camera
|
||||||
function toggleProjection() {
|
function toggleProjection() {
|
||||||
if (!props.modelViewerInfo) return;
|
if (!props.modelViewerInfo) return;
|
||||||
let scene: ModelScene = props.modelViewerInfo.scene
|
let scene = props.modelViewerInfo.scene
|
||||||
let prevCam = scene.camera;
|
let prevCam = scene.camera;
|
||||||
let wasPerspectiveCamera = prevCam.isPerspectiveCamera;
|
let wasPerspectiveCamera = prevCam.isPerspectiveCamera;
|
||||||
if (wasPerspectiveCamera) {
|
if (wasPerspectiveCamera) {
|
||||||
@@ -47,11 +50,15 @@ function toggleProjection() {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<orientation-gizmo v-if="props.modelViewerInfo" :scene="props.modelViewerInfo.scene"/>
|
<orientation-gizmo v-if="props.modelViewerInfo" :scene="props.modelViewerInfo.scene"/>
|
||||||
<v-btn icon="mdi-projector" @click="toggleProjection"><span class="icon-detail">{{ toggleProjectionText }}</span>
|
<v-btn icon="" @click="toggleProjection"><span class="icon-detail">{{ toggleProjectionText }}</span>
|
||||||
<v-icon icon="mdi-projector"></v-icon>
|
<svg-icon type="mdi" :path="mdiProjector"></svg-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-btn icon="" @click=""> <!-- TODO: Center camera -->
|
||||||
|
<svg-icon type="mdi" :path="mdiCrosshairsGps"/>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!--suppress CssUnusedSymbol -->
|
||||||
<style>
|
<style>
|
||||||
.icon-detail {
|
.icon-detail {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -62,7 +69,7 @@ function toggleProjection() {
|
|||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-detail + .v-icon {
|
.icon-detail + svg {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 5px;
|
top: 5px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {settings} from "../tools/settings";
|
import {settings} from "../misc/settings";
|
||||||
import {ModelViewerElement} from '@google/model-viewer';
|
import {ModelViewerElement} from '@google/model-viewer';
|
||||||
import {onMounted, ref} from "vue";
|
import {onMounted, ref} from "vue";
|
||||||
import {$scene} from "@google/model-viewer/lib/model-viewer-base";
|
import {$scene} from "@google/model-viewer/lib/model-viewer-base";
|
||||||
@@ -28,7 +28,6 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!--suppress VueMissingComponentImportInspection -->
|
|
||||||
<model-viewer ref="viewer"
|
<model-viewer ref="viewer"
|
||||||
style="width: 100%; height: 100%" :src="props.src" alt="The 3D model(s)" camera-controls
|
style="width: 100%; height: 100%" :src="props.src" alt="The 3D model(s)" camera-controls
|
||||||
camera-orbit="30deg 75deg auto" max-camera-orbit="Infinity 180deg auto"
|
camera-orbit="30deg 75deg auto" max-camera-orbit="Infinity 180deg auto"
|
||||||
|
|||||||
16
yarn.lock
16
yarn.lock
@@ -44,6 +44,11 @@
|
|||||||
"@monogrid/gainmap-js" "^3.0.1"
|
"@monogrid/gainmap-js" "^3.0.1"
|
||||||
lit "^2.7.2"
|
lit "^2.7.2"
|
||||||
|
|
||||||
|
"@jamescoyle/vue-icon@^0.1.2":
|
||||||
|
version "0.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@jamescoyle/vue-icon/-/vue-icon-0.1.2.tgz#b9e254187de6716b81bf9e0e8400ec012231bd05"
|
||||||
|
integrity sha512-KFrImXx5TKIi6iQXlnyLEBl4rNosNKbTeRnr70ucTdUaciVmd9qK9d/pZAaKt1Ob/8xNnX2GMp8LisyHdKtEgw==
|
||||||
|
|
||||||
"@jridgewell/sourcemap-codec@^1.4.15":
|
"@jridgewell/sourcemap-codec@^1.4.15":
|
||||||
version "1.4.15"
|
version "1.4.15"
|
||||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
|
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
|
||||||
@@ -103,10 +108,15 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.8.5.tgz#8233e8762440b0f4632c47a09b1b6f23de8b934c"
|
resolved "https://registry.yarnpkg.com/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.8.5.tgz#8233e8762440b0f4632c47a09b1b6f23de8b934c"
|
||||||
integrity sha512-4wvrf5BgnR8RpogHhtpCPJMKBmvyZPhhUtEwMJbXh0ni2BucpfF07jlmyM11zRqQ2XIq6PbC2j7W7UCCcm1rRQ==
|
integrity sha512-4wvrf5BgnR8RpogHhtpCPJMKBmvyZPhhUtEwMJbXh0ni2BucpfF07jlmyM11zRqQ2XIq6PbC2j7W7UCCcm1rRQ==
|
||||||
|
|
||||||
"@mdi/font@^7.4.47":
|
"@mdi/js@^7.4.47":
|
||||||
version "7.4.47"
|
version "7.4.47"
|
||||||
resolved "https://registry.yarnpkg.com/@mdi/font/-/font-7.4.47.tgz#2ae522867da3a5c88b738d54b403eb91471903af"
|
resolved "https://registry.yarnpkg.com/@mdi/js/-/js-7.4.47.tgz#7d8a4edc9631bffeed80d1ec784f9beae559a76a"
|
||||||
integrity sha512-43MtGpd585SNzHZPcYowu/84Vz2a2g31TvPMTm9uTiCSWzaheQySUcSyUH/46fPnuPQWof2yd0pGBtzee/IQWw==
|
integrity sha512-KPnNOtm5i2pMabqZxpUz7iQf+mfrYZyKCZ8QNz85czgEt7cuHcGorWfdzUMWYA0SD+a6Hn4FmJ+YhzzzjkTZrQ==
|
||||||
|
|
||||||
|
"@mdi/svg@^7.4.47":
|
||||||
|
version "7.4.47"
|
||||||
|
resolved "https://registry.yarnpkg.com/@mdi/svg/-/svg-7.4.47.tgz#f8e5516aae129764a76d1bb2f27e55bee03e6e90"
|
||||||
|
integrity sha512-WQ2gDll12T9WD34fdRFgQVgO8bag3gavrAgJ0frN4phlwdJARpE6gO1YvLEMJR0KKgoc+/Ea/A0Pp11I00xBvw==
|
||||||
|
|
||||||
"@mischnic/json-sourcemap@^0.1.0":
|
"@mischnic/json-sourcemap@^0.1.0":
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user