Basic scan grouping
This commit is contained in:
parent
2756185ef6
commit
4428e8906f
3 changed files with 221 additions and 37 deletions
|
|
@ -0,0 +1,90 @@
|
||||||
|
<template>
|
||||||
|
<div class="captureCard uk-card uk-card-primary uk-card-hover uk-padding-remove uk-width-medium uk-margin-right">
|
||||||
|
|
||||||
|
<div class="uk-card-media-top">
|
||||||
|
<img class="uk-width-1-1" v-bind:src="thumbnail" v-bind:alt="metadata.scan_id" uk-img>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-card-body uk-padding-small">
|
||||||
|
<div class="uk-width-1-1 uk-margin-small uk-margin-remove-left uk-margin-remove-right" uk-grid>
|
||||||
|
<div class="uk-margin-remove-top uk-padding-remove uk-width-expand"><b>Scan:</b> {{ metadata.custom.basename }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-expand"><time>{{ betterTimestring }}</time></div>
|
||||||
|
<div class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-auto">
|
||||||
|
<a v-bind:href="metadataModalTarget" uk-toggle>More...</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-card-footer uk-padding-small">
|
||||||
|
<span v-for="tag in metadata.tags" :key="tag" class="uk-label uk-margin-small-right deletable-label"> {{ tag }} </span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-bind:id="metadataModalID" uk-modal>
|
||||||
|
|
||||||
|
<div class="uk-modal-dialog uk-modal-body">
|
||||||
|
<button class="uk-modal-close-default" type="button" uk-close></button>
|
||||||
|
<h2 class="uk-modal-title">{{ metadata.basename }}</h2>
|
||||||
|
<p><b>Time: </b>{{ betterTimestring }}</p>
|
||||||
|
<p><b>Scan ID: </b>{{ metadata.custom.scan_id }}</p>
|
||||||
|
|
||||||
|
<div v-for="(value, key) in metadata.custom" :key="key" >
|
||||||
|
<p><b>{{ key }}: </b>{{ value }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import UIkit from 'uikit';
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
// Export main app
|
||||||
|
export default {
|
||||||
|
name: 'captureCard',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
metadata: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
makeModalName: function(prefix) {
|
||||||
|
return prefix + this.metadata.id
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
tagModalID: function () {
|
||||||
|
return this.makeModalName("tag-modal-")
|
||||||
|
},
|
||||||
|
tagModalTarget: function () {
|
||||||
|
return "#" + this.tagModalID
|
||||||
|
},
|
||||||
|
metadataModalID: function () {
|
||||||
|
return this.makeModalName("metadata-modal-")
|
||||||
|
},
|
||||||
|
metadataModalTarget: function () {
|
||||||
|
return "#" + this.metadataModalID
|
||||||
|
},
|
||||||
|
betterTimestring: function () {
|
||||||
|
var dtSplit = this.metadata.custom.time.split("_");
|
||||||
|
var date = dtSplit[0]
|
||||||
|
var time = dtSplit[1].replace(/-/g, ":")
|
||||||
|
return date + " " + time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -26,13 +26,19 @@
|
||||||
|
|
||||||
<div v-if="$store.getters.ready" class="uk-padding-remove-top" uk-lightbox="toggle: .lightbox-link">
|
<div v-if="$store.getters.ready" class="uk-padding-remove-top" uk-lightbox="toggle: .lightbox-link">
|
||||||
<div class="uk-grid-medium uk-padding uk-padding-remove-right uk-grid-match" uk-grid>
|
<div class="uk-grid-medium uk-padding uk-padding-remove-right uk-grid-match" uk-grid>
|
||||||
|
|
||||||
<captureCard
|
<div v-for="item in sortedItems" :key="item.metadata.id">
|
||||||
v-for="capture in sortedDateCaptures"
|
<captureCard
|
||||||
:key="capture.metadata.id"
|
v-if="!('isScan' in item)"
|
||||||
:metadata="capture.metadata"
|
:metadata="item.metadata"
|
||||||
:temporary="capture.temporary"
|
:temporary="item.temporary"
|
||||||
/>
|
/>
|
||||||
|
<scanCard
|
||||||
|
v-else
|
||||||
|
:metadata="item.metadata"
|
||||||
|
:thumbnail="item.thumbnail"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -44,20 +50,23 @@
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import captureCard from './galleryComponents/captureCard.vue'
|
import captureCard from './galleryComponents/captureCard.vue'
|
||||||
|
import scanCard from './galleryComponents/scanCard.vue'
|
||||||
|
|
||||||
// Export main app
|
// Export main app
|
||||||
export default {
|
export default {
|
||||||
name: 'galleryDisplay',
|
name: 'galleryDisplay',
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
captureCard
|
captureCard,
|
||||||
|
scanCard
|
||||||
},
|
},
|
||||||
|
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
captureList: [],
|
captureList: [],
|
||||||
checkedTags: [],
|
checkedTags: [],
|
||||||
sortDescending: true
|
sortDescending: true,
|
||||||
|
scanTag: 'scan'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -80,7 +89,47 @@ export default {
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.$store.dispatch('handleHTTPError', error); // Let store handle error
|
this.$store.dispatch('handleHTTPError', error); // Let store handle error
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
filterCaptureList: function(list, filterTags) {
|
||||||
|
var result = [];
|
||||||
|
for (var capture of list) {
|
||||||
|
// Assume exclusion
|
||||||
|
var includeCapture = false;
|
||||||
|
|
||||||
|
// Filter by selected tags
|
||||||
|
var tags = capture.metadata.tags;
|
||||||
|
let checker = (arr, target) => target.every(v => arr.includes(v));
|
||||||
|
// True if all tags match
|
||||||
|
includeCapture = checker(tags, filterTags);
|
||||||
|
|
||||||
|
// Add to capture list if matched
|
||||||
|
if (includeCapture == true) {
|
||||||
|
result.push(capture);
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
|
||||||
|
sortCaptureList: function(list) {
|
||||||
|
function compare(a, b) {
|
||||||
|
if (a.metadata.time < b.metadata.time)
|
||||||
|
return -1;
|
||||||
|
if (a.metadata.time > b.metadata.time)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.sortDescending == true) {
|
||||||
|
return list.sort(compare).reverse();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return list.sort(compare);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -91,10 +140,8 @@ export default {
|
||||||
allTags: function () {
|
allTags: function () {
|
||||||
// Return an array of unique tags across all captures
|
// Return an array of unique tags across all captures
|
||||||
var tags = [];
|
var tags = [];
|
||||||
for (var i in this.captureList) {
|
for (var capture of this.captureList) {
|
||||||
var capture = this.captureList[i]
|
for (var tag of capture.metadata.tags) {
|
||||||
for (var j in capture.metadata.tags) {
|
|
||||||
var tag = capture.metadata.tags[j];
|
|
||||||
if (!tags.includes(tag)) {
|
if (!tags.includes(tag)) {
|
||||||
tags.push(tag);
|
tags.push(tag);
|
||||||
};
|
};
|
||||||
|
|
@ -103,45 +150,92 @@ export default {
|
||||||
return tags.sort()
|
return tags.sort()
|
||||||
},
|
},
|
||||||
|
|
||||||
filteredCaptures: function () {
|
noScanCaptureList: function () {
|
||||||
var captures = [];
|
var captures = [];
|
||||||
for (var i in this.captureList) {
|
for (var capture of this.captureList) {
|
||||||
// Quickly access capture object
|
|
||||||
var capture = this.captureList[i];
|
|
||||||
// Assume exclusion
|
// Assume exclusion
|
||||||
var includeCapture = false;
|
var includeCapture = false;
|
||||||
|
|
||||||
// Filter by selected tags
|
// Filter by selected tags
|
||||||
var tags = capture.metadata.tags;
|
var tags = capture.metadata.tags;
|
||||||
let checker = (arr, target) => target.every(v => arr.includes(v));
|
|
||||||
// True if all tags match
|
|
||||||
includeCapture = checker(tags, this.checkedTags);
|
|
||||||
|
|
||||||
// Add to capture list if matched
|
// Add to capture list if matched
|
||||||
if (includeCapture == true) {
|
if (!tags.includes(this.scanTag)) {
|
||||||
captures.push(capture);
|
captures.push(capture);
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return captures
|
return captures
|
||||||
},
|
},
|
||||||
|
|
||||||
sortedDateCaptures: function () {
|
allScans: function () {
|
||||||
function compare(a, b) {
|
// Return an array of unique tags across all captures
|
||||||
if (a.metadata.time < b.metadata.time)
|
var scans = {};
|
||||||
return -1;
|
|
||||||
if (a.metadata.time > b.metadata.time)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.sortDescending == true) {
|
for (var capture of this.captureList) {
|
||||||
return this.filteredCaptures.sort(compare).reverse();
|
var custom = capture.metadata.custom;
|
||||||
}
|
var tags = capture.metadata.tags;
|
||||||
else {
|
|
||||||
return this.filteredCaptures.sort(compare);
|
if ('scan_id' in custom) {
|
||||||
}
|
var id = custom['scan_id']
|
||||||
|
|
||||||
|
// If this scan ID hasn't been seen before
|
||||||
|
if (!(id in scans)) {
|
||||||
|
scans[id] = {}
|
||||||
|
scans[id].isScan = true
|
||||||
|
scans[id].captureList = []
|
||||||
|
scans[id].metadata = {
|
||||||
|
filename: custom.basename,
|
||||||
|
time: custom.time,
|
||||||
|
id: custom.scan_id
|
||||||
|
}
|
||||||
|
scans[id].metadata.tags = []
|
||||||
|
scans[id].metadata.custom = {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add the capture object to the scan
|
||||||
|
scans[id].captureList.push(capture)
|
||||||
|
|
||||||
|
// Add missing scan metadata, prioritising first capture
|
||||||
|
for (var key of Object.keys(custom)) {
|
||||||
|
if (!(key in scans[id].metadata.custom)) {
|
||||||
|
scans[id].metadata.custom[key] = custom[key]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Append missing tags
|
||||||
|
for (var tag of tags) {
|
||||||
|
if (!scans[id].metadata.tags.includes(tag)) {
|
||||||
|
scans[id].metadata.tags.push(tag)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a preview thumbnail
|
||||||
|
if (!('thumbnail' in scans[id])) {
|
||||||
|
scans[id].thumbnail = this.$store.getters.uri + "/camera/capture/" + capture.metadata.id + "/download?thumbnail=true"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return scans
|
||||||
|
},
|
||||||
|
|
||||||
|
scanList: function () {
|
||||||
|
return Object.values(this.allScans)
|
||||||
|
},
|
||||||
|
|
||||||
|
itemList: function () {
|
||||||
|
return this.noScanCaptureList.concat(this.scanList)
|
||||||
|
},
|
||||||
|
|
||||||
|
filteredItems: function () {
|
||||||
|
return this.filterCaptureList(this.itemList, this.checkedTags)
|
||||||
|
},
|
||||||
|
|
||||||
|
sortedItems: function () {
|
||||||
|
return this.sortCaptureList(this.filteredItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
recalibrateConfirm: function() {
|
recalibrateConfirm: function() {
|
||||||
context = this
|
var context = this
|
||||||
this.modalConfirm('Start recalibration? This may take a while, and the microscope will be locked during this time.')
|
this.modalConfirm('Start recalibration? This may take a while, and the microscope will be locked during this time.')
|
||||||
.then(function() {
|
.then(function() {
|
||||||
context.recalibrateRequest()
|
context.recalibrateRequest()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue