Skip to content

Commit 6d024dc

Browse files
authored
Merge pull request #654 from Tom-TBT/refresh_btn
Refresh metadata button to reload channel names, pixel sizes
2 parents e241dc0 + 6261140 commit 6d024dc

4 files changed

Lines changed: 136 additions & 12 deletions

File tree

src/index.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,11 @@ <h5>Example Label</h5>
12751275
<li class="edit-legend">
12761276
<a class="dropdown-item" href="#">Add Figure Legend...</a>
12771277
</li>
1278+
<li class="reload_metadata"
1279+
title="Reload metadata such as image names, pixel sizes and channel names from the server, for all panels."
1280+
>
1281+
<a class="dropdown-item" href="#">Reload images...</a>
1282+
</li>
12781283
</ul>
12791284
</li>
12801285
<li class="nav-item dropdown px-2" id="edit_actions">

src/js/models/figure_model.js

Lines changed: 104 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,101 @@
632632
});
633633
},
634634

635+
reloadMetadata: function() {
636+
// Reload metadata (name, dataset, channels, pixel sizes, ...) for all panels
637+
// Fetch each image's data once per id, then apply to all panels with that imageId.
638+
// Reload here must not change edits made by the user (channel LUT, contrast, field of view, ...)
639+
640+
var panels = this.panels;
641+
var ids = {};
642+
panels.each(function(panel){
643+
// Make a set of imageIds
644+
ids[panel.get('imageId')] = true;
645+
});
646+
var imageIds = Object.keys(ids);
647+
if (imageIds.length === 0) return;
648+
649+
let cors_headers = { mode: 'cors', credentials: 'include', headers: {"Content-Type": "application/json"} };
650+
var fetches = imageIds.map(function(iid){
651+
// singe fetch per imageId
652+
var imgDataUrl = BASE_WEBFIGURE_URL + 'imgData/' + iid + '/';
653+
return fetch(imgDataUrl, cors_headers)
654+
.then(rsp => rsp.json())
655+
.then(data => {
656+
657+
// values returned here are caught below in the Promise.all handler
658+
if (data.Exception || data.ConcurrencyException) {
659+
return {id: iid, error: true, msg: data.Exception || "ConcurrencyException", url: imgDataUrl};
660+
}
661+
return {id: iid, data: data, url: imgDataUrl};
662+
})
663+
.catch(err => ({id: iid, error: true, msg: err && err.message ? err.message : String(err), url: imgDataUrl}));
664+
});
665+
666+
Promise.all(fetches).then(function(results){
667+
results.forEach(function(res){
668+
var iid = res.id;
669+
if (res.error) {
670+
// Show an alert but continue updating other images
671+
alert(`Image loading from ${res.url} included an Error: ${res.msg}`);
672+
return;
673+
}
674+
675+
var data = res.data;
676+
// Update all panels that share this imageId
677+
panels.each(function(panel){
678+
if (panel.get('imageId') == iid) {
679+
var new_channels = JSON.parse(JSON.stringify(panel.attributes.channels));
680+
for (var i=0; i < data.channels.length; i++) {
681+
new_channels[i].label = data.channels[i].label;
682+
}
683+
684+
var newData = {
685+
'name': data.meta.imageName,
686+
'datasetName': data.meta.datasetName,
687+
'datasetId': data.meta.datasetId,
688+
'channels': new_channels,
689+
'parents': data.parents
690+
};
691+
692+
// Unset to start afresh
693+
panel.unset('pixel_size_x');
694+
panel.unset('pixel_size_y');
695+
panel.unset('pixel_size_z');
696+
panel.unset('pixel_size_x_symbol');
697+
panel.unset('pixel_size_z_symbol');
698+
panel.unset('pixel_size_x_unit');
699+
panel.unset('pixel_size_z_unit');
700+
newData.pixel_size_x_unit = 'MICROMETER'; // Set back to panel model default
701+
newData.pixel_size_x_symbol = '\xB5m'; // µm
702+
703+
if (data.pixel_size) {
704+
if (data.pixel_size.valueX) {
705+
newData.pixel_size_x = data.pixel_size.valueX;
706+
newData.pixel_size_x_symbol = data.pixel_size.symbolX;
707+
newData.pixel_size_x_unit = data.pixel_size.unitX;
708+
}
709+
if (data.pixel_size.valueY) {
710+
newData.pixel_size_y = data.pixel_size.valueY;
711+
newData.pixel_size_y_symbol = data.pixel_size.symbolY;
712+
}
713+
if (data.pixel_size.valueZ) {
714+
newData.pixel_size_z = data.pixel_size.valueZ;
715+
newData.pixel_size_z_symbol = data.pixel_size.symbolZ;
716+
newData.pixel_size_z_unit = data.pixel_size.unitZ;
717+
}
718+
}
719+
720+
panel.set(newData);
721+
panel.trigger('change:labels', panel);
722+
}
723+
});
724+
});
725+
});
726+
this.set('unsaved', true);
727+
alert("Metadata reloaded for " + this.panels.length + " panel" + (this.panels.length > 1 ? 's.' : '.'));
728+
},
729+
635730
// Used to position the #figure within canvas and also to coordinate svg layout.
636731
getFigureSize: function() {
637732
var pc = this.get('page_count'),
@@ -760,7 +855,7 @@
760855
right = this.get_right_panel(sel),
761856
bottom = this.get_bottom_panel(sel),
762857
left_x = left.get('x'),
763-
right_x = right.get('x') + right.get('width'),
858+
right_x = right.get('x') + right.get('width'),
764859
top_y = top.get('y'),
765860
bottom_y = bottom.get('y') + bottom.get('height'),
766861
grid = [],
@@ -797,7 +892,7 @@
797892
}else{
798893
c = {'x': left_x + left.get('width')/2, 'y': c.y + row[0].get('height')}
799894
grid.push(row);
800-
}
895+
}
801896
}
802897

