Files
speckle-server/packages/frontend/src/embed/EmbedViewer.vue
T
2022-04-01 18:24:51 +03:00

254 lines
6.7 KiB
Vue

<template>
<v-app
:class="`no-scrollbar ${
$vuetify.theme.dark ? 'background-dark' : 'background-light'
}`"
>
<!-- <speckle-loading v-if="!stream || error" :error="error" style="z-index: 101000" /> -->
<div v-if="!error" style="z-index: 1000">
<div class="top-left bottom-left ma-2 d-flex">
<span class="caption d-inline-flex align-center">
<img src="@/assets/logo.svg" height="20" />
<span style="margin-top: 2px" class="primary--text">
<a href="https://speckle.xyz" target="_blank" class="text-decoration-none">
Speckle
</a>
</span>
</span>
</div>
<div
class="pa-2 d-flex align-center justify-space-between caption"
style="position: fixed; bottom: 0; width: 100%"
>
<v-btn
v-if="stream && serverInfo"
v-tooltip="'See in Speckle'"
color="primary"
small
class="rounded-lg"
:href="goToServerUrl"
target="blank"
>
<v-icon small>mdi-open-in-new</v-icon>
</v-btn>
</div>
</div>
<div
v-if="!loadedModel"
ref="cover"
class="d-flex fullscreen align-center justify-center bg-img"
/>
<div
v-if="!loadedModel && loadProgress > 0"
class="d-flex fullscreen align-center justify-center"
>
<v-progress-linear
v-model="loadProgress"
:indeterminate="loadProgress >= 99 && !loadedModel"
color="primary"
style="max-width: 30%"
></v-progress-linear>
</div>
<div
v-if="!loadedModel && loadProgress === 0"
class="d-flex fullscreen align-center justify-center"
>
<v-btn fab color="primary" class="elevation-10" @click="load()">
<v-icon>mdi-play</v-icon>
</v-btn>
</div>
<div style="position: fixed" class="no-scrollbar">
<speckle-viewer @load-progress="captureProgress" />
</div>
</v-app>
</template>
<script>
import SpeckleViewer from '@/main/components/common/SpeckleViewer.vue'
import { getCommit, getLatestBranchCommit, getServerInfo } from '@/embed/speckleUtils'
export default {
name: 'EmbedViewer',
components: {
SpeckleViewer
},
filters: {
truncate: function (str, n = 20) {
return str.length > n ? str.substr(0, n - 3) + '...' : str
}
},
data() {
return {
loadedModel: false,
loadProgress: 0,
error: null,
objectId: this.$route.query.object,
input: {
stream: this.$route.query.stream,
object: this.$route.query.object,
branch: this.$route.query.branch || 'main',
commit: this.$route.query.commit
},
lastCommit: null,
specificCommit: null,
serverInfo: null
}
},
computed: {
isSmall() {
return (
this.$vuetify.breakpoint.name === 'xs' || this.$vuetify.breakpoint.name === 'sm'
)
},
displayType() {
if (!this.input.stream) {
return 'error'
}
if (this.input.commit) return 'commit'
if (this.input.object) return 'object'
if (this.input.branch) return 'branch'
return 'stream'
},
stream() {
return this.lastCommit || this.specificCommit
},
objectUrl() {
return `${window.location.protocol}//${window.location.host}/streams/${this.input.stream}/objects/${this.objectId}`
},
goToServerUrl() {
let stream = this.input.stream
let base = `${window.location.origin}/streams/${stream}/`
let commit = this.input.commit
if (commit) return base + `commits/${commit}`
let object = this.objectId
if (object) return base + `objects/${object}`
let branch = this.input.branch
if (branch) return base + `branches/${encodeURI(branch)}`
return base
}
},
watch: {
displayType(oldVal, newVal) {
if (newVal === 'error') this.error = 'Provided details were invalid'
else {
this.error = null
}
}
},
async beforeMount() {
try {
let serverInfoResponse = await getServerInfo()
this.serverInfo = serverInfoResponse.data.serverInfo
} catch (e) {
this.error = e.message
return
}
if (this.displayType === 'commit') {
try {
let res = await getCommit(this.input.stream, this.input.commit)
let data = res.data
let latestCommit = data.stream.commit
if (this.input.object === undefined)
this.objectId = latestCommit.referencedObject
this.specificCommit = data.stream
} catch (e) {
this.error = e.message
return
}
} else {
try {
let res = await getLatestBranchCommit(this.input.stream, this.input.branch)
let data = res.data
let latestCommit =
data.stream.branch.commits.items[0] || data.stream.branch.commit
if (!latestCommit) {
this.error = 'No commit for this branch'
this.lastCommit = data.stream
return
}
if (this.input.object === undefined)
this.objectId = latestCommit.referencedObject
else this.objectId = this.input.object
this.lastCommit = data.stream
} catch (e) {
this.error = e.message
return
}
}
this.getPreviewImage()
},
mounted() {},
methods: {
async load() {
await window.__viewer.loadObject(this.objectUrl)
window.__viewer.zoomExtents(undefined, true)
this.loadedModel = true
this.$mixpanel.track('Embedded Model Load', {
step: this.onboarding,
type: 'action'
})
},
captureProgress(args) {
this.loadProgress = args.progress * 100
},
async getPreviewImage(angle) {
angle = angle || 0
let previewUrl = this.objectUrl.replace('streams', 'preview') + '/' + angle
let token = undefined
try {
token = localStorage.getItem('AuthToken')
} catch (e) {
console.warn('Sanboxed mode, only public streams will fetch properly.')
}
const res = await fetch(previewUrl, {
headers: token ? { Authorization: `Bearer ${token}` } : {}
})
const blob = await res.blob()
const imgUrl = URL.createObjectURL(blob)
if (this.$refs.cover) this.$refs.cover.style.backgroundImage = `url('${imgUrl}')`
this.hasImg = true
}
}
}
</script>
<style lang="scss">
body::-webkit-scrollbar {
display: none;
}
.fullscreen {
height: 100vh !important;
width: 100vw !important;
position: fixed;
&::-webkit-scrollbar {
display: none;
}
}
.no-scrollbar {
width: 100vw;
height: 100vh;
overflow: hidden;
&::-webkit-scrollbar {
display: none;
}
}
.bg-img {
background-position: center;
background-repeat: no-repeat;
/*background-attachment: fixed;*/
filter: blur(2px);
}
.no-events {
pointer-events: none;
}
</style>