Skip to content

Commit 87067e8

Browse files
committed
WIP: Refactor study results local features
1 parent 79e2276 commit 87067e8

11 files changed

Lines changed: 292 additions & 283 deletions
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
isic.models.AnnotationModel = girder.Model.extend({
2-
resourceName: 'annotation'
2+
resourceName: 'annotation',
3+
4+
isComplete: function () {
5+
return this.get('state') === 'active';
6+
},
7+
8+
image: function () {
9+
return new isic.models.ImageModel(this.get('image'));
10+
}
311
});
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
isic.views.StudyResultsLocalFeaturesView = isic.View.extend({
2+
/**
3+
* Create a view to select and display local features of an annotation.
4+
*
5+
* @param {Object} settings - Parameters for the view.
6+
* @param {HTMLElement} settings.el - Element to attach this view to.
7+
* @param {isic.models.AnnotationModel} settings.annotation - The annotation
8+
* model; this may change and this view will update.
9+
* @param {isic.models.FeaturesetModel} settings.featureset - The featureset
10+
* of the study for the annotation; this should never change (delete and
11+
* re-instantiate this view for a new study).
12+
* @param {girder.View} settings.parentView - View that instantiated this view.
13+
*/
14+
initialize: function (settings) {
15+
this.annotation = settings.annotation;
16+
this.featureset = settings.featureset;
17+
18+
this.render();
19+
20+
this.listenTo(this.annotation, 'change', this.annotationChanged);
21+
this.listenTo(this.featureset, 'change', this.render);
22+
},
23+
24+
render: function () {
25+
if (!this.featureset.id) {
26+
// TODO: this should not happen
27+
this.$el.html('<span>N/A</span>');
28+
return this;
29+
}
30+
this.$el.html(isic.templates.studyResultsLocalFeaturesPage({
31+
hasLocalFeatures: !_.isEmpty(this.featureset.get('localFeatures'))
32+
}));
33+
34+
this.selectFeatureView = new isic.views.StudyResultsLocalFeaturesSelectView({
35+
el: this.$('#isic-study-results-local-features-select-container'),
36+
annotation: this.annotation,
37+
featureset: this.featureset,
38+
parentView: this
39+
});
40+
this.overlayImageViewerWidget = new isic.views.OverlayImageViewerWidget({
41+
el: this.$('#isic-study-results-local-features-image-container'),
42+
model: this.annotation.image(),
43+
parentView: this
44+
}).render();
45+
46+
this.selectedFeatureId = null;
47+
this.listenTo(this.selectFeatureView, 'changed', this.selectedFeatureChanged);
48+
49+
return this;
50+
},
51+
52+
selectedFeatureChanged: function (featureId) {
53+
if (featureId === this.selectedFeatureId) {
54+
return;
55+
}
56+
this.selectedFeatureId = featureId;
57+
58+
if (this.selectedFeatureId && this.annotation.isComplete()) {
59+
var annotationValue = this.annotation.get('annotations')[this.selectedFeatureId];
60+
if (annotationValue) {
61+
this.overlayImageViewerWidget.overlay(annotationValue);
62+
return;
63+
}
64+
}
65+
this.overlayImageViewerWidget.clear();
66+
},
67+
68+
annotationChanged: function () {
69+
this.selectedFeatureId = null;
70+
71+
// this.selectFeatureView updates itself when this.annotation changes
72+
73+
// TODO: this.overlayImageViewerWidget should probably expose a method
74+
// to update its model
75+
var overlayImageModel = this.overlayImageViewerWidget.model;
76+
overlayImageModel.clear({silent: true});
77+
overlayImageModel.set(this.annotation.image().attributes);
78+
},
79+
80+
setVisible: function (visible) {
81+
if (visible) {
82+
this.$el.removeClass('hidden');
83+
} else {
84+
this.$el.addClass('hidden');
85+
}
86+
}
87+
});
88+
89+
// View for a collection of local features in a select tag
90+
isic.views.StudyResultsLocalFeaturesSelectView = isic.View.extend({
91+
events: {
92+
'change': 'selectedFeatureChanged'
93+
},
94+
95+
initialize: function (settings) {
96+
this.annotation = settings.annotation;
97+
this.featureset = settings.featureset;
98+
99+
this.render();
100+
101+
this.listenTo(this.annotation, 'change', this.annotationChanged);
102+
},
103+
104+
render: function () {
105+
var availableFeatures;
106+
if (this.annotation.isComplete()) {
107+
// Annotation is complete
108+
var featuresetLocalFeatures = this.featureset.get('localFeatures');
109+
var annotationValues = this.annotation.get('annotations');
110+
availableFeatures = featuresetLocalFeatures.filter(_.bind(function (feature) {
111+
return _.has(annotationValues, feature.id);
112+
}, this));
113+
} else {
114+
// Annotation is pending
115+
availableFeatures = [];
116+
}
117+
118+
this.$el.html(isic.templates.studyResultsLocalFeaturesSelectPage({
119+
availableFeatures: availableFeatures
120+
}));
121+
122+
// Set up select box
123+
var placeholder = _.isEmpty(availableFeatures)
124+
? 'No features available'
125+
: 'Select a feature... (' + availableFeatures.length + ' available)';
126+
var select = this.$('#isic-study-results-local-features-select-box');
127+
select.select2({
128+
placeholder: placeholder
129+
});
130+
131+
return this;
132+
},
133+
134+
selectedFeatureChanged: function () {
135+
this.trigger('changed', this.$('select').val());
136+
},
137+
138+
annotationChanged: function () {
139+
// Destroy previous select2
140+
var select = this.$('#isic-study-results-local-features-select-box');
141+
select.select2('destroy');
142+
143+
this.render();
144+
}
145+
});

0 commit comments

Comments
 (0)