diff --git a/src/public/assets/scripts/main.js b/src/public/assets/scripts/main.js index aea8bf3..9c26eb7 100644 --- a/src/public/assets/scripts/main.js +++ b/src/public/assets/scripts/main.js @@ -1 +1 @@ -biigle.$viewModel("maia-job-form",function(e){new Vue({el:e,data:{showAdvanced:!1},methods:{toggle:function(){this.showAdvanced=!this.showAdvanced}}})}),biigle.$viewModel("maia-show-container",function(e){var t=biigle.$require("maia.job"),n=biigle.$require("maia.states"),i=biigle.$require("maia.api.maiaJob"),r=biigle.$require("maia.api.maiaAnnotation"),s=biigle.$require("messages.store"),a=biigle.$require("annotations.stores.images");new Vue({el:e,mixins:[biigle.$require("core.mixins.loader")],components:{sidebar:biigle.$require("annotations.components.sidebar"),sidebarTab:biigle.$require("core.components.sidebarTab"),selectTpTab:biigle.$require("maia.components.selectTpTab"),tpImageGrid:biigle.$require("maia.components.tpImageGrid"),refineTpTab:biigle.$require("maia.components.refineTpTab"),refineTpCanvas:biigle.$require("maia.components.refineTpCanvas")},data:{visitedSelectTpTab:!1,visitedRefineTpTab:!1,visitedReviewAcTab:!1,openTab:"info",trainingProposals:[],selectTpOffset:0,lastSelectedTp:null,currentImage:null,currentTpIndex:0},computed:{infoTabOpen:function(){return"info"===this.openTab},selectTpTabOpen:function(){return"select-training-proposals"===this.openTab},refineTpTabOpen:function(){return"refine-training-proposals"===this.openTab},reviewAcTabOpen:function(){return"review-annotation-candidates"===this.openTab},hasTrainingProposals:function(){return this.trainingProposals.length>0},isInTrainingProposalState:function(){return t.state_id===n["training-proposals"]},imageIds:function(){var e={};return this.trainingProposals.map(function(e){return e.image_id}).filter(function(t){return!e.hasOwnProperty(t)&&(e[t]=!0)})},tpById:function(){var e={};return this.trainingProposals.forEach(function(t){e[t.id]=t}),e},tpOrderedByImageId:function(){return this.trainingProposals.slice().sort(function(e,t){return e.image_id-t.image_id})},selectedTpOrderedByImageId:function(){return this.tpOrderedByImageId.filter(function(e){return e.selected})},previousTpIndex:function(){return(this.currentTpIndex+this.selectedTpOrderedByImageId.length-1)%this.selectedTpOrderedByImageId.length},nextTpIndex:function(){return(this.currentTpIndex+1)%this.selectedTpOrderedByImageId.length},currentTp:function(){return this.selectedTpOrderedByImageId.length>0&&this.refineTpTabOpen?this.selectedTpOrderedByImageId[this.currentTpIndex]:null},hasNoSelectedTp:function(){return 0===this.selectedTpOrderedByImageId.length},currentImageIdsIndex:function(){return this.imageIds.indexOf(this.currentImageId)},currentImageId:function(){return this.currentTp?this.currentTp.image_id:null},previousImageIdsIndex:function(){return(this.currentImageIdsIndex+this.imageIds.length-1)%this.imageIds.length},previousImageId:function(){return this.imageIds[this.nextImageIdsIndex]},nextImageIdsIndex:function(){return(this.currentImageIdsIndex+1)%this.imageIds.length},nextImageId:function(){return this.imageIds[this.nextImageIdsIndex]},tpForCurrentImage:function(){return this.hasCurrentImage?this.trainingProposals.filter(function(e){return e.image_id===this.currentImageId},this):[]},selectedTpForCurrentImage:function(){return this.tpForCurrentImage.filter(function(e){return e.selected})},unSelectedTpForCurrentImage:function(){return this.tpForCurrentImage.filter(function(e){return!e.selected})},currentTpArray:function(){return this.hasCurrentImage&&this.currentTp?[this.currentTp]:[]},hasCurrentImage:function(){return null!==this.currentImage},visitedSelectOrRefineTpTab:function(){return this.visitedSelectTpTab||this.visitedRefineTpTab},selectedAndSeenTps:function(){return this.selectedTpOrderedByImageId.filter(function(e){return e.seen})}},methods:{handleSidebarToggle:function(){this.$nextTick(function(){this.$refs.imageGrid.$emit("resize")})},handleTabOpened:function(e){this.openTab=e},setTrainingProposals:function(e){this.trainingProposals=e.body.map(function(e){return e.shape="Circle",e.seen=!1,e})},fetchTrainingProposals:function(){return this.startLoading(),i.getTrainingProposals({id:t.id}).then(this.setTrainingProposals).catch(s.handleErrorResponse).finally(this.finishLoading)},openRefineTpTab:function(){this.openTab="refine-training-proposals"},handleSelectedTrainingProposal:function(e,t){e.selected?this.updateSelectTrainingProposal(e,!1):t.shiftKey&&this.lastSelectedTp?this.selectAllTpBetween(e,this.lastSelectedTp):(this.lastSelectedTp=e,this.updateSelectTrainingProposal(e,!0))},updateSelectTpOffset:function(e){this.selectTpOffset=e},selectAllTpBetween:function(e,t){var n=this.trainingProposals.indexOf(e),i=this.trainingProposals.indexOf(t);if(i0&&this.$emit("unselect-tp",this.selectedAnnotations[0])}},watch:{unselectedAnnotations:function(e){this.refreshAnnotationSource(e,this.unselectedAnnotationSource)},selectingTp:function(e){this.selectTpInteraction.setActive(e)}},created:function(){this.createUnselectedAnnotationsLayer(),this.map.addLayer(this.unselectedAnnotationLayer),this.selectInteraction.setActive(!1),this.canModify&&(this.createSelectTpInteraction(this.unselectedAnnotationFeatures),this.map.addInteraction(this.selectTpInteraction),biigle.$require("keyboard").on("Delete",this.handleUnselectTp))}}),biigle.$component("maia.components.refineTpTab",{props:{selectedTrainingProposals:{type:Array,required:!0},seenTrainingProposals:{type:Array,required:!0}},data:function(){return{}},computed:{numberSelectedTps:function(){return this.selectedTrainingProposals.length},numberSeenTps:function(){return this.seenTrainingProposals.length},hasNoSelectedTp:function(){return 0===this.numberSelectedTps},hasSeenAllSelectedTps:function(){return this.numberSelectedTps>0&&this.numberSelectedTps===this.numberSeenTps},textClass:function(){return this.hasSeenAllSelectedTps?"text-success":""},buttonClass:function(){return this.hasSeenAllSelectedTps?"btn-success":"btn-default"}},methods:{},created:function(){}}),biigle.$component("maia.components.selectTpTab",{props:{trainingProposals:{type:Array,required:!0}},data:function(){return{}},computed:{selectedTp:function(){return this.trainingProposals.filter(function(e){return e.selected})},selectedTpCount:function(){return this.selectedTp.length},tpCount:function(){return this.trainingProposals.length}},methods:{proceed:function(){this.$emit("proceed")}},created:function(){}}),biigle.$component("maia.components.tpImageGrid",{mixins:[biigle.$require("volumes.components.imageGrid")],components:{imageGridImage:biigle.$require("maia.components.tpImageGridImage")}}),biigle.$component("maia.components.tpImageGridImage",{mixins:[biigle.$require("volumes.components.imageGridImage")],template:'
',computed:{showAnnotationLink:function(){return!1},selected:function(){return this.image.selected},title:function(){if(this.selectable)return this.selected?"Undo marking as interesting":"Mark as interesting"}},methods:{getBlob:function(){return biigle.$require("maia.api.maiaAnnotation").getFile({id:this.image.id})}}}),biigle.$declare("maia.api.maiaAnnotation",Vue.resource("api/v1/maia-annotations{/id}",{},{getFile:{method:"GET",url:"api/v1/maia-annotations{/id}/file"}})),biigle.$declare("maia.api.maiaJob",Vue.resource("api/v1/maia-jobs{/id}",{},{save:{method:"POST",url:"api/v1/volumes{/id}/maia-jobs"},getTrainingProposals:{method:"GET",url:"api/v1/maia-jobs{/id}/training-proposals"}})); \ No newline at end of file +biigle.$viewModel("maia-job-form",function(e){new Vue({el:e,data:{showAdvanced:!1},methods:{toggle:function(){this.showAdvanced=!this.showAdvanced}}})}),biigle.$viewModel("maia-show-container",function(e){var t=biigle.$require("maia.job"),n=biigle.$require("maia.states"),i=biigle.$require("maia.api.maiaJob"),a=biigle.$require("maia.api.maiaAnnotation"),s=biigle.$require("messages.store"),r=biigle.$require("annotations.stores.images");new Vue({el:e,mixins:[biigle.$require("core.mixins.loader")],components:{sidebar:biigle.$require("annotations.components.sidebar"),sidebarTab:biigle.$require("core.components.sidebarTab"),selectTpTab:biigle.$require("maia.components.selectTpTab"),tpImageGrid:biigle.$require("maia.components.tpImageGrid"),refineTpTab:biigle.$require("maia.components.refineTpTab"),refineTpCanvas:biigle.$require("maia.components.refineTpCanvas"),reviewAcTab:biigle.$require("maia.components.reviewAcTab"),acImageGrid:biigle.$require("maia.components.acImageGrid")},data:{visitedSelectTpTab:!1,visitedRefineTpTab:!1,visitedReviewAcTab:!1,openTab:"info",trainingProposals:[],selectTpOffset:0,lastSelectedTp:null,currentImage:null,currentTpIndex:0,annotationCandidates:[],reviewAcOffset:0},computed:{infoTabOpen:function(){return"info"===this.openTab},selectTpTabOpen:function(){return"select-training-proposals"===this.openTab},refineTpTabOpen:function(){return"refine-training-proposals"===this.openTab},reviewAcTabOpen:function(){return"review-annotation-candidates"===this.openTab},hasTrainingProposals:function(){return this.trainingProposals.length>0},hasAnnotationCandidates:function(){return this.annotationCandidates.length>0},isInTrainingProposalState:function(){return t.state_id===n["training-proposals"]},isInAnnotationCandidateState:function(){return t.state_id===n["annotation-candidates"]},imageIds:function(){var e={};return this.trainingProposals.map(function(e){return e.image_id}).filter(function(t){return!e.hasOwnProperty(t)&&(e[t]=!0)})},tpById:function(){var e={};return this.trainingProposals.forEach(function(t){e[t.id]=t}),e},tpOrderedByImageId:function(){return this.trainingProposals.slice().sort(function(e,t){return e.image_id-t.image_id})},selectedTpOrderedByImageId:function(){return this.tpOrderedByImageId.filter(function(e){return e.selected})},previousTpIndex:function(){return(this.currentTpIndex+this.selectedTpOrderedByImageId.length-1)%this.selectedTpOrderedByImageId.length},nextTpIndex:function(){return(this.currentTpIndex+1)%this.selectedTpOrderedByImageId.length},currentTp:function(){return this.selectedTpOrderedByImageId.length>0&&this.refineTpTabOpen?this.selectedTpOrderedByImageId[this.currentTpIndex]:null},hasNoSelectedTp:function(){return 0===this.selectedTpOrderedByImageId.length},currentImageIdsIndex:function(){return this.imageIds.indexOf(this.currentImageId)},currentImageId:function(){return this.currentTp?this.currentTp.image_id:null},previousImageIdsIndex:function(){return(this.currentImageIdsIndex+this.imageIds.length-1)%this.imageIds.length},previousImageId:function(){return this.imageIds[this.nextImageIdsIndex]},nextImageIdsIndex:function(){return(this.currentImageIdsIndex+1)%this.imageIds.length},nextImageId:function(){return this.imageIds[this.nextImageIdsIndex]},tpForCurrentImage:function(){return this.hasCurrentImage?this.trainingProposals.filter(function(e){return e.image_id===this.currentImageId},this):[]},selectedTpForCurrentImage:function(){return this.tpForCurrentImage.filter(function(e){return e.selected})},unSelectedTpForCurrentImage:function(){return this.tpForCurrentImage.filter(function(e){return!e.selected})},currentTpArray:function(){return this.hasCurrentImage&&this.currentTp?[this.currentTp]:[]},hasCurrentImage:function(){return null!==this.currentImage},visitedSelectOrRefineTpTab:function(){return this.visitedSelectTpTab||this.visitedRefineTpTab},selectedAndSeenTps:function(){return this.selectedTpOrderedByImageId.filter(function(e){return e.seen})}},methods:{handleSidebarToggle:function(){this.$nextTick(function(){this.$refs.imageGrid.$emit("resize")})},handleTabOpened:function(e){this.openTab=e},setTrainingProposals:function(e){this.trainingProposals=e.body.map(function(e){return e.shape="Circle",e.seen=!1,e})},fetchTrainingProposals:function(){return this.startLoading(),i.getTrainingProposals({id:t.id}).then(this.setTrainingProposals).catch(s.handleErrorResponse).finally(this.finishLoading)},openRefineTpTab:function(){this.openTab="refine-training-proposals"},handleSelectedTrainingProposal:function(e,t){e.selected?this.updateSelectTrainingProposal(e,!1):t.shiftKey&&this.lastSelectedTp?this.selectAllTpBetween(e,this.lastSelectedTp):(this.lastSelectedTp=e,this.updateSelectTrainingProposal(e,!0))},updateSelectTpOffset:function(e){this.selectTpOffset=e},updateReviewAcOffset:function(e){this.reviewAcOffset=e},selectAllTpBetween:function(e,t){var n=this.trainingProposals.indexOf(e),i=this.trainingProposals.indexOf(t);if(i
',computed:{showAnnotationLink:function(){return!1},selected:function(){return this.image.selected},title:function(){return this.selected?"Remove selected label":"Assign selected label"}},methods:{getBlob:function(){return biigle.$require("maia.api.maiaAnnotation").getFile({id:this.image.id})}}}),biigle.$component("maia.components.refineTpCanvas",{mixins:[biigle.$require("annotations.components.annotationCanvas")],props:{unselectedAnnotations:{type:Array,default:function(){return[]}}},data:function(){return{selectingTp:!1}},computed:{},methods:{toggleMarkAsInteresting:function(){this.selectingTp=!this.selectingTp},createUnselectedAnnotationsLayer:function(){this.unselectedAnnotationFeatures=new ol.Collection,this.unselectedAnnotationSource=new ol.source.Vector({features:this.unselectedAnnotationFeatures}),this.unselectedAnnotationLayer=new ol.layer.Vector({source:this.unselectedAnnotationSource,zIndex:50,updateWhileAnimating:!0,updateWhileInteracting:!0,style:biigle.$require("annotations.stores.styles").editing,opacity:.5})},createSelectTpInteraction:function(e){var t=biigle.$require("annotations.ol.AttachLabelInteraction");this.selectTpInteraction=new t({map:this.map,features:e}),this.selectTpInteraction.setActive(!1),this.selectTpInteraction.on("attach",this.handleSelectTp)},handleSelectTp:function(e){this.$emit("select-tp",e.feature.get("annotation"))},handleUnselectTp:function(){this.selectedAnnotations.length>0&&this.$emit("unselect-tp",this.selectedAnnotations[0])}},watch:{unselectedAnnotations:function(e){this.refreshAnnotationSource(e,this.unselectedAnnotationSource)},selectingTp:function(e){this.selectTpInteraction.setActive(e)}},created:function(){this.createUnselectedAnnotationsLayer(),this.map.addLayer(this.unselectedAnnotationLayer),this.selectInteraction.setActive(!1),this.canModify&&(this.createSelectTpInteraction(this.unselectedAnnotationFeatures),this.map.addInteraction(this.selectTpInteraction),biigle.$require("keyboard").on("Delete",this.handleUnselectTp))}}),biigle.$component("maia.components.refineTpTab",{props:{selectedTrainingProposals:{type:Array,required:!0},seenTrainingProposals:{type:Array,required:!0}},data:function(){return{}},computed:{numberSelectedTps:function(){return this.selectedTrainingProposals.length},numberSeenTps:function(){return this.seenTrainingProposals.length},hasNoSelectedTp:function(){return 0===this.numberSelectedTps},hasSeenAllSelectedTps:function(){return this.numberSelectedTps>0&&this.numberSelectedTps===this.numberSeenTps},textClass:function(){return this.hasSeenAllSelectedTps?"text-success":""},buttonClass:function(){return this.hasSeenAllSelectedTps?"btn-success":"btn-default"}},methods:{},created:function(){}}),biigle.$component("maia.components.reviewAcTab",{props:{},data:function(){return{}},computed:{},methods:{},created:function(){}}),biigle.$component("maia.components.selectTpTab",{props:{trainingProposals:{type:Array,required:!0}},data:function(){return{}},computed:{selectedTp:function(){return this.trainingProposals.filter(function(e){return e.selected})},selectedTpCount:function(){return this.selectedTp.length},tpCount:function(){return this.trainingProposals.length}},methods:{proceed:function(){this.$emit("proceed")}},created:function(){}}),biigle.$component("maia.components.tpImageGrid",{mixins:[biigle.$require("volumes.components.imageGrid")],components:{imageGridImage:biigle.$require("maia.components.tpImageGridImage")}}),biigle.$component("maia.components.tpImageGridImage",{mixins:[biigle.$require("volumes.components.imageGridImage")],template:'
',computed:{showAnnotationLink:function(){return!1},selected:function(){return this.image.selected},title:function(){if(this.selectable)return this.selected?"Undo marking as interesting":"Mark as interesting"}},methods:{getBlob:function(){return biigle.$require("maia.api.maiaAnnotation").getFile({id:this.image.id})}}}); \ No newline at end of file diff --git a/src/resources/assets/js/components/acImageGrid.js b/src/resources/assets/js/components/acImageGrid.js new file mode 100644 index 0000000..98265a0 --- /dev/null +++ b/src/resources/assets/js/components/acImageGrid.js @@ -0,0 +1,11 @@ +/** + * A variant of the image grid used for the selection of MAIA annotation candidates. + * + * @type {Object} + */ +biigle.$component('maia.components.acImageGrid', { + mixins: [biigle.$require('volumes.components.imageGrid')], + components: { + imageGridImage: biigle.$require('maia.components.acImageGridImage'), + }, +}); diff --git a/src/resources/assets/js/components/acImageGridImage.js b/src/resources/assets/js/components/acImageGridImage.js new file mode 100644 index 0000000..cdf7adb --- /dev/null +++ b/src/resources/assets/js/components/acImageGridImage.js @@ -0,0 +1,35 @@ +/** + * A variant of the image grid image used for the selection of MAIA annotation candidates. + * + * @type {Object} + */ +biigle.$component('maia.components.acImageGridImage', { + mixins: [biigle.$require('volumes.components.imageGridImage')], + template: '
' + + '
' + + '' + + '
' + + '' + + '
' + + '' + + '' + + '' + + '
' + + '
', + computed: { + showAnnotationLink: function () { + return false; + }, + selected: function () { + return this.image.selected; + }, + title: function () { + return this.selected ? 'Remove selected label' : 'Assign selected label'; + }, + }, + methods: { + getBlob: function () { + return biigle.$require('maia.api.maiaAnnotation').getFile({id: this.image.id}); + }, + }, +}); diff --git a/src/resources/assets/js/components/reviewAcTab.js b/src/resources/assets/js/components/reviewAcTab.js new file mode 100644 index 0000000..f0a70d1 --- /dev/null +++ b/src/resources/assets/js/components/reviewAcTab.js @@ -0,0 +1,24 @@ +/** + * The review annotation candidates tab + * + * @type {Object} + */ +biigle.$component('maia.components.reviewAcTab', { + props: { + // + }, + data: function () { + return { + // + }; + }, + computed: { + // + }, + methods: { + // + }, + created: function () { + // + }, +}); diff --git a/src/resources/assets/js/components/tpImageGridImage.js b/src/resources/assets/js/components/tpImageGridImage.js index 25e6b2f..eec8280 100644 --- a/src/resources/assets/js/components/tpImageGridImage.js +++ b/src/resources/assets/js/components/tpImageGridImage.js @@ -19,8 +19,6 @@ biigle.$component('maia.components.tpImageGridImage', { computed: { showAnnotationLink: function () { return false; - // var route = biigle.$require('largo.showAnnotationRoute'); - // return route ? (route + this.image.id) : ''; }, selected: function () { return this.image.selected; diff --git a/src/resources/assets/js/maiaShowContainer.js b/src/resources/assets/js/maiaShowContainer.js index 979f8d9..c12829d 100644 --- a/src/resources/assets/js/maiaShowContainer.js +++ b/src/resources/assets/js/maiaShowContainer.js @@ -19,6 +19,8 @@ biigle.$viewModel('maia-show-container', function (element) { tpImageGrid: biigle.$require('maia.components.tpImageGrid'), refineTpTab: biigle.$require('maia.components.refineTpTab'), refineTpCanvas: biigle.$require('maia.components.refineTpCanvas'), + reviewAcTab: biigle.$require('maia.components.reviewAcTab'), + acImageGrid: biigle.$require('maia.components.acImageGrid'), }, data: { visitedSelectTpTab: false, @@ -30,6 +32,8 @@ biigle.$viewModel('maia-show-container', function (element) { lastSelectedTp: null, currentImage: null, currentTpIndex: 0, + annotationCandidates: [], + reviewAcOffset: 0, }, computed: { infoTabOpen: function () { @@ -47,9 +51,15 @@ biigle.$viewModel('maia-show-container', function (element) { hasTrainingProposals: function () { return this.trainingProposals.length > 0; }, + hasAnnotationCandidates: function () { + return this.annotationCandidates.length > 0; + }, isInTrainingProposalState: function () { return job.state_id === states['training-proposals']; }, + isInAnnotationCandidateState: function () { + return job.state_id === states['annotation-candidates']; + }, imageIds: function () { var tmp = {}; @@ -200,6 +210,10 @@ biigle.$viewModel('maia-show-container', function (element) { // TODO this updates on keyboard events of the refine view, too! this.selectTpOffset = offset; }, + updateReviewAcOffset: function (offset) { + // TODO this updates on keyboard events of the refine view, too! + this.reviewAcOffset = offset; + }, selectAllTpBetween: function (first, second) { var index1 = this.trainingProposals.indexOf(first); var index2 = this.trainingProposals.indexOf(second); @@ -281,6 +295,23 @@ biigle.$viewModel('maia-show-container', function (element) { handleUnselectTp: function (proposal) { this.updateSelectTrainingProposal(proposal, false); }, + setAnnotationCandidates: function (response) { + this.annotationCandidates = response.body.map(function (c) { + c.shape = 'Circle'; + return c; + }); + }, + fetchAnnotationCandidates: function () { + this.startLoading(); + + return maiaJobApi.getAnnotationCandidates({id: job.id}) + .then(this.setAnnotationCandidates) + .catch(messages.handleErrorResponse) + .finally(this.finishLoading); + }, + handleSelectedAnnotationCandidate: function (candidate) { + console.log('select', candidate); + }, }, watch: { selectTpTabOpen: function () { @@ -295,6 +326,9 @@ biigle.$viewModel('maia-show-container', function (element) { visitedSelectOrRefineTpTab: function () { this.fetchTrainingProposals(); }, + visitedReviewAcTab: function () { + this.fetchAnnotationCandidates(); + }, currentImageId: function (id) { if (id) { this.fetchCurrentImage().then(this.focusCurrentTp); diff --git a/src/resources/views/show.blade.php b/src/resources/views/show.blade.php index 80ca74a..42bfd96 100644 --- a/src/resources/views/show.blade.php +++ b/src/resources/views/show.blade.php @@ -33,12 +33,19 @@
@include('maia::show.info-content')
-
- @include('maia::show.select-tp-content') -
-
- @include('maia::show.refine-tp-content') -
+ @if ($job->state_id >= $states['training-proposals']) +
+ @include('maia::show.select-tp-content') +
+
+ @include('maia::show.refine-tp-content') +
+ @endif + @if ($job->state_id >= $states['annotation-candidates']) +
+ @include('maia::show.review-ac-content') +
+ @endif diff --git a/src/resources/views/show/review-ac-content.blade.php b/src/resources/views/show/review-ac-content.blade.php new file mode 100644 index 0000000..2339835 --- /dev/null +++ b/src/resources/views/show/review-ac-content.blade.php @@ -0,0 +1,16 @@ + +
+
+ There are no annotation candidates. +
+
diff --git a/src/resources/views/show/review-ac-tab.blade.php b/src/resources/views/show/review-ac-tab.blade.php index 2893c10..63dccea 100644 --- a/src/resources/views/show/review-ac-tab.blade.php +++ b/src/resources/views/show/review-ac-tab.blade.php @@ -1,3 +1,5 @@ + +