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": {
|
||||
"@gltf-transform/core": "^3.10.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-orientation-gizmo": "https://github.com/jrj2211/three-orientation-gizmo",
|
||||
"vue": "^3.4.16",
|
||||
"vuetify": "^3.5.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mdi/font": "^7.4.47",
|
||||
"@parcel/optimizer-data-url": "2.11.0",
|
||||
"@parcel/reporter-bundle-analyzer": "^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">
|
||||
import {defineAsyncComponent, ref, Ref} from "vue";
|
||||
import Sidebar from "./models/Sidebar.vue";
|
||||
import Loading from "./viewer/Loading.vue";
|
||||
import Sidebar from "./misc/Sidebar.vue";
|
||||
import Loading from "./misc/Loading.vue";
|
||||
import ModelViewerOverlay from "./viewer/ModelViewerOverlay.vue";
|
||||
import Tools from "./tools/Tools.vue";
|
||||
import Models from "./models/Models.vue";
|
||||
import {VLayout, VMain, VToolbarTitle} from "vuetify/lib/components";
|
||||
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
|
||||
const ModelViewerWrapper = defineAsyncComponent({
|
||||
@@ -23,11 +23,13 @@ let modelSrc: Ref<string | Uint8Array> = ref(settings.preloadModels[0]);
|
||||
|
||||
<template>
|
||||
<v-layout full-height>
|
||||
|
||||
<!-- The main content of the app is the model-viewer with the SVG "2D" overlay -->
|
||||
<v-main id="main">
|
||||
<model-viewer-wrapper :src="modelSrc" @load-viewer="(args) => modelViewerInfo = args"/>
|
||||
<model-viewer-overlay v-if="modelViewerInfo"/>
|
||||
</v-main>
|
||||
|
||||
<!-- The left collapsible sidebar has the list of models -->
|
||||
<sidebar :opened-init="openSidebarsByDefault" side="left">
|
||||
<template #toolbar>
|
||||
@@ -35,6 +37,7 @@ let modelSrc: Ref<string | Uint8Array> = ref(settings.preloadModels[0]);
|
||||
</template>
|
||||
<models :modelViewerInfo="modelViewerInfo"/>
|
||||
</sidebar>
|
||||
|
||||
<!-- The right collapsible sidebar has the list of tools -->
|
||||
<sidebar :opened-init="openSidebarsByDefault" side="right" :width="120">
|
||||
<template #toolbar>
|
||||
@@ -42,6 +45,7 @@ let modelSrc: Ref<string | Uint8Array> = ref(settings.preloadModels[0]);
|
||||
</template>
|
||||
<tools :modelViewerInfo="modelViewerInfo"/>
|
||||
</sidebar>
|
||||
|
||||
</v-layout>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -21,6 +21,5 @@ const app = createApp(App)
|
||||
app.use(vuetify)
|
||||
app.mount('body')
|
||||
|
||||
// Start non-blocking loading of Vuetify and icon styles
|
||||
import('vuetify/lib/styles/main.sass');
|
||||
import('@mdi/font/css/materialdesignicons.css');
|
||||
// Start non-blocking loading of Vuetify styles
|
||||
import('vuetify/lib/styles/main.sass');
|
||||
@@ -1,6 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import {ref} from "vue";
|
||||
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({
|
||||
openedInit: Boolean,
|
||||
@@ -9,22 +11,28 @@ const props = defineProps({
|
||||
});
|
||||
|
||||
let opened = ref(props.openedInit);
|
||||
const openIcon = props.side === 'left' ? '$next' : '$prev';
|
||||
const openIcon = props.side === 'left' ? mdiChevronRight : mdiChevronLeft;
|
||||
|
||||
</script>
|
||||
|
||||
<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-toolbar density="compact">
|
||||
<v-toolbar-items v-if="side == 'right'">
|
||||
<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>
|
||||
<slot name="toolbar"></slot>
|
||||
<v-toolbar-items v-if="side == 'left'">
|
||||
<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>
|
||||
<slot/>
|
||||
@@ -3,16 +3,19 @@ import {VBtn, VIcon} from "vuetify/lib/components";
|
||||
import {ref} from "vue";
|
||||
import OrientationGizmo from "./OrientationGizmo.vue";
|
||||
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) {
|
||||
if (!props.modelViewerInfo) return;
|
||||
let scene: ModelScene = props.modelViewerInfo.scene
|
||||
let scene = props.modelViewerInfo.scene
|
||||
let perspectiveCam = (scene as any).__perspectiveCamera;
|
||||
if (force || perspectiveCam && scene.camera != perspectiveCam) {
|
||||
// Get zoom level from perspective camera
|
||||
@@ -29,7 +32,7 @@ function syncOrthoCamera(force: boolean) {
|
||||
let toggleProjectionText = ref('PERSP'); // Default to perspective camera
|
||||
function toggleProjection() {
|
||||
if (!props.modelViewerInfo) return;
|
||||
let scene: ModelScene = props.modelViewerInfo.scene
|
||||
let scene = props.modelViewerInfo.scene
|
||||
let prevCam = scene.camera;
|
||||
let wasPerspectiveCamera = prevCam.isPerspectiveCamera;
|
||||
if (wasPerspectiveCamera) {
|
||||
@@ -47,11 +50,15 @@ function toggleProjection() {
|
||||
|
||||
<template>
|
||||
<orientation-gizmo v-if="props.modelViewerInfo" :scene="props.modelViewerInfo.scene"/>
|
||||
<v-btn icon="mdi-projector" @click="toggleProjection"><span class="icon-detail">{{ toggleProjectionText }}</span>
|
||||
<v-icon icon="mdi-projector"></v-icon>
|
||||
<v-btn icon="" @click="toggleProjection"><span class="icon-detail">{{ toggleProjectionText }}</span>
|
||||
<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>
|
||||
</template>
|
||||
|
||||
<!--suppress CssUnusedSymbol -->
|
||||
<style>
|
||||
.icon-detail {
|
||||
position: absolute;
|
||||
@@ -62,7 +69,7 @@ function toggleProjection() {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.icon-detail + .v-icon {
|
||||
.icon-detail + svg {
|
||||
position: relative;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import {settings} from "../tools/settings";
|
||||
import {settings} from "../misc/settings";
|
||||
import {ModelViewerElement} from '@google/model-viewer';
|
||||
import {onMounted, ref} from "vue";
|
||||
import {$scene} from "@google/model-viewer/lib/model-viewer-base";
|
||||
@@ -28,7 +28,6 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!--suppress VueMissingComponentImportInspection -->
|
||||
<model-viewer ref="viewer"
|
||||
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"
|
||||
|
||||
16
yarn.lock
16
yarn.lock
@@ -44,6 +44,11 @@
|
||||
"@monogrid/gainmap-js" "^3.0.1"
|
||||
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":
|
||||
version "1.4.15"
|
||||
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"
|
||||
integrity sha512-4wvrf5BgnR8RpogHhtpCPJMKBmvyZPhhUtEwMJbXh0ni2BucpfF07jlmyM11zRqQ2XIq6PbC2j7W7UCCcm1rRQ==
|
||||
|
||||
"@mdi/font@^7.4.47":
|
||||
"@mdi/js@^7.4.47":
|
||||
version "7.4.47"
|
||||
resolved "https://registry.yarnpkg.com/@mdi/font/-/font-7.4.47.tgz#2ae522867da3a5c88b738d54b403eb91471903af"
|
||||
integrity sha512-43MtGpd585SNzHZPcYowu/84Vz2a2g31TvPMTm9uTiCSWzaheQySUcSyUH/46fPnuPQWof2yd0pGBtzee/IQWw==
|
||||
resolved "https://registry.yarnpkg.com/@mdi/js/-/js-7.4.47.tgz#7d8a4edc9631bffeed80d1ec784f9beae559a76a"
|
||||
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":
|
||||
version "0.1.1"
|
||||
|
||||
Reference in New Issue
Block a user