Skip to content

Commit

Permalink
feat(webui): support image resizing & rotating
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Apr 6, 2021
1 parent 3ab470f commit 6a48912
Showing 1 changed file with 87 additions and 55 deletions.
142 changes: 87 additions & 55 deletions packages/plugin-webui/client/views/layout/overlay.vue
Original file line number Diff line number Diff line change
@@ -1,26 +1,39 @@
<template>
<div id="overlay" :class="{ hidden: !store.overlayImage }" @click="onClick">
<template v-if="store.overlayImage">
<span class="button left" :class="{ disabled: !siblings.prev }" @click.stop="siblings.prev && (store.overlayImage = siblings.prev)">
<transition name="fade">
<div class="image-viewer" v-if="store.overlayImage" @click="setImage(null)">
<span class="button left" :class="{ disabled: !siblings.prev }" @click.stop="setImage(siblings.prev)">
<i class="fas fa-chevron-left"/>
</span>
<span class="button right" :class="{ disabled: !siblings.next }" @click.stop="siblings.next && (store.overlayImage = siblings.next)">
<span class="button right" :class="{ disabled: !siblings.next }" @click.stop="setImage(siblings.next)">
<i class="fas fa-chevron-right"/>
</span>
</template>
<transition @before-enter="onBeforeEnter" @after-enter="onAfterEnter" :duration="{ enter: 1, leave: 400 }">
<img ref="img" v-if="store.overlayImage" :src="store.overlayImage.src"/>
</transition>
</div>
<span class="button bottom" @click.stop>
<i class="fas fa-search-minus" @click="scale -= 0.2"/>
<i class="fas fa-search-plus" @click="scale += 0.2"/>
<i class="fas fa-expand" @click="scale = 1"/>
<i class="fas fa-undo" @click="rotate -= 90"/>
<i class="fas fa-redo" @click="rotate += 90"/>
</span>
<transition @before-appear="moveToOrigin" @after-appear="moveToCenter" appear :duration="1">
<img ref="img" :style="{ transform }" :src="store.overlayImage.src"/>
</transition>
</div>
</transition>
</template>

<script lang="ts" setup>
import { store } from '~/client'
import { computed, watch, ref } from 'vue'
const scale = ref(1)
const rotate = ref(0)
const img = ref<HTMLImageElement>(null)
const transform = computed(() => {
return `scale(${scale.value}) rotate(${rotate.value}deg)`
})
const siblings = computed(() => {
if (!store.overlayImage) return
const elements = [...document.querySelectorAll<HTMLImageElement>('.k-image')]
Expand All @@ -31,18 +44,29 @@ const siblings = computed(() => {
}
})
const defaultScale = computed(() => {
const { naturalHeight, naturalWidth } = store.overlayImage
const maxHeight = innerHeight - paddingVertical * 2
const maxWidth = innerWidth - paddingHorizontal * 2
return Math.min(1, maxHeight / naturalHeight, maxWidth / naturalWidth)
})
watch(() => store.overlayImage, (el, origin) => {
if (!el) {
onBeforeEnter(img.value, origin)
return
}
scale.value = 1
rotate.value = 0
if (!el) return moveToOrigin(img.value, origin)
if (img.value) {
img.value.style.transition = null
onAfterEnter(img.value)
img.value.style.transition = '0.3s transform ease'
moveToCenter(img.value)
}
})
function onBeforeEnter(el: HTMLImageElement, origin = store.overlayImage) {
function setImage(el: HTMLImageElement) {
if (el === undefined) return
store.overlayImage = el
}
function moveToOrigin(el: HTMLImageElement, origin = store.overlayImage) {
const { height, width } = origin
const { left, top } = origin.getBoundingClientRect()
el.style.width = width + 'px'
Expand All @@ -55,82 +79,90 @@ function onBeforeEnter(el: HTMLImageElement, origin = store.overlayImage) {
const paddingVertical = 72
const paddingHorizontal = 144
async function onAfterEnter(el: HTMLImageElement) {
function moveToCenter(el: HTMLImageElement) {
const { naturalHeight, naturalWidth } = store.overlayImage
const maxHeight = innerHeight - paddingVertical * 2
const maxWidth = innerWidth - paddingHorizontal * 2
const scale = Math.min(1, maxHeight / naturalHeight, maxWidth / naturalWidth)
const width = naturalWidth * scale, height = naturalHeight * scale
const scale = defaultScale.value
const width = naturalWidth * scale
const height = naturalHeight * scale
el.style.width = width + 'px'
el.style.height = height + 'px'
el.style.left = (innerWidth - width) / 2 + 'px'
el.style.top = (innerHeight - height) / 2 + 'px'
}
function onClick(ev: MouseEvent) {
store.overlayImage = null
}
</script>

<style lang="scss">
$buttonSize: 3rem;
$buttonBg: #303133;
#overlay {
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
.fade-enter-to, .fade-leave-from {
opacity: 1;
}
.image-viewer {
position: absolute;
left: 0;
bottom: 0;
top: 0;
right: 0;
z-index: 1000;
transition: 0.4s background-color ease;
transition: 0.4s opacity ease;
user-select: none;
background-color: #0006;
pointer-events: initial;
&.hidden {
background-color: #0000;
pointer-events: none;
.button {
opacity: 0;
}
}
.button {
position: absolute;
border-radius: 50%;
border-radius: $buttonSize;
cursor: pointer;
user-select: none;
opacity: 0.8;
opacity: 0.5;
font-size: $buttonSize / 2;
width: $buttonSize;
height: $buttonSize;
background-color: #606266;
background-color: $buttonBg;
display: flex;
align-items: center;
justify-content: center;
justify-content: space-evenly;
transition: 0.4s ease;
top: 50%;
transform: translateY(-50%);
&.left {
left: $buttonSize;
i {
margin-left: -3px;
}
i {
transition: 0.4s ease;
}
&:not(.disabled):hover {
opacity: 0.8;
}
&.right {
right: $buttonSize;
i {
margin-right: -3px;
&:not(.disabled) i:hover {
color: rgba(244, 244, 245, .8);
}
@each $tag in left, right {
&.#{$tag} {
top: 50%;
transform: translateY(-50%);
width: $buttonSize;
#{$tag}: $buttonSize;
i {
margin-#{$tag}: -3px;
}
}
}
&.disable {
pointer-events: none;
&.bottom {
bottom: $buttonSize;
width: $buttonSize * 6;
left: 50%;
transform: translateX(-50%);
}
&.disabled {
cursor: not-allowed;
}
}
Expand Down

0 comments on commit 6a48912

Please sign in to comment.