Skip to content

Commit 6d9b30b

Browse files
authored
Merge pull request #197 from MetaCell/feature/circuit-browser-fixes
Circuit Browser Fixes for #VFB-223 and #VFB-224
2 parents 93e5de2 + dafda57 commit 6d9b30b

File tree

3 files changed

+125
-80
lines changed

3 files changed

+125
-80
lines changed

applications/virtual-fly-brain/frontend/src/components/StackViewer.jsx

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -152,36 +152,69 @@ const VFBStackViewer = (props) => {
152152
const config = useMemo(() => {
153153
let result = {
154154
serverUrl: 'http://www.virtualflybrain.org/fcgi/wlziipsrv.fcgi',
155-
templateId: 'NOTSET'
155+
templateId: 'NOTSET',
156+
templateDomainIds: [],
157+
templateDomainNames: [],
158+
templateDomainTypeIds: [],
159+
subDomains: []
156160
};
157-
158-
data?.forEach( stackViewerData => {
161+
162+
data?.forEach(stackViewerData => {
159163
if (stackViewerData?.metadata?.IsTemplate) {
160-
let keys = Object.keys(stackViewerData.metadata?.Images);
161-
result = stackViewerData.metadata?.Images[keys[0]]?.[0];
162-
result.serverUrl = 'http://www.virtualflybrain.org/fcgi/wlziipsrv.fcgi';
163-
if ( stackViewerData?.metadata?.Domains ){
164-
keys = Object.keys(stackViewerData?.metadata?.Domains);
164+
const imageKeys = Object.keys(stackViewerData.metadata?.Images || {});
165+
if (!imageKeys.length) {
166+
return;
167+
}
168+
169+
const imageMeta =
170+
stackViewerData.metadata?.Images[imageKeys[0]]?.[0];
171+
if (!imageMeta) {
172+
return;
165173
}
166-
let ids = [parseInt(keys[keys?.length - 1]) + 1], labels = [parseInt(keys[keys?.length - 1]) + 1], classID = [parseInt(keys[keys?.length - 1]) + 1];
167-
keys?.forEach( key => {
168-
ids[parseInt(key)] = (stackViewerData?.metadata?.Domains?.[key]?.id);
169-
labels[parseInt(key)] = (stackViewerData?.metadata?.Domains?.[key]?.type_label);
170-
classID[parseInt(key)] = (stackViewerData?.metadata?.Domains?.[key]?.type_id);
171-
})
172-
let voxels = [];
173-
if (result?.voxel != undefined) {
174-
voxelSizeRef.current.x = Number(result.voxel.X || 0.622088);
175-
voxelSizeRef.current.y = Number(result.voxel.Y || 0.622088);
176-
voxelSizeRef.current.z = Number(result.voxel.Z || 0.622088);
177-
voxels = [voxelSizeRef.current.x, voxelSizeRef.current.y, voxelSizeRef.current.z];
174+
175+
const domains = stackViewerData.metadata?.Domains || {};
176+
const domainKeys = Object.keys(domains);
177+
const maxIndex = domainKeys.reduce(
178+
(acc, k) => Math.max(acc, Number(k) || 0),
179+
0
180+
);
181+
182+
const ids = new Array(maxIndex + 1);
183+
const labels = new Array(maxIndex + 1);
184+
const classIDs = new Array(maxIndex + 1);
185+
186+
domainKeys.forEach(key => {
187+
const idx = Number(key);
188+
const d = domains[key];
189+
ids[idx] = d?.id;
190+
labels[idx] = d?.type_label;
191+
classIDs[idx] = d?.type_id;
192+
});
193+
194+
const voxels = [];
195+
if (imageMeta?.voxel) {
196+
voxelSizeRef.current.x = Number(imageMeta.voxel.X || 0.622088);
197+
voxelSizeRef.current.y = Number(imageMeta.voxel.Y || 0.622088);
198+
voxelSizeRef.current.z = Number(imageMeta.voxel.Z || 0.622088);
199+
voxels.push(
200+
voxelSizeRef.current.x,
201+
voxelSizeRef.current.y,
202+
voxelSizeRef.current.z
203+
);
178204
}
179205

180-
let subDomains = [voxels, ids, labels, classID]
181-
result.subDomains = subDomains;
206+
result = {
207+
...imageMeta,
208+
serverUrl: 'http://www.virtualflybrain.org/fcgi/wlziipsrv.fcgi',
209+
templateId: stackViewerData.metadata?.Id,
210+
templateDomainIds: ids,
211+
templateDomainNames: labels,
212+
templateDomainTypeIds: classIDs,
213+
subDomains: [voxels, ids, labels, classIDs]
214+
};
182215
}
183216
});
184-
217+
185218
return result;
186219
}, [data]);
187220

applications/virtual-fly-brain/frontend/src/components/StackViewerComponent.jsx

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -981,16 +981,14 @@ const rgbToHex = (color) => {
981981
createImages: async function () {
982982
if (this.state.stack.length > 0) {
983983
var i, x, y, w, h, d, offX, offY, t, image, Xpos, Ypos, XboundMax, YboundMax, XboundMin, YboundMin;
984-
/*
985-
* move through tiles
986-
* console.log('Creating slice view...');
987-
*/
984+
988985
this.state.visibleTiles = [];
989-
w = Math.ceil(((this.state.imageX / 10.0) * this.state.scl) / this.state.tileX);
990-
h = Math.ceil(((this.state.imageY / 10.0) * this.state.scl) / this.state.tileY);
991-
// console.log('Tile grid is ' + w.toString() + ' wide by ' + h.toString() + ' high');
986+
987+
w = Math.ceil(this.state.imageX / this.state.tileX);
988+
h = Math.ceil(this.state.imageY / this.state.tileY);
992989
this.state.numTiles = w * h;
993-
990+
// console.log('Tile grid is ' + w.toString() + ' wide by ' + h.toString() + ' high');
991+
994992
for (t = 0; t < w * h; t++) {
995993
x = 0;
996994
y = 0;
@@ -1683,12 +1681,23 @@ const StackViewerComponent = () => createClass({
16831681
}
16841682

16851683
// detect available wheel event
1686-
support = "onwheel" in document.createElement("div") ? "wheel" // Modern browsers support "wheel"
1687-
: document.onmousewheel !== undefined ? "mousewheel" // Webkit and IE support at least "mousewheel"
1688-
: "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox
1689-
this?.addWheelListener(document.getElementById(this.props.data.id + 'displayArea'), (e) => {
1684+
support = "onwheel" in document.createElement("div")
1685+
? "wheel" // Modern browsers
1686+
: document.onmousewheel !== undefined
1687+
? "mousewheel" // Webkit / IE
1688+
: "DOMMouseScroll"; // Older Firefox
1689+
1690+
const displayElem =
1691+
document.getElementById((this.props.data && this.props.data.id) + 'displayArea') ||
1692+
document.getElementById('slice-viewer');
1693+
1694+
if (displayElem) {
1695+
this.addWheelListener(displayElem, (e) => {
16901696
this.onWheelEvent(e);
16911697
});
1698+
} else {
1699+
console.warn('StackViewer: wheel listener target not found for slice viewer');
1700+
}
16921701

16931702
if (this.props.data && this.props.data != null && this.props.data.instances && this.props.data.instances != null) {
16941703
this.setState(this.handleInstances(this.props.data.instances));
@@ -1732,24 +1741,30 @@ const StackViewerComponent = () => createClass({
17321741
newState.voxelY = Number(this.props.config.subDomains[0][1] || 0.622088);
17331742
newState.voxelZ = Number(this.props.config.subDomains[0][2] || 0.622088);
17341743
}
1735-
if (this.props.config && this.props.config != null) {
1736-
if (this.props.config.subDomains && this.props.config.subDomains != null && this.props.config.subDomains.length) {
1737-
if (this.props.config.subDomains.length > 0 && this.props.config.subDomains[0] && this.props.config.subDomains[0].length && this.props.config.subDomains[0].length > 2) {
1738-
newState.voxelX = Number(this.props.config.subDomains[0][0] || 0.622088);
1739-
newState.voxelY = Number(this.props.config.subDomains[0][1] || 0.622088);
1740-
newState.voxelZ = Number(this.props.config.subDomains[0][2] || 0.622088);
1741-
}
1742-
if (this.props.config.subDomains.length > 3 && this.props.config.subDomains[1] != null) {
1743-
newState.tempName = this.props.config.subDomains[2];
1744-
newState.tempId = this.props.config.subDomains[1];
1745-
newState.tempType = this.props.config.subDomains[3];
1746-
// FIXME : Add extra subdomain to match previous configuration
1747-
// if (this.props.config.subDomains[4] && this.props.config.subDomains[4].length && this.props.config.subDomains[4].length > 0) {
1748-
// newState.fxp = JSON.parse(this.props.config.subDomains[4][0]);
1749-
// }
1750-
}
1744+
if (this.props.config) {
1745+
const {
1746+
subDomains = [],
1747+
templateDomainIds,
1748+
templateDomainNames,
1749+
templateDomainTypeIds
1750+
} = this.props.config;
1751+
1752+
if (subDomains.length > 0 && subDomains[0] && subDomains[0].length > 2) {
1753+
newState.voxelX = Number(subDomains[0][0] || 0.622088);
1754+
newState.voxelY = Number(subDomains[0][1] || 0.622088);
1755+
newState.voxelZ = Number(subDomains[0][2] || 0.622088);
17511756
}
1752-
}
1757+
1758+
const templateIds = templateDomainIds || subDomains[1];
1759+
const templateNames = templateDomainNames || subDomains[2];
1760+
const templateTypes = templateDomainTypeIds || subDomains[3];
1761+
1762+
if (templateIds && templateNames && templateTypes) {
1763+
newState.tempId = templateIds;
1764+
newState.tempName = templateNames;
1765+
newState.tempType = templateTypes;
1766+
}
1767+
}
17531768
for (instance in instances) {
17541769
try {
17551770
if ((instances[instance].wrappedObj.id != undefined) && (instances[instance].parent != null) ){
@@ -1792,7 +1807,7 @@ const StackViewerComponent = () => createClass({
17921807

17931808
componentWillUnmount: function () {
17941809
this._isMounted = false;
1795-
return true;
1810+
return true;
17961811
},
17971812
/**
17981813
* Event handler for clicking zoom in. Increments the zoom level

applications/virtual-fly-brain/frontend/src/reducers/middleware/urlUpdaterMiddleware.js

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -49,44 +49,41 @@ const isFirstTimeLoad = (allLoadedInstances, store) => {
4949
if (currentUrl != appLoadedUrl) {
5050
localStorage.setItem(APP_LOADED_FLAG_KEY, currentUrl);
5151
// Load id parameter from URL and dispatch action
52-
let idToUpdate = [];
5352
const idsFromUrl = getUrlParameter("i");
54-
// let idToUpdate = [DEFAULT_ID];
55-
56-
if (idsFromUrl) {
57-
idToUpdate = [...new Set(idsFromUrl?.split(','))];
58-
}
59-
6053
const idSelected = getUrlParameter("id");
6154

55+
const queuedInstances = idsFromUrl
56+
? idsFromUrl
57+
.split(',')
58+
.map(id => id?.trim())
59+
.filter(Boolean)
60+
: [];
61+
62+
let loadOrder = [...queuedInstances];
6263
if (idSelected) {
63-
// If an ID is specified in the URL, check if present and if yes move it as last in the list, otherwise add it at the end
64-
idToUpdate = idToUpdate.filter(id => id !== idSelected);
65-
// If the selected ID is not already in the list, add it
66-
if (!idToUpdate.includes(idSelected)) {
67-
idToUpdate.push(idSelected);
68-
}
69-
} else if (idToUpdate.length === 0) {
70-
// If no ID is specified in the URL, add the default ID
71-
idToUpdate.push(DEFAULT_ID);
64+
loadOrder = loadOrder.filter(id => id !== idSelected);
65+
loadOrder.unshift(idSelected);
7266
}
7367

74-
// Filter out instances that are already loaded to get the actual count we need to load
75-
const instancesToLoad = idToUpdate.filter(id => !allLoadedInstances?.find(i => i.metadata?.Id === id));
76-
7768
// If we have instances to load, set up bulk loading
69+
if (loadOrder.length === 0) {
70+
loadOrder.push(DEFAULT_ID);
71+
}
72+
73+
const uniqueLoadOrder = [...new Set(loadOrder)];
74+
const instancesToLoad = uniqueLoadOrder.filter(id => !allLoadedInstances?.find(i => i.metadata?.Id === id));
75+
7876
if (instancesToLoad.length > 0) {
7977
store.dispatch(setBulkLoadingCount(instancesToLoad.length));
8078
}
8179

82-
idToUpdate?.forEach( id => {
83-
// if it's the last ID in the list, we need to focus it
84-
if (id === idToUpdate[idToUpdate.length - 1]) {
85-
getInstance(allLoadedInstances, id, true);
86-
}
87-
else {
88-
getInstance(allLoadedInstances, id, false);
89-
}
80+
const focusTarget = queuedInstances.length > 0
81+
? queuedInstances[queuedInstances.length - 1]
82+
: (idSelected || uniqueLoadOrder[uniqueLoadOrder.length - 1]);
83+
84+
uniqueLoadOrder.forEach(id => {
85+
const shouldFocus = id === focusTarget;
86+
getInstance(allLoadedInstances, id, shouldFocus);
9087
});
9188
}
9289
};

0 commit comments

Comments
 (0)