mirror of
				https://github.com/MarcZierle/photo-log-frontend.git
				synced 2025-11-02 18:24:57 +00:00 
			
		
		
		
	implement photo cropping - simple bbox
This commit is contained in:
		
							parent
							
								
									a9c8e2cbda
								
							
						
					
					
						commit
						2fa9b70bc2
					
				@ -89,3 +89,7 @@ export function updatePhoto(photo) {
 | 
			
		||||
export function deletePhoto(id) {
 | 
			
		||||
	return apiClient.delete('/deletephoto/'+id+'/')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function cropPhoto(id, mode) {
 | 
			
		||||
	return apiClient.get('/cropphoto/'+id+'/?mode='+mode)
 | 
			
		||||
}
 | 
			
		||||
@ -1,13 +1,28 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
		<n-space justify="start">
 | 
			
		||||
			<cropper
 | 
			
		||||
				class="cropper"
 | 
			
		||||
				:src="src"
 | 
			
		||||
			:stencil-props="{
 | 
			
		||||
				aspectRatio: 1/1.41421356
 | 
			
		||||
			}"
 | 
			
		||||
				:stencil-props="aspect_ratio"
 | 
			
		||||
				:auto-zoom="true"
 | 
			
		||||
				@change="change"
 | 
			
		||||
				ref="cropper"
 | 
			
		||||
			/>
 | 
			
		||||
 | 
			
		||||
			<n-space vertical justify="space-between">
 | 
			
		||||
				<div>
 | 
			
		||||
					<h2>Preview</h2>
 | 
			
		||||
					<n-image
 | 
			
		||||
						class="preview"
 | 
			
		||||
						height="200"
 | 
			
		||||
						:src="preview_data_url"
 | 
			
		||||
					/>
 | 
			
		||||
				</div>
 | 
			
		||||
 | 
			
		||||
				<n-checkbox v-model:checked="lock_aspect_ratio">lock aspect ratio to flip chart size?</n-checkbox>
 | 
			
		||||
			</n-space>
 | 
			
		||||
		</n-space>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@ -28,15 +43,48 @@ export default {
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
 | 
			
		||||
			preview_data_url: null,
 | 
			
		||||
			lock_aspect_ratio: true,
 | 
			
		||||
			bbox: []
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		console.log(this.src)
 | 
			
		||||
	computed: {
 | 
			
		||||
		aspect_ratio() { 
 | 
			
		||||
			if (this.lock_aspect_ratio) {
 | 
			
		||||
				return {
 | 
			
		||||
					aspectRatio: 1/1.41421356
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return {}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		coordinates_to_bbox(coordinates) {
 | 
			
		||||
			let top_left = [
 | 
			
		||||
				coordinates.left,
 | 
			
		||||
				coordinates.top
 | 
			
		||||
			]
 | 
			
		||||
			let top_right = [
 | 
			
		||||
				coordinates.left + coordinates.width,
 | 
			
		||||
				coordinates.top
 | 
			
		||||
			]
 | 
			
		||||
			let bottom_right = [
 | 
			
		||||
				coordinates.left + coordinates.width,
 | 
			
		||||
				coordinates.top + coordinates.height
 | 
			
		||||
			]
 | 
			
		||||
			let bottom_left = [
 | 
			
		||||
				coordinates.left,
 | 
			
		||||
				coordinates.top + coordinates.height
 | 
			
		||||
			]
 | 
			
		||||
 | 
			
		||||
			return [top_left, top_right, bottom_right, bottom_left]
 | 
			
		||||
		},
 | 
			
		||||
		change({ coordinates, canvas }) {
 | 
			
		||||
			console.log(coordinates, canvas)
 | 
			
		||||
			this.preview_data_url = canvas.toDataURL()
 | 
			
		||||
			this.bbox = this.coordinates_to_bbox(coordinates)
 | 
			
		||||
		},
 | 
			
		||||
		getResult() {
 | 
			
		||||
			return JSON.parse(JSON.stringify(this.bbox))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -48,4 +96,8 @@ export default {
 | 
			
		||||
	width: 600px;
 | 
			
		||||
	background: #DDD;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.preview {
 | 
			
		||||
	max-width: 300px;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@ -105,11 +105,16 @@ export default {
 | 
			
		||||
			type: Number,
 | 
			
		||||
			required: false,
 | 
			
		||||
			default: 150,
 | 
			
		||||
		}
 | 
			
		||||
		},
 | 
			
		||||
		init_selection: {
 | 
			
		||||
			type: Boolean,
 | 
			
		||||
			required: false,
 | 
			
		||||
			default: false,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	emits: [
 | 
			
		||||
		'update:select',
 | 
			
		||||
		'update:delet',
 | 
			
		||||
		'update:delete',
 | 
			
		||||
		'update:crop',
 | 
			
		||||
		'update:ocr',
 | 
			
		||||
		'update:group',
 | 
			
		||||
@ -126,6 +131,9 @@ export default {
 | 
			
		||||
	beforeMount() {
 | 
			
		||||
		this.imgSrcObj = new Image()
 | 
			
		||||
		this.imgSrcObj.src = this.src
 | 
			
		||||
		if (this.can_select && this.init_selection) {
 | 
			
		||||
			this.selected = true
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	watch: {
 | 
			
		||||
		imgSrcObj: {
 | 
			
		||||
@ -202,6 +210,7 @@ export default {
 | 
			
		||||
		toggleSelection() {
 | 
			
		||||
			if (this.can_select) {
 | 
			
		||||
				this.selected = !this.selected
 | 
			
		||||
				this.$emit('update:select', this.selected)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@ -27,18 +27,18 @@
 | 
			
		||||
						:title="group.name"
 | 
			
		||||
						:name="group.id">
 | 
			
		||||
					
 | 
			
		||||
						<n-image-group>
 | 
			
		||||
							<n-space>
 | 
			
		||||
								<n-image
 | 
			
		||||
								<PhotoItem
 | 
			
		||||
									v-for="photo in photos[group.id]"
 | 
			
		||||
									:key="photo.id"
 | 
			
		||||
									width="100"
 | 
			
		||||
									:src="photo.cropped_image !== null ? photo.cropped_image : photo.original_image"
 | 
			
		||||
									@click="toggle_select_photo(photo.id)"
 | 
			
		||||
									:class="{selected: is_photo_selected(photo.id)}"
 | 
			
		||||
									preview-disabled />
 | 
			
		||||
									:can_select="true"
 | 
			
		||||
									:init_selection="is_photo_selected(photo.id)"
 | 
			
		||||
									@update:select="toggle_select_photo(photo.id)"
 | 
			
		||||
									:ref="'photoitem-'+photo.id"
 | 
			
		||||
								/>
 | 
			
		||||
							</n-space>
 | 
			
		||||
						</n-image-group>
 | 
			
		||||
 | 
			
		||||
					<template #header-extra>{{group.date}}</template>
 | 
			
		||||
					</n-collapse-item>
 | 
			
		||||
@ -57,13 +57,13 @@
 | 
			
		||||
<script>
 | 
			
		||||
import { useMessage } from 'naive-ui'
 | 
			
		||||
 | 
			
		||||
//import PhotoItem from '@/components/PhotoItem'
 | 
			
		||||
import PhotoItem from '@/components/PhotoItem'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'PhotoSelectModal',
 | 
			
		||||
	emits: [ 'closed', 'selected' ],
 | 
			
		||||
	components: {
 | 
			
		||||
		//PhotoItem
 | 
			
		||||
		PhotoItem
 | 
			
		||||
	},
 | 
			
		||||
	props: {
 | 
			
		||||
		showSelection: {
 | 
			
		||||
@ -140,6 +140,7 @@ export default {
 | 
			
		||||
				if (this.selecions_left > 0) {
 | 
			
		||||
					this.selection.push(photo_id)
 | 
			
		||||
				} else {
 | 
			
		||||
					this.$refs['photoitem-'+photo_id][0].selected = false
 | 
			
		||||
					this.message.error('You can only select ' + this.max_select + ' photo(s)')
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ import {
 | 
			
		||||
	getPhotosByGroup,
 | 
			
		||||
	updatePhoto,
 | 
			
		||||
	deletePhoto,
 | 
			
		||||
	cropPhoto,
 | 
			
		||||
} from '@/api'
 | 
			
		||||
 | 
			
		||||
export default createStore({
 | 
			
		||||
@ -167,7 +168,20 @@ export default createStore({
 | 
			
		||||
					reject(error)
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		},
 | 
			
		||||
		cropPhoto({commit}, {id, mode}) {
 | 
			
		||||
			new Promise((resolve, reject) => {
 | 
			
		||||
				cropPhoto(id, mode).then((response) => {
 | 
			
		||||
					commit('UPDATE_PHOTO', {
 | 
			
		||||
						id: response.data.id,
 | 
			
		||||
						cropped_image: response.data.cropped_image
 | 
			
		||||
					})
 | 
			
		||||
					resolve()
 | 
			
		||||
				}).catch((error) => {
 | 
			
		||||
					reject(error)
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	getters: {
 | 
			
		||||
		photoLogById: (state) => (id) =>  {
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,9 @@
 | 
			
		||||
			<n-space justify="space-around" >
 | 
			
		||||
				<n-space vertical>
 | 
			
		||||
					<h2>Documents</h2>
 | 
			
		||||
					<a target="_blank" href='https://dev.marczierle.com/zierle-training/generate_document/modify_document.php?selection=0'>
 | 
			
		||||
						<n-button type="primary">All Documents</n-button>
 | 
			
		||||
					</a>
 | 
			
		||||
				</n-space>
 | 
			
		||||
				<n-space vertical>
 | 
			
		||||
					<h2>Photo Logs</h2>
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
		<n-table :bordered="false" :single-line="true">
 | 
			
		||||
			<thead>
 | 
			
		||||
				<th>Photo Log Title</th>
 | 
			
		||||
				<th>PDF</th>
 | 
			
		||||
				<th>Date created</th>
 | 
			
		||||
				<th>delete</th>
 | 
			
		||||
			</thead>
 | 
			
		||||
@ -12,6 +13,9 @@
 | 
			
		||||
					<router-link :to="{name: 'CreateLog', params: {e: photolog.id}}">
 | 
			
		||||
						<td>{{ photolog.title }}</td>
 | 
			
		||||
					</router-link>
 | 
			
		||||
					<td>
 | 
			
		||||
						<a :href="photolog.pdf" target="_blank">PDF</a>
 | 
			
		||||
					</td>
 | 
			
		||||
					<td>{{ photolog.date }}</td>
 | 
			
		||||
					<td>
 | 
			
		||||
						<n-button type="error" @click="askDeleteLog(photolog.id)">Delete</n-button>
 | 
			
		||||
 | 
			
		||||
@ -40,15 +40,17 @@
 | 
			
		||||
				title="Adjust Photo Cropping"
 | 
			
		||||
				:bordered="true"
 | 
			
		||||
			>
 | 
			
		||||
				<template #header-extra> Header </template>
 | 
			
		||||
 | 
			
		||||
				<PhotoCropper :src="current_photo_src" />
 | 
			
		||||
				<PhotoCropper
 | 
			
		||||
					style="max-width:900px;margin:auto;"
 | 
			
		||||
					:src="current_photo_src"
 | 
			
		||||
					ref="cropper"
 | 
			
		||||
				/>
 | 
			
		||||
				
 | 
			
		||||
				<template #footer> Footer </template>
 | 
			
		||||
				<template #action>
 | 
			
		||||
					<n-space justify="end">
 | 
			
		||||
						<n-button @click="showCropModal = false">Cancel</n-button>
 | 
			
		||||
						<n-button type="primary">Save</n-button>
 | 
			
		||||
						<n-button type="primary" @click="changeCrop">Save</n-button>
 | 
			
		||||
					</n-space>
 | 
			
		||||
				</template>
 | 
			
		||||
			</n-card>
 | 
			
		||||
@ -242,6 +244,25 @@ export default {
 | 
			
		||||
				})
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		changeCrop() {
 | 
			
		||||
			let bbox = this.$refs.cropper.getResult()
 | 
			
		||||
			if (bbox && this.current_photo) {
 | 
			
		||||
				this.$store.dispatch('updatePhoto', {
 | 
			
		||||
					id: this.current_photo,
 | 
			
		||||
					bbox_coords: bbox
 | 
			
		||||
				}).then(()=>{
 | 
			
		||||
					setTimeout(()=>{
 | 
			
		||||
						this.$store.dispatch('cropPhoto', {
 | 
			
		||||
							id: this.current_photo,
 | 
			
		||||
							mode: 'bbox'
 | 
			
		||||
						}).then(()=>{
 | 
			
		||||
							this.current_photo = null
 | 
			
		||||
							this.showCropModal = false
 | 
			
		||||
						})
 | 
			
		||||
					}, 100)
 | 
			
		||||
				})
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		changeOCRText(){
 | 
			
		||||
			if (this.current_ocr_text.length !== null && this.current_photo) {
 | 
			
		||||
				this.$store.dispatch('updatePhoto', {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user