Commit 01e90569 authored by Jean Rabreau's avatar Jean Rabreau
Browse files

plug rti viewer to stored files

parent 9865cacf
Pipeline #60586 passed with stages
in 4 minutes and 58 seconds
/* eslint-disable no-console */
/*
Relight
......@@ -281,7 +282,7 @@ initTree: function() {
};
t.parseMetaData = function (response) {
console.log(response)
// console.log(response)
t.suffix = "." + /Format="(\w+)/.exec(response)[1];
t.tilesize = parseInt(/TileSize="(\d+)/.exec(response)[1]);
t.overlap = parseInt(/Overlap="(\d+)/.exec(response)[1]);
......@@ -374,7 +375,7 @@ initTree: function() {
};
break;
default:
console.log("OOOPPpppps");
console.warn("OOOPPpppps");
}
if(t.metaDataURL) {
......@@ -516,7 +517,7 @@ loadTile: function(level, x, y) {
var index = t.index(level, x, y);
if(t.requested[index]) {
console.log("AAARRGGHHH double request!");
console.warn("AAARRGGHHH double request!");
return;
}
t.requested[index] = true;
......@@ -624,7 +625,7 @@ computeLightWeights: function(lpos) {
case 'bilinear': lightFun = t.computeLightWeightsOcta; break;
case 'ptm': lightFun = t.computeLightWeightsPtm; break;
case 'hsh': lightFun = t.computeLightWeightsHsh; break;
default: console.log("Unknown basis", t.type);
default: console.warn("Unknown basis", t.type);
}
lightFun.call(this, l);
......@@ -815,8 +816,8 @@ loadProgram: function() {
let compiled = gl.getShaderParameter(t.vertShader, gl.COMPILE_STATUS);
if(!compiled) {
alert("Failed vertex shader compilation: see console log and ask for support.");
console.log(t.vertShader);
console.log(gl.getShaderInfoLog(t.vertShader));
console.warn(t.vertShader);
console.warn(gl.getShaderInfoLog(t.vertShader));
}
t.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
......@@ -826,8 +827,8 @@ loadProgram: function() {
compiled = gl.getShaderParameter(t.fragShader, gl.COMPILE_STATUS);
if(!compiled) {
alert("Failed fragment shader compilation: see console log and ask for support.");
console.log(t.fragCode);
console.log(gl.getShaderInfoLog(t.fragShader));
console.warn(t.fragCode);
console.warn(gl.getShaderInfoLog(t.fragShader));
}
t.program = gl.createProgram();
......
<template>
<div id="file__management">
<v-row no-gutters>
<v-col cols="12" md="8" offset-md="2">
<v-form v-model="isValid" ref="form" lazy-validation>
<v-file-input
show-size
:label="$t('file.upload.label')"
@change="updateFileToLoad"
:rules="requiredRule"
/>
<v-progress-linear
v-show="currentFile"
color="primary"
:indeterminate="loading"
:value="progress"
/>
<v-btn color="secondary" dark small @click="onUploadFile">
{{ $t('file.upload.button') }}
<v-icon right dark>mdi-cloud-upload</v-icon>
</v-btn>
</v-form>
</v-col>
</v-row>
<v-row>
<v-switch
v-model="isDownloadable"
:label="$t('file.downloadable')"
@change="downloadUpdate"
/>
</v-row>
<v-row>
<v-col cols="12">
<v-data-table
:headers="headers"
:items="fileWithViewer"
:value="fileView"
@input="onSetFileView"
single-select
show-select
hide-default-footer
>
<template v-slot:top >
<h2>{{ $t('file.header') }}</h2>
</template>
<template v-slot:[`item.icon`]="{ item }">
<v-icon>{{ item.icon }}</v-icon>
</template>
<template v-slot:[`item.delete`]="{ item }">
<v-icon small @click="onDeleteRequest(item)">
mdi-delete
</v-icon>
</template>
</v-data-table>
<confirmBox
:dialog.sync="showConfirm"
action="delete"
:object="$t('file.designate', {name: fileToDelete.name})"
@confirm="onDeleteFile"
/>
</v-col>
</v-row>
</div>
</template>
<script>
import {mapActions, mapGetters} from 'vuex'
import ConfirmBox from '@/components/common/ConfirmBox'
import { SUPPORTED_3D_EXTENSIONS, TYPE_RENDER_MAP } from '@/store/item'
export default {
name: "FileUpload",
components: {ConfirmBox},
props: {
item: {
type: Object,
required: true
}
},
data() {
return {
fileView: this.item.viewer
? this.item.mediaFiles.filter(f => f.id === this.item.viewer.fileId)
: [],
isDownloadable: this.item.viewer.isDownloadable,
isValid: false,
loading: false,
progress: 0,
currentFile: undefined,
requiredRule: [file => !!file || "un fichier est requis"],
fileToDelete: {},
showConfirm: false,
}
},
computed: {
...mapGetters('item', ['itemId']),
headers() {
return [
{text: this.$t('file.visualize'), value: 'data-table-select', align: 'end'},
{text: this.$t('file.type'), value: 'icon', align: 'start'},
{text: this.$t('file.name'), value: 'name'},
{text: this.$t('file.size'), value: 'size'},
{text: this.$t('btn.delete'), value:'delete', sortable: false}
]
},
fileWithViewer() {
return this.item.mediaFiles.map(f => {
const { component, icon } = this.viewerComponent(f)
return {
...f,
component,
icon,
isSelectable: !!component
}
})
},
},
methods: {
...mapActions('item', ['itemLoad', 'itemUpdate', 'fileUpload', 'fileDelete']),
downloadUpdate() {
this.itemUpdate({
viewer: {
...this.item.viewer,
isDownloadable: this.isDownloadable
}
})
},
/**
* Update current file to be uploaded
* and initialize upload progress bar
*
* @param {File} file
*/
updateFileToLoad(file) {
this.progress = 0
this.currentFile = file
},
onDeleteRequest(file) {
this.fileToDelete = file
this.showConfirm = true
},
onDeleteFile() {
this.fileDelete(this.fileToDelete.id)
.then(() => {
this.fileToDelete = {}
})
.finally(() => {
this.showConfirm = false
})
},
/**
* Update file selection for visualization
*
* @param {MediaFile[]} selection
*/
onSetFileView(selection) {
const newViewerSetting = {
...selection.length
? {fileId: selection[0].id, component: selection[0].component}
: {},
isDownloadable: this.isDownloadable,
}
this.itemUpdate({ viewer: newViewerSetting })
},
onUploadFile() {
if (this.$refs.form.validate()) {
this.loading = true
this.fileUpload(this.currentFile)
.then(progress => {
this.progress = progress
})
.finally(() => {
this.loading = false
})
}
},
/**
*
* @param {MediaFile} file
* @returns {{component, icon}|{}}
*/
viewerComponent(file) {
const { name, contentType } = file
const fileExtension = name.match(/.+\.([^.]+)$/)
const is3DModel = fileExtension && SUPPORTED_3D_EXTENSIONS.includes(fileExtension[1])
const mediaType = is3DModel ? 'model' : contentType.match(/.*(?=\/)/)[0]
return TYPE_RENDER_MAP[mediaType] || {}
},
},
}
</script>
<style lang="scss" scoped>
.v-progress-linear {
margin-bottom: 5px;
}
</style>
<template>
<v-row class="d-flex fill-height">
<v-col cols="10">
<div id="relight__container">
<!-- <v-navigation-drawer-->
<!-- v-model="toolAccess"-->
<!-- absolute-->
<!-- :mini-variant="!help"-->
<!-- >-->
<!-- <v-list dense>-->
<!-- <v-list-item @click="toolAccess = !toolAccess">-->
<!-- <v-icon >mdi-chevron-left</v-icon>-->
<!-- <v-subheader>{{ $t('hop.close') }}</v-subheader>-->
<!-- </v-list-item>-->
<!-- <v-list-item @click="reset">-->
<!-- <v-icon>mdi-home</v-icon>-->
<!-- <v-subheader>{{ $t('hop.reset') }}</v-subheader>-->
<!-- </v-list-item>-->
<!-- &lt;!&ndash; <v-list-item @click="">&ndash;&gt;-->
<!-- &lt;!&ndash; <v-icon>{{ fullscreen.icon }}</v-icon>&ndash;&gt;-->
<!-- &lt;!&ndash; <v-subheader>{{ fullscreen.help }}</v-subheader>&ndash;&gt;-->
<!-- &lt;!&ndash; </v-list-item>&ndash;&gt;-->
<!-- <ZoomButton @zoom="zoomIn" opp="plus"/>-->
<!-- <ZoomButton @zoom="zoomOut" opp="minus"/>-->
<!-- &lt;!&ndash; <v-list-item @click="cameraType.switch">&ndash;&gt;-->
<!-- &lt;!&ndash; <v-icon>mdi-camera-flip-outline</v-icon>&ndash;&gt;-->
<!-- &lt;!&ndash; <v-subheader>{{ cameraType.nextType }}</v-subheader>&ndash;&gt;-->
<!-- &lt;!&ndash; </v-list-item>&ndash;&gt;-->
<!-- </v-list>-->
<!-- </v-navigation-drawer>-->
<!-- <transition name="slide">-->
<!-- <v-list-item-->
<!-- v-if="!toolAccess"-->
<!-- id="toolbar"-->
<!-- @click="toolAccess = !toolAccess"-->
<!-- dense-->
<!-- shaped-->
<!-- >-->
<!-- <v-icon>mdi-tools</v-icon><v-icon>mdi-chevron-right</v-icon>-->
<!-- </v-list-item>-->
<!-- </transition>-->
<div class="relight">
</div>
</div>
</v-col>
</v-row>
</template>
<script>
import RelightViewer from '@/assets/relight/relight-interface'
// import ZoomButton from '@/components/renderer/file/model/ZoomButton'
export default {
name: "Rti",
components: {
// ZoomButton
},
props: {
file: {
type: Object,
required: true,
}
},
data() {
return {
help: false,
relightViewer: {},
toolAccess: false,
}
},
computed: {
nav() {
return this.relightViewer.nav
},
},
mounted() {
this.relightViewer = new RelightViewer('.relight',
{
layers: [{
url: this.file.url.replace(/\/info\.json$/, ''),
layout:"image",
}],
fit: true,
bounded: false,
zbounded: false,
maxzoom: -4,
minzoom: 100,
pos: { x:0, y:0, z:0, a:0 },
rotation: 0,
// pagemap: { /*thumb: 'thumb.jpg', */size:200, autohide:1000 },
scale: 1.0,
background: [0.4, 0.4, 0.4, .3]
}
);
},
methods: {
reset() {
this.relightViewer.centerAndScale(this.nav.zoomdelay)
},
zoomIn() {
this.relightViewer.zoom(-this.nav.zoomstep, this.nav.zoomdelay)
},
zoomOut() {
this.relightViewer.zoom(this.nav.zoomstep, this.nav.zoomdelay)
},
},
}
</script>
<style lang="scss" scoped>
@import '/static/stylesheet/vendor/vcg.isti.cnr.it/relight.css';
#relight__container {
width:100%; height:100%; position: relative;
}
.relight { position:relative; touch-action: none; width:100%; height:100%; }
.relight canvas { width:100%; height:100%; display:block; }
.relight-toolbox { position: absolute; top:0px; left:0px; padding:5px; }
.relight-toolbox > div { background-size:cover; cursor:pointer; margin:5px; opacity:0.7 }
.relight-toolbox > div:hover { opacity:0.9; }
.relight-home { background-image: url(/static/skins/dark/home.png); }
.relight-zoomin { background-image: url(/static/skins/dark/zoomin.png); }
.relight-zoomout { background-image: url(/static/skins/dark/zoomout.png); }
.relight-rotate { background-image: url(/static/skins/dark/rotate.png); }
.relight-light { background-image: url(/static/skins/dark/light.png); }
.relight-light_on { background-image: url(/static/skins/dark/light_on.png); }
.relight-normals { background-image: url(/static/skins/dark/normals.png); }
.relight-normals_on { background-image: url(/static/skins/dark/normals_on.png); }
.relight-full { background-image: url(/static/skins/dark/full.png); }
.relight-full_on { background-image: url(/static/skins/dark/full_on.png); }
.relight-info { background-image: url(/static/skins/dark/help.png); }
.relight {
position:relative;
}
.relight-info-dialog {
display:none;
position:absolute;
top:0px;
left:0px;
width:100%;
height:100%;
background-color:rgb(0, 0, 0, 0.5);
}
.relight-info-content {
display:none;
background-color:white;
padding:20px;
max-height: calc(100% - 100px);
width: 80%;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 5px;
}
.relight-scale {
position:absolute;
bottom:10px;
right:10px;
padding:20px 10px;
width:5%;
text-align:center;
z-index:1000;
background-color:rgba(0, 0, 0, 0.5);
color:#eee;
transition: opacity 1s ease;
opacity:1.0;
}
.relight-pagemap {
position:absolute;
top:10px;
right:10px;
background-color:rgb(255, 255, 255, 0.1);
transition: opacity 1s ease;
opacity:1.0;
}
.relight-pagemap[style]:hover {
opacity:1.0 !important;
}
.relight-pagemap-area {
position:absolute;
top:0px; left:0px;
border: 1px solid white;
box-shadow: 0 0 0 1px #ccc;
opacity:0.5;
}
@media screen and (max-width: 576px) {
.relight-toolbox > div { width: 9vmin; height: 9vmin; }
.relight-pagemap { display:none; }
.relight-scale { width:15%; }
}
@media screen and (min-width: 576px) {
.relight-toolbox > div {width: 9vmin; height: 9vmin; }
.relight-pagemap { display:none; }
.relight-scale { width:10%; }
}
@media screen and (min-width: 768px) {
.relight-toolbox > div {width: 7vmin; height: 7vmin; }
.relight-pagemap { display:block; width:200px; }
.relight-scale { width:7%; }
}
@media screen and (min-width: 992px) {
.relight-toolbox > div {width: 6vmin; height: 6vmin; }
.relight-pagemap { display:block; width:200px; }
.relight-scale { width:5%; }
}
#toolbar {
position:absolute;
top:8px;
left: 0px;
-webkit-user-select:none;
-webkit-touch-callout:none;
-khtml-user-select:none;
-moz-user-select:none;
-ms-user-select:none;
user-select:none;
touch-action:none;
-ms-touch-action:none;
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-tap-highlight-color: transparent;
z-index: 1;
background: rgba(255,255,255,0.3);
&.theme--dark {
background: rgba(0,0,0,0.3);
}
}
slide-enter-active {
animation: slide-in 1s;
}
.slide-leave-active {
animation: slide-out .3s;
}
@keyframes slide-out {
0% {
margin-left: 0px;
opacity: 1;
background: transparent;
}
70%{
opacity: 0.7;
}
100% {
margin-left: 56px;
opacity: 0;
}
}
@keyframes slide-in {
0% {
left: -56px;
}
100% {
left: 0px;
}
}
</style>
......@@ -69,8 +69,6 @@ export default {
},
},
mounted() {
// const url1 = 'test/bilinear18';
const url2 = 'items/c950b2d5-d748-467c-bb69-8f4c7bf5eda6/mediafiles/get_rti';
this.relightViewer = new RelightViewer('.relight',
{
......
......@@ -11,8 +11,8 @@ export const LOCALES_MAP = {
}
export const messages = {
'fr': fr_FR,
'en': en_US,
fr: fr_FR,
en: en_US,
};
export default new VueI18n({
......
......@@ -112,9 +112,13 @@ const TYPE_RENDER_MAP = {
component: 'Pdf',
icon: 'mdi-file-pdf-outline'
},
rti: {
component: 'Rti',
icon: 'mdi-camera-iris'
},
video: {
component: 'Video',
icon: 'mdi-file-video'
icon: 'mdi-camera-iris'
},
}
......@@ -192,18 +196,6 @@ const Item = {
}
})
},
rtiUpload({getters}, file) {
const itemId = getters['itemId']
const formData = new FormData()
formData.append("Content-Type", file.type)
formData.append("file", file)
// request pre-signed post url
return authority.post(
`items/${itemId}/mediafiles/rti/`,
formData
)
}
,
/**
*
* @param context
......@@ -236,19 +228,50 @@ const Item = {
{filename}
).then(response => {
commit('ADD_MEDIA_FILE', response.data)
return dispatch(
dispatch(
'dialog/displayInfo',
i18n.t('file.upload.success', { filename }),
{root: true}
).then(() => 100)
)
return 100
})
})
}).catch(error => dispatch(
'dialog/displayError',
{ error, message: i18n.t('file.upload.error', {filename}) },
{root: true}
))