From cb2bfd8a76237a05c2743886b70f2f57dc37b136 Mon Sep 17 00:00:00 2001 From: EdwardAJ <13517115@std.stei.itb.ac.id> Date: Wed, 8 Apr 2020 01:01:58 +0700 Subject: [PATCH] Add design to toolbar --- frontend/components/label/Box.vue | 11 ++- frontend/components/label/Toolbar.vue | 64 +++++++++++++ frontend/components/view/Suggest.vue | 10 +- frontend/pages/viewer/index-edit.vue | 41 +++++++- frontend/pages/viewer/index.vue | 133 ++++++++++++++++---------- 5 files changed, 202 insertions(+), 57 deletions(-) create mode 100644 frontend/components/label/Toolbar.vue diff --git a/frontend/components/label/Box.vue b/frontend/components/label/Box.vue index a7aec54..350b319 100644 --- a/frontend/components/label/Box.vue +++ b/frontend/components/label/Box.vue @@ -16,7 +16,7 @@ class="circle" :style="{ top: bTop + -6 + 'px', left: bLeft + -6 + 'px'}" @mousedown="isLeftCircleActive = true" - @mousemove="resizeBox" + @mousemove="resizeBoxFromTopLeft" @mouseup="onStopResize" /> @@ -35,7 +35,8 @@ class="suggestion-form" :style="{ top: bTop + -6 + 'px', left: bLeft + bWidth * 0.3 + 'px', width: suggestWidth + 'px'}" :class="{'suggest-active': isSuggestActive}" - :initialData="bContent" + :initial-data="bContent" + :suggest-type="suggestType" @onEnableForm="handleOnEnableForm" @onDisableForm="handleOnDisableForm" /> @@ -88,6 +89,10 @@ export default { type: String, default: '' }, + suggestType: { + type: String, + default: 'label' + }, canDelete: { type: Boolean, default: true @@ -127,7 +132,7 @@ export default { this.$emit("onDelete", this.bIndex) } }, - resizeBox (e) { + resizeBoxFromTopLeft (e) { if (this.bActive && this.isLeftCircleActive) { this.isOnResize = true var prevbLeft = this.bLeft diff --git a/frontend/components/label/Toolbar.vue b/frontend/components/label/Toolbar.vue new file mode 100644 index 0000000..11f170d --- /dev/null +++ b/frontend/components/label/Toolbar.vue @@ -0,0 +1,64 @@ +<template> + <div class="bg-toolbar"> + <div class="layout"> + <i + class="first-icon-margin icon fas fa-plus" + :class="{'active': activeIcon === 'add-box'}" + @click="handleClickEvent('add-box')" + /> + <i + class="icon fas fa-expand" + :class="{'active': activeIcon === 'resize-box'}" + @click="handleClickEvent('resize-box')" + /> + <i + class="icon fas fa-trash" + :class="{'active': activeIcon === 'delete-box'}" + @click="handleClickEvent('delete-box')" + /> + </div> + </div> +</template> + +<script scoped> +export default { + data () { + return { + activeIcon: 'add-box' + } + }, + methods: { + handleClickEvent (iconName) { + this.activeIcon = iconName + this.$emit("onIconClick", iconName) + } + } +} +</script> + +<style scoped> + .bg-toolbar { + background-color: #F7F7F7; + width: 3.75vw; + } + + .icon { + font-size: 1.1rem; + color: #707070; + margin-top: 27px; + } + + .first-icon-margin { + margin-top: 32px; + } + + .layout { + margin-left: calc(3.75vw - 2.1rem); + cursor: pointer; + } + + .active { + color: #009DFF; + } + +</style> \ No newline at end of file diff --git a/frontend/components/view/Suggest.vue b/frontend/components/view/Suggest.vue index e116058..81370f2 100644 --- a/frontend/components/view/Suggest.vue +++ b/frontend/components/view/Suggest.vue @@ -27,6 +27,10 @@ export default { initialData: { type: String, default: '' + }, + suggestType: { + type: String, + default: 'label' } }, data() { @@ -46,7 +50,11 @@ export default { this.simpleSuggestionList.push(content['content_name']) }) } - this.enableForm() + + if (this.suggestType !== 'edit') { + this.enableForm() + } + this.$watch(() => { if (this.$refs["form"].isInFocus) { this.enableForm() diff --git a/frontend/pages/viewer/index-edit.vue b/frontend/pages/viewer/index-edit.vue index 17c8c8a..d15104c 100644 --- a/frontend/pages/viewer/index-edit.vue +++ b/frontend/pages/viewer/index-edit.vue @@ -33,6 +33,7 @@ <Box v-if="boxes[i]" :key="i" + :suggest-type="'edit'" :b-width="boxes[i].width" :b-height="boxes[i].height" :b-top="boxes[i].top" @@ -89,6 +90,14 @@ export default { isEdited: false } }, + async created () { + window.addEventListener("beforeunload", async (event) => { + await this.closeViewer() + event.returnValue= "You have unsaved changes." + }) + await this.startHeartBeat() + this.timer = setInterval(this.startHeartBeat, 90000) + }, async mounted () { this.image.url = this.$route.query.url this.image.id = this.$route.query.id @@ -96,7 +105,21 @@ export default { this.dataReady = false this.dataReady = true }, + async beforeDestroy () { + // window.removeEventListener("beforeunload", true) + await this.closeViewer() + }, methods: { + async startHeartBeat() { + var url = '/api/accesscontrol/requestaccess/' + parseInt(this.$route.query.id) + // alert(url) + try { + await this.$axios.get(url).catch((error) => console.error(error)) + } catch (error) { + this.showFailedAlert("An error occured", error) + await this.closeViewer() + } + }, async getAllLabels () { var url = '/api/label/imagequery/' + this.image.id var response = await this.$axios.get(url).catch( error => console.error(error)) @@ -147,9 +170,25 @@ export default { console.log(this.boxes) console.log(this.previouslyCreatedBox) }, - closeViewer () { + async closeViewer () { + try { + await this.deleteImageAccessControlByImageID(this.image.id) + } catch (error) { + console.log(error) + } + clearInterval(this.timer) this.$router.push('/main/edit') }, + async deleteImageAccessControlByImageID (imageID) { + var url = '/api/accesscontrol/' + imageID + try { + var response = await this.$axios.delete(url) + return response.data.status + } catch (error) { + console.log("Label" , error) + throw error + } + }, onMouseDownHandler (e) { if (this.drawingBox.active) { this.stopDrawingBox() diff --git a/frontend/pages/viewer/index.vue b/frontend/pages/viewer/index.vue index 4094326..f179228 100644 --- a/frontend/pages/viewer/index.vue +++ b/frontend/pages/viewer/index.vue @@ -1,57 +1,67 @@ <template> <div ref="imageWrapper" class="viewer-background"> - <div class="btn-close-section"> - <button - type="button" - class="btn-label-no-border btn-sm btn-light btn-close-text mt-2" - aria-label="Close" - @click="closeViewer()" - > - <span aria-hidden="true">×</span> - </button> - </div> - <div class="viewer-wrapper center center-horizontal" @mousedown="stopDrawingBox"> - <div id="image"> - <img - ref="image" - draggable="false" - class="image" - :src="image.url" - @mousedown="onMouseDownHandler" - @mousemove="changeBox" - @mouseup="stopDrawingBox" - > - <Box - v-if="drawingBox.active" - :b-width="drawingBox.width" - :b-height="drawingBox.height" - :b-top="drawingBox.top" - :b-left="drawingBox.left" - /> - <div v-for="i in Object.keys(boxes)" :key="i"> - {{ i }} + <div class="flex-viewer"> + <Toolbar + @onIconClick="setBoxAction($event)" + /> + <div class="viewer-wrapper center center-horizontal" @mousedown="stopDrawingBox"> + <div id="image"> + <img + ref="image" + draggable="false" + class="image" + :src="image.url" + @mousedown="onMouseDownHandler" + @mousemove="changeBox" + @mouseup="stopDrawingBox" + > <Box - v-if="boxes[i]" - :key="i" - :b-width="boxes[i].width" - :b-height="boxes[i].height" - :b-top="boxes[i].top" - :b-left="boxes[i].left" - :b-active="i === activeBoxIndex" - :b-index="parseInt(i)" - :b-content="boxes[i].content" - :can-delete="canDelete" - @onStopResize="changeBoxAttribute($event, i)" - @onDelete="deleteBox(i)" - @onSelect="makeCurrentBoxActive(i)" - @onDisableForm="changeBoxContent($event, i)" - @onEnableForm="makeCurrentBoxActive(i)" + v-if="drawingBox.active" + :b-width="drawingBox.width" + :b-height="drawingBox.height" + :b-top="drawingBox.top" + :b-left="drawingBox.left" /> + <div v-for="i in Object.keys(boxes)" :key="i"> + <Box + v-if="boxes[i]" + :key="i" + :b-width="boxes[i].width" + :b-height="boxes[i].height" + :b-top="boxes[i].top" + :b-left="boxes[i].left" + :b-active="i === activeBoxIndex" + :b-index="parseInt(i)" + :b-content="boxes[i].content" + :can-delete="canDelete" + @onStopResize="changeBoxAttribute($event, i)" + @onDelete="deleteBox(i)" + @onSelect="makeCurrentBoxActive(i)" + @onDisableForm="changeBoxContent($event, i)" + @onEnableForm="makeCurrentBoxActive(i)" + /> + </div> + </div> + </div> + <div class="button-block"> + <div class="btn-close-section"> + <button + type="button" + class="btn-label-no-border btn-sm btn-light btn-close-text mt-2" + aria-label="Close" + @click="closeViewer()" + > + <span aria-hidden="true">×</span> + </button> </div> </div> </div> - <div class="btn-section"> - <button type="button" class="btn-label-no-border btn-lg btn-dark btn-text" @click="saveImage"> + <div class="btn-save-section"> + <button + type="button" + class="btn-label-no-border btn-lg btn-dark btn-text" + @click="saveImage" + > Save Image </button> </div> @@ -60,11 +70,13 @@ <script> import Box from '~/components/label/Box' +import Toolbar from '~/components/label/Toolbar' import { Cursors } from '~/mixins/label/getCursorPosition' export default { components: { - Box + Box, + Toolbar }, data () { return { @@ -114,6 +126,9 @@ export default { await this.closeViewer() } }, + setBoxAction (iconName) { + console.log("Icon name: ", iconName) + }, async closeViewer () { try { await this.deleteImageAccessControlByImageID(this.image.id) @@ -346,7 +361,7 @@ export default { } .viewer-wrapper { - height: 87.5vh; + /* height: 87.5vh; */ width: 100vw; } @@ -359,10 +374,10 @@ export default { justify-content: center; } - .btn-section { + .btn-save-section { text-align: right; - margin-right: 15px; - margin-top: -10px; + margin-top: -40px; + margin-right: 5px; } .btn-text { @@ -384,4 +399,18 @@ export default { border: 0; } + .btn-lg { + width: 115px; + } + + .flex-viewer { + display: flex; + height: 100vh; + } + + .button-block { + display: block; + height: 100vh; + } + </style> \ No newline at end of file -- GitLab