add rotate view to image viewer, mobile css fix
This commit is contained in:
parent
6e993dd095
commit
fe9fedb14e
22
frontend/src/components/buttons/RotatePreview.vue
Normal file
22
frontend/src/components/buttons/RotatePreview.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<button :title="$t('buttons.info')" :aria-label="$t('buttons.info')" class="action" @click="$emit('rotate', rotate_left)">
|
||||
<i class="material-icons">{{ this.icon }}</i>
|
||||
<span>{{ $t('buttons.info') }}</span>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'rotate-button',
|
||||
props: [ 'rotate_left' ],
|
||||
computed: {
|
||||
icon () {
|
||||
if (this.rotate_left) {
|
||||
return 'rotate_left'
|
||||
}
|
||||
|
||||
return 'rotate_right'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -20,6 +20,7 @@ import throttle from 'lodash.throttle'
|
||||
export default {
|
||||
props: {
|
||||
src: String,
|
||||
angle: Number,
|
||||
moveDisabledTime: {
|
||||
type: Number,
|
||||
default: () => 200
|
||||
@ -83,17 +84,35 @@ export default {
|
||||
watch: {
|
||||
src: function () {
|
||||
this.setCenter()
|
||||
},
|
||||
angle: function () {
|
||||
this.setCenter()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
imgHeight() {
|
||||
let img = this.$refs.imgex
|
||||
|
||||
// slow version
|
||||
// return img.clientHeight * Math.cos(this.angle * Math.PI) + img.clientWidth * Math.sin(this.angle * Math.PI)
|
||||
return !(this.angle % 180) ? img.clientHeight : img.clientWidth
|
||||
},
|
||||
imgWidth() {
|
||||
let img = this.$refs.imgex
|
||||
|
||||
// slow version
|
||||
// return img.clientWidth * Math.cos(this.angle * Math.PI) + img.clientHeight * Math.sin(this.angle * Math.PI)
|
||||
return !(this.angle % 180) ? img.clientWidth : img.clientHeight
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fit() {
|
||||
let img = this.$refs.imgex
|
||||
|
||||
const wScale = window.innerWidth / img.clientWidth
|
||||
const hScale = window.innerHeight / img.clientHeight
|
||||
const wScale = window.innerWidth / this.imgWidth
|
||||
const hScale = window.innerHeight / this.imgHeight
|
||||
|
||||
this.scale = Math.min(wScale, hScale)
|
||||
this.minScale = this.scale
|
||||
this.maxScale = 4 * this.scale
|
||||
this.setZoom()
|
||||
},
|
||||
refit() {
|
||||
@ -288,7 +307,7 @@ export default {
|
||||
setZoom() {
|
||||
this.scale = this.scale < this.minScale ? this.minScale : this.scale
|
||||
this.scale = this.scale > this.maxScale ? this.maxScale : this.scale
|
||||
this.$refs.imgex.style.transform = `scale(${this.scale})`
|
||||
this.$refs.imgex.style.transform = `scale(${this.scale}) rotate(${this.angle}deg)`
|
||||
this.refit()
|
||||
},
|
||||
pxStringToNumber(style) {
|
||||
|
||||
@ -7,7 +7,9 @@
|
||||
|
||||
<div class="title">{{ this.name }}</div>
|
||||
|
||||
<preview-size-button v-if="isResizeEnabled && req.type === 'image'" @change-size="toggleSize" v-bind:size="fullSize" :disabled="loading"></preview-size-button>
|
||||
<rotate-button v-if="isGallery" :rotate_left="true" @rotate="setRotate($event)" :disabled="loading"></rotate-button>
|
||||
<rotate-button v-if="isGallery" :rotate_left="false" @rotate="setRotate($event)" :disabled="loading"></rotate-button>
|
||||
<preview-size-button v-if="isResizeEnabled && isGallery" @change-size="toggleSize" v-bind:size="fullSize" :disabled="loading"></preview-size-button>
|
||||
<button @click="openMore" id="more" :aria-label="$t('buttons.more')" :title="$t('buttons.more')" class="action">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
@ -37,7 +39,7 @@
|
||||
|
||||
<template v-if="!loading">
|
||||
<div class="preview">
|
||||
<ExtendedImage v-if="isGallery" :src="raw"></ExtendedImage>
|
||||
<ExtendedImage v-if="isGallery" :src="raw" :angle="angle"></ExtendedImage>
|
||||
<audio v-else-if="req.type == 'audio'" :src="raw" autoplay controls></audio>
|
||||
<video v-else-if="req.type == 'video'" :src="raw" autoplay controls>
|
||||
<track
|
||||
@ -66,6 +68,7 @@ import { mapState } from 'vuex'
|
||||
import url from '@/utils/url'
|
||||
import { baseURL, resizePreview } from '@/utils/constants'
|
||||
import { files as api } from '@/api'
|
||||
import RotateButton from "@/components/buttons/RotatePreview"
|
||||
import PreviewSizeButton from '@/components/buttons/PreviewSize'
|
||||
import InfoButton from '@/components/buttons/Info'
|
||||
import DeleteButton from '@/components/buttons/Delete'
|
||||
@ -82,6 +85,7 @@ const mediaTypes = [
|
||||
export default {
|
||||
name: 'preview',
|
||||
components: {
|
||||
RotateButton,
|
||||
PreviewSizeButton,
|
||||
InfoButton,
|
||||
DeleteButton,
|
||||
@ -97,7 +101,8 @@ export default {
|
||||
name: '',
|
||||
subtitles: [],
|
||||
fullSize: false,
|
||||
isGallery: false
|
||||
isGallery: false,
|
||||
angle: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -130,6 +135,9 @@ export default {
|
||||
watch: {
|
||||
$route: function () {
|
||||
this.updatePreview()
|
||||
},
|
||||
showMore: function () {
|
||||
if (!this.showMore) this.hideGalleryBar()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -140,20 +148,38 @@ export default {
|
||||
this.$store.commit('setPreviewMode', true)
|
||||
this.listing = this.oldReq.items
|
||||
this.$root.$on('preview-deleted', this.deleted)
|
||||
if (this.isGallery) this.$root.$on('gallery-nav', this.nav)
|
||||
if (this.isGallery) {
|
||||
this.$root.$on('gallery-nav', this.nav)
|
||||
document.querySelector('#previewer .overlay').addEventListener('mouseenter', this.showGalleryBar)
|
||||
document.querySelector('#previewer .gallery-bar #dropdown').addEventListener('mouseenter', this.showGalleryBar)
|
||||
}
|
||||
this.updatePreview()
|
||||
},
|
||||
beforeDestroy () {
|
||||
window.removeEventListener('keydown', this.key)
|
||||
this.$store.commit('setPreviewMode', false)
|
||||
this.$root.$off('preview-deleted', this.deleted)
|
||||
if (this.isGallery) this.$root.$off('gallery-nav', this.nav)
|
||||
if (this.isGallery) {
|
||||
this.$root.$off('gallery-nav', this.nav)
|
||||
document.querySelector('#previewer .overlay').removeEventListener('mouseenter', this.showGalleryBar)
|
||||
document.querySelector('#previewer .gallery-bar #dropdown').removeEventListener('mouseenter', this.showGalleryBar)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
nav(e) {
|
||||
if (e===0 && this.hasPrevious) this.prev()
|
||||
else if (e===1 && this.hasNext) this.next()
|
||||
},
|
||||
showGalleryBar() {
|
||||
document.querySelector('#previewer .gallery-bar').style.opacity = 1
|
||||
document.querySelector('#previewer .gallery-bar').style.zIndex = 'auto'
|
||||
document.querySelector('#previewer .preview .image-ex-container').style.zIndex = -1
|
||||
},
|
||||
hideGalleryBar() {
|
||||
document.querySelector('#previewer .gallery-bar').style.removeProperty('opacity')
|
||||
document.querySelector('#previewer .gallery-bar').style.zIndex = 2
|
||||
document.querySelector('#previewer .preview .image-ex-container').style.zIndex = 'auto'
|
||||
},
|
||||
deleted () {
|
||||
this.listing = this.listing.filter(item => item.name !== this.name)
|
||||
|
||||
@ -189,6 +215,7 @@ export default {
|
||||
}
|
||||
},
|
||||
async updatePreview () {
|
||||
this.angle = 0
|
||||
if (this.req.subtitles) {
|
||||
this.subtitles = this.req.subtitles.map(sub => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`)
|
||||
}
|
||||
@ -243,6 +270,13 @@ export default {
|
||||
resetPrompts () {
|
||||
this.$store.commit('closeHovers')
|
||||
},
|
||||
setRotate(rotate_left) {
|
||||
if (rotate_left) {
|
||||
this.angle -= 90
|
||||
} else {
|
||||
this.angle += 90
|
||||
}
|
||||
},
|
||||
toggleSize () {
|
||||
this.fullSize = !this.fullSize
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user