-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathNeuroglancerViewer.js
More file actions
157 lines (146 loc) · 4.13 KB
/
Copy pathNeuroglancerViewer.js
File metadata and controls
157 lines (146 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import React, { useState, useEffect } from "react";
import { Button, Spin, Alert, Typography } from "antd";
import { ReloadOutlined } from "@ant-design/icons";
import { apiClient } from "../api";
const { Text, Title } = Typography;
/**
* NeuroglancerViewer Component
*
* Loads and displays Neuroglancer viewer in an iframe using the project's image files.
* Uses the same approach as the Visualization tab.
*
* @param {number} projectId - Project ID to load viewer for
* @param {object} currentSynapse - Current synapse for position reference
*/
function NeuroglancerViewer({ projectId = 1, currentSynapse }) {
const [viewerUrl, setViewerUrl] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
// Load Neuroglancer viewer on mount
useEffect(() => {
loadViewer();
}, [projectId]);
const loadViewer = async () => {
setLoading(true);
setError(null);
try {
const response = await apiClient.get(`/api/synanno/ng-url/${projectId}`);
if (response.data.url) {
setViewerUrl(response.data.url);
} else {
// If backend returns a message instead of URL (transition state)
if (response.data.message) {
// We can handle the message here, but for now let's just show the "Setup in Progress" state
// by not setting the URL.
console.log("Neuroglancer message:", response.data.message);
}
setError(null); // Clear error if it's just a transition message
}
} catch (err) {
console.error("Failed to load Neuroglancer viewer", err);
setError(
err.response?.data?.detail || "Failed to load Neuroglancer viewer",
);
} finally {
setLoading(false);
}
};
const refreshViewer = () => {
loadViewer();
};
if (loading) {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100%",
minHeight: "400px",
}}
>
<Spin size="large" tip="Loading Neuroglancer viewer..." />
</div>
);
}
if (error) {
return (
<div
style={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
height: "100%",
padding: "40px",
gap: "16px",
}}
>
<Alert
message="Failed to Load Viewer"
description={error}
type="error"
showIcon
style={{ maxWidth: "600px" }}
/>
<Button onClick={loadViewer}>Try Again</Button>
</div>
);
}
// Display viewer in iframe
return (
<div style={{ width: "100%", height: "100%", position: "relative" }}>
<div
style={{
position: "absolute",
top: 10,
right: 10,
zIndex: 1000,
background: "rgba(255, 255, 255, 0.9)",
borderRadius: "4px",
padding: "4px",
}}
>
<Button
type="link"
icon={<ReloadOutlined />}
onClick={refreshViewer}
title="Refresh viewer"
/>
{currentSynapse && (
<Text
type="secondary"
style={{ marginLeft: "8px", fontSize: "12px" }}
>
Synapse #{currentSynapse.id}
</Text>
)}
</div>
{viewerUrl ? (
<iframe
title="Neuroglancer Viewer"
width="100%"
height="800"
frameBorder="0"
scrolling="no"
src={viewerUrl}
style={{ background: "#000" }}
/>
) : (
<div style={{ padding: 40, textAlign: "center" }}>
<Title level={4}>Setup in Progress</Title>
<Text>Data server is running. Preparing viewer...</Text>
<div style={{ marginTop: 20 }}>
<Alert
message="Transitioning to Web Client"
description="Converting data to NIfTI format for web compatibility..."
type="info"
showIcon
/>
</div>
</div>
)}
</div>
);
}
export default NeuroglancerViewer;