add rotate view to image viewer, mobile css fix

This commit is contained in:
Weidi Deng 2021-01-08 09:51:47 +08:00
parent 6e993dd095
commit fe9fedb14e
3 changed files with 85 additions and 10 deletions

View 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>

View File

@ -20,6 +20,7 @@ import throttle from 'lodash.throttle'
export default { export default {
props: { props: {
src: String, src: String,
angle: Number,
moveDisabledTime: { moveDisabledTime: {
type: Number, type: Number,
default: () => 200 default: () => 200
@ -83,17 +84,35 @@ export default {
watch: { watch: {
src: function () { src: function () {
this.setCenter() 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: { methods: {
fit() { fit() {
let img = this.$refs.imgex const wScale = window.innerWidth / this.imgWidth
const hScale = window.innerHeight / this.imgHeight
const wScale = window.innerWidth / img.clientWidth
const hScale = window.innerHeight / img.clientHeight
this.scale = Math.min(wScale, hScale) this.scale = Math.min(wScale, hScale)
this.minScale = this.scale this.minScale = this.scale
this.maxScale = 4 * this.scale
this.setZoom() this.setZoom()
}, },
refit() { refit() {
@ -288,7 +307,7 @@ export default {
setZoom() { setZoom() {
this.scale = this.scale < this.minScale ? this.minScale : this.scale this.scale = this.scale < this.minScale ? this.minScale : this.scale
this.scale = this.scale > this.maxScale ? this.maxScale : 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() this.refit()
}, },
pxStringToNumber(style) { pxStringToNumber(style) {

View File

@ -7,7 +7,9 @@
<div class="title">{{ this.name }}</div> <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"> <button @click="openMore" id="more" :aria-label="$t('buttons.more')" :title="$t('buttons.more')" class="action">
<i class="material-icons">more_vert</i> <i class="material-icons">more_vert</i>
</button> </button>
@ -37,7 +39,7 @@
<template v-if="!loading"> <template v-if="!loading">
<div class="preview"> <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> <audio v-else-if="req.type == 'audio'" :src="raw" autoplay controls></audio>
<video v-else-if="req.type == 'video'" :src="raw" autoplay controls> <video v-else-if="req.type == 'video'" :src="raw" autoplay controls>
<track <track
@ -66,6 +68,7 @@ import { mapState } from 'vuex'
import url from '@/utils/url' import url from '@/utils/url'
import { baseURL, resizePreview } from '@/utils/constants' import { baseURL, resizePreview } from '@/utils/constants'
import { files as api } from '@/api' import { files as api } from '@/api'
import RotateButton from "@/components/buttons/RotatePreview"
import PreviewSizeButton from '@/components/buttons/PreviewSize' import PreviewSizeButton from '@/components/buttons/PreviewSize'
import InfoButton from '@/components/buttons/Info' import InfoButton from '@/components/buttons/Info'
import DeleteButton from '@/components/buttons/Delete' import DeleteButton from '@/components/buttons/Delete'
@ -82,6 +85,7 @@ const mediaTypes = [
export default { export default {
name: 'preview', name: 'preview',
components: { components: {
RotateButton,
PreviewSizeButton, PreviewSizeButton,
InfoButton, InfoButton,
DeleteButton, DeleteButton,
@ -97,7 +101,8 @@ export default {
name: '', name: '',
subtitles: [], subtitles: [],
fullSize: false, fullSize: false,
isGallery: false isGallery: false,
angle: 0
} }
}, },
computed: { computed: {
@ -130,6 +135,9 @@ export default {
watch: { watch: {
$route: function () { $route: function () {
this.updatePreview() this.updatePreview()
},
showMore: function () {
if (!this.showMore) this.hideGalleryBar()
} }
}, },
created() { created() {
@ -140,20 +148,38 @@ export default {
this.$store.commit('setPreviewMode', true) this.$store.commit('setPreviewMode', true)
this.listing = this.oldReq.items this.listing = this.oldReq.items
this.$root.$on('preview-deleted', this.deleted) 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() this.updatePreview()
}, },
beforeDestroy () { beforeDestroy () {
window.removeEventListener('keydown', this.key) window.removeEventListener('keydown', this.key)
this.$store.commit('setPreviewMode', false) this.$store.commit('setPreviewMode', false)
this.$root.$off('preview-deleted', this.deleted) 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: { methods: {
nav(e) { nav(e) {
if (e===0 && this.hasPrevious) this.prev() if (e===0 && this.hasPrevious) this.prev()
else if (e===1 && this.hasNext) this.next() 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 () { deleted () {
this.listing = this.listing.filter(item => item.name !== this.name) this.listing = this.listing.filter(item => item.name !== this.name)
@ -189,6 +215,7 @@ export default {
} }
}, },
async updatePreview () { async updatePreview () {
this.angle = 0
if (this.req.subtitles) { if (this.req.subtitles) {
this.subtitles = this.req.subtitles.map(sub => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`) this.subtitles = this.req.subtitles.map(sub => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`)
} }
@ -243,6 +270,13 @@ export default {
resetPrompts () { resetPrompts () {
this.$store.commit('closeHovers') this.$store.commit('closeHovers')
}, },
setRotate(rotate_left) {
if (rotate_left) {
this.angle -= 90
} else {
this.angle += 90
}
},
toggleSize () { toggleSize () {
this.fullSize = !this.fullSize this.fullSize = !this.fullSize
} }