803898
// get the row id of the most left panel
@@ -807,7 +902,7 @@
807902
left_panel_row = i;
808903
}
809904
});
810-
905+
811906
// define the spacer between images
812907
var spacer = left.get('width')/20;
813908
if (!isNaN(parseFloat(gridGap))) {
@@ -849,7 +944,7 @@
849944
}
850945

851946
// set the row position (i.e. y coordinate) of each row
852-
var ref_y_offset = max_h
947+
var ref_y_offset = max_h
853948
var rows_position = {}
854949
max_h = 0
855950
// for rows above the reference row
@@ -872,15 +967,15 @@
872967
max_h = Math.max(max_h, row[c].get('height'));
873968
}
874969
}
875-
876-
// update position of panels
970+
971+
// update position of panels
877972
for (var [r, y] of Object.entries(rows_position)){
878973
var row = grid[r];
879974
var last_column_id = -1
880975
for (var c=0; c<row.length; c++) {
881976
let panel = row[c];
882977
var closest_column = this.get_closest_column(panel, reference_grid, last_panel_width)
883-
978+
884979
if(closest_column >= 0){
885980
// update closest_column id to take into account spare panel positions
886981
if(last_column_id == closest_column){
@@ -920,7 +1015,7 @@
9201015
if(current_distance < min_x_distance){
9211016
closest_col = col_id
9221017
min_x_distance = current_distance
923-
}
1018+
}
9241019
}
9251020

9261021
// if the panel is located far away from the last reference column,
@@ -945,7 +1040,7 @@
9451040
return p;
9461041
} else {
9471042
return top_left;
948-
}
1043+
}
9491044
});
9501045
},
9511046

src/js/models/panel_model.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@
147147
let txtShape = shape;
148148
// apply any translation and rotation to Text
149149
let newCoords = {x: txtShape.x, y: txtShape.y};
150-
// If the Inset was previously rotated, we need to 'undo' that rotation first
150+
// If the Inset was previously rotated, we need to 'undo' that rotation first
151151
if (prevCoords.rotation && prevCoords.rotation != 360) {
152152
let prevCx = prevCoords.x + prevCoords.width / 2;
153153
let prevCy = prevCoords.y + prevCoords.height / 2;
@@ -278,6 +278,14 @@
278278
'parents': data.parents
279279
};
280280

281+
if (data.pixel_size_x == undefined ||
282+
data.pixel_size_x_unit == undefined ||
283+
data.pixel_size_x_symbol == undefined) {
284+
// Set back to panel model default
285+
newData.pixel_size_x_unit = 'MICROMETER';
286+
newData.pixel_size_x_symbol = '\xB5m'; // µm
287+
}
288+
281289
// theT and theZ are not changed unless we have to...
282290
if (this.get('theT') >= newData.sizeT) {
283291
newData.theT = newData.sizeT - 1;
@@ -605,8 +613,17 @@
605613
}
606614
} else {
607615
// project, dataset, screen, plate, well, field (name, id, label, index)
608-
var parentVal = this.get("parents")?.[property]?.[format];
609-
text = parentVal == null ? "undefined" : "" + parentVal;
616+
if (this.get("parents") == null && property === "dataset"){
617+
// fallback on old property
618+
if (format === "id") {
619+
text = ""+this.get('datasetId');
620+
} else if (format === "name") {
621+
text = this.get('datasetName') ? this.get('datasetName') : "No/Many Datasets";
622+
}
623+
} else {
624+
var parentVal = this.get("parents")?.[property]?.[format];
625+
text = parentVal == null ? "undefined" : "" + parentVal;
626+
}
610627
}
611628
return text;
612629
},

src/js/views/figure_view.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@
133133
"click .upload_omero_script": "upload_omero_script",
134134
"click .export_options li": "export_options",
135135
"click .add_panel": "addPanel",
136+
"click .reload_metadata": "reloadMetadata",
136137
"click .delete_panel": "deleteSelectedPanels",
137138
"click .copy": "copy_selected_panels",
138139
"click .paste": "paste_panels",
@@ -732,6 +733,12 @@
732733
this.model.select_all();
733734
},
734735

736+
reloadMetadata: function(event) {
737+
event.preventDefault();
738+
if (this.modal_visible()) return true;
739+
this.model.reloadMetadata();
740+
},
741+
735742
deleteSelectedPanels: function(event) {
736743
event.preventDefault();
737744
if (this.modal_visible()) return true;

0 commit comments

Comments
 (0)