@abi-software/scaffoldvuer 1.21.1-beta.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -12
- package/dist/index.html +9 -6
- package/dist/scaffoldvuer.js +14095 -13154
- package/dist/scaffoldvuer.umd.cjs +48 -48
- package/dist/style.css +1 -1
- package/eslint.config.js +37 -9
- package/package.json +10 -3
- package/public/index.html +9 -6
- package/src/App.vue +312 -279
- package/src/ScaffoldVuer-wc.js +4 -4
- package/src/app/DropZone.vue +11 -27
- package/src/app/ModelsInformation.js +22 -19
- package/src/app/ModelsTable.vue +42 -65
- package/src/app/TextureDemos.js +38 -64
- package/src/assets/_variables.scss +12 -10
- package/src/components/GlyphsControls.vue +3 -23
- package/src/components/LinesControls.vue +27 -66
- package/src/components/OpacityControls.vue +22 -26
- package/src/components/PointsControls.vue +20 -71
- package/src/components/PrimitiveControls.vue +35 -49
- package/src/components/ScaffoldOverlay.vue +63 -63
- package/src/components/ScaffoldTooltip.vue +36 -49
- package/src/components/ScaffoldTreeControls.vue +81 -129
- package/src/components/ScaffoldVuer.vue +509 -498
- package/src/components/TextureSlidesControls.vue +22 -64
- package/src/components/TransformationControls.vue +15 -42
- package/src/components/index.js +2 -2
- package/src/main.js +16 -18
- package/src/scripts/Annotation.js +3 -3
- package/src/scripts/BaseModule.js +26 -30
- package/src/scripts/EventNotifier.js +30 -36
- package/src/scripts/GraphicsHighlight.js +43 -50
- package/src/scripts/LocalFilesHelper.js +27 -26
- package/src/scripts/MappedNerves.js +2139 -697
- package/src/scripts/MappedOrgans.js +24 -25
- package/src/scripts/OrgansRenderer.js +445 -425
- package/src/scripts/RendererModule.js +133 -122
- package/src/scripts/Search.js +135 -151
- package/src/scripts/Utilities.js +129 -127
- package/src/scripts/WebGL.js +57 -91
- package/src/scripts/niftiHelper.js +3 -3
- package/src/store/index.js +7 -7
- package/vite.config.js +51 -50
- package/vite.static-build.js +7 -7
- package/vuese-generator.js +48 -56
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { THREE } from 'zincjs';
|
|
2
|
-
import { objectsToZincObjects, NERVE_CONFIG } from
|
|
2
|
+
import { objectsToZincObjects, NERVE_CONFIG } from './Utilities';
|
|
3
3
|
|
|
4
4
|
const setEmissiveColour = (fullList, colour, setDepthFunc, mode) => {
|
|
5
5
|
for (let i = 0; i < fullList.length; i++) {
|
|
@@ -7,10 +7,10 @@ const setEmissiveColour = (fullList, colour, setDepthFunc, mode) => {
|
|
|
7
7
|
let object = fullList[i].userData;
|
|
8
8
|
if (object && object.isZincObject) {
|
|
9
9
|
let emissiveColour = colour;
|
|
10
|
-
if (mode ===
|
|
10
|
+
if (mode === 'highlight' && 'highlightColour' in object.userData) {
|
|
11
11
|
emissiveColour = object.userData.highlightColour;
|
|
12
12
|
}
|
|
13
|
-
if (mode ===
|
|
13
|
+
if (mode === 'select' && 'selectedColour' in object.userData) {
|
|
14
14
|
emissiveColour = object.userData.selectedColour;
|
|
15
15
|
}
|
|
16
16
|
if (emissiveColour) {
|
|
@@ -22,7 +22,7 @@ const setEmissiveColour = (fullList, colour, setDepthFunc, mode) => {
|
|
|
22
22
|
if (setDepthFunc && fullList[i].material.depthFunc) {
|
|
23
23
|
fullList[i].material.depthFunc = THREE.LessEqualDepth;
|
|
24
24
|
}
|
|
25
|
-
fullList[i].children.forEach(child => {
|
|
25
|
+
fullList[i].children.forEach((child) => {
|
|
26
26
|
const object = child.userData;
|
|
27
27
|
if (object && object.isZincObject && child.material && child.material.emissive) {
|
|
28
28
|
child.material.emissive.setRGB(...colour);
|
|
@@ -30,7 +30,7 @@ const setEmissiveColour = (fullList, colour, setDepthFunc, mode) => {
|
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
-
}
|
|
33
|
+
};
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* This module manages highlighted and selected objects in 3D modules.
|
|
@@ -38,7 +38,7 @@ const setEmissiveColour = (fullList, colour, setDepthFunc, mode) => {
|
|
|
38
38
|
* @class
|
|
39
39
|
* @returns {exports.GraphicsHighlight}
|
|
40
40
|
*/
|
|
41
|
-
const GraphicsHighlight = function() {
|
|
41
|
+
const GraphicsHighlight = function () {
|
|
42
42
|
let currentHighlightedObjects = [];
|
|
43
43
|
let currentSelectedObjects = [];
|
|
44
44
|
this.highlightColour = [0.5, 0, 0];
|
|
@@ -48,9 +48,8 @@ const GraphicsHighlight = function() {
|
|
|
48
48
|
const _temp2 = [];
|
|
49
49
|
const _this = this;
|
|
50
50
|
|
|
51
|
-
const isDifferent = function(array1, array2) {
|
|
52
|
-
if (
|
|
53
|
-
return false;
|
|
51
|
+
const isDifferent = function (array1, array2) {
|
|
52
|
+
if (array1.length == 0 && array2.length == 0) return false;
|
|
54
53
|
for (let i = 0; i < array1.length; i++) {
|
|
55
54
|
let matched = false;
|
|
56
55
|
for (let j = 0; j < array2.length; j++) {
|
|
@@ -58,8 +57,7 @@ const GraphicsHighlight = function() {
|
|
|
58
57
|
matched = true;
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
|
-
if (!matched)
|
|
62
|
-
return true;
|
|
60
|
+
if (!matched) return true;
|
|
63
61
|
}
|
|
64
62
|
for (let i = 0; i < array2.length; i++) {
|
|
65
63
|
let matched = false;
|
|
@@ -68,16 +66,14 @@ const GraphicsHighlight = function() {
|
|
|
68
66
|
matched = true;
|
|
69
67
|
}
|
|
70
68
|
}
|
|
71
|
-
if (!matched)
|
|
72
|
-
return true;
|
|
69
|
+
if (!matched) return true;
|
|
73
70
|
}
|
|
74
71
|
return false;
|
|
75
|
-
}
|
|
72
|
+
};
|
|
76
73
|
|
|
77
|
-
const getUnmatchingObjects = function(objectsArray1, objectsArray2) {
|
|
74
|
+
const getUnmatchingObjects = function (objectsArray1, objectsArray2) {
|
|
78
75
|
_temp1.length = 0;
|
|
79
|
-
if (objectsArray2.length == 0)
|
|
80
|
-
return objectsArray1;
|
|
76
|
+
if (objectsArray2.length == 0) return objectsArray1;
|
|
81
77
|
for (let i = 0; i < objectsArray1.length; i++) {
|
|
82
78
|
let matched = false;
|
|
83
79
|
for (let j = 0; j < objectsArray2.length; j++) {
|
|
@@ -85,14 +81,12 @@ const GraphicsHighlight = function() {
|
|
|
85
81
|
matched = true;
|
|
86
82
|
}
|
|
87
83
|
}
|
|
88
|
-
if (!matched)
|
|
89
|
-
_temp1.push(objectsArray1[i]);
|
|
84
|
+
if (!matched) _temp1.push(objectsArray1[i]);
|
|
90
85
|
}
|
|
91
86
|
return _temp1;
|
|
92
|
-
}
|
|
87
|
+
};
|
|
93
88
|
|
|
94
|
-
|
|
95
|
-
/*
|
|
89
|
+
/*
|
|
96
90
|
* Not sure why the following block does not work
|
|
97
91
|
*
|
|
98
92
|
this.setHighlighted = function(objects) {
|
|
@@ -126,7 +120,7 @@ const GraphicsHighlight = function() {
|
|
|
126
120
|
}
|
|
127
121
|
*/
|
|
128
122
|
|
|
129
|
-
this.setHighlighted = function(objects) {
|
|
123
|
+
this.setHighlighted = function (objects) {
|
|
130
124
|
const previousHighlightedObjects = [...currentHighlightedObjects];
|
|
131
125
|
this.setNervesStyle(previousHighlightedObjects);
|
|
132
126
|
_this.resetHighlighted();
|
|
@@ -134,12 +128,12 @@ const GraphicsHighlight = function() {
|
|
|
134
128
|
const array = getUnmatchingObjects(objects, currentSelectedObjects);
|
|
135
129
|
const fullList = getFullListOfObjects(array);
|
|
136
130
|
this.setNervesStyle(array, NERVE_CONFIG.HIGHLIGHTED_COLOUR);
|
|
137
|
-
setEmissiveColour(fullList, _this.highlightColour, false,
|
|
131
|
+
setEmissiveColour(fullList, _this.highlightColour, false, 'highlight');
|
|
138
132
|
currentHighlightedObjects = array;
|
|
139
133
|
return isDifferent(currentHighlightedObjects, previousHighlightedObjects);
|
|
140
|
-
}
|
|
134
|
+
};
|
|
141
135
|
|
|
142
|
-
this.setSelected = function(objects) {
|
|
136
|
+
this.setSelected = function (objects) {
|
|
143
137
|
// first find highlighted object that are not selected
|
|
144
138
|
const previousSelectedObjects = [...currentSelectedObjects];
|
|
145
139
|
this.setNervesStyle(previousSelectedObjects);
|
|
@@ -148,19 +142,18 @@ const GraphicsHighlight = function() {
|
|
|
148
142
|
_this.resetSelected();
|
|
149
143
|
const fullList = getFullListOfObjects(objects);
|
|
150
144
|
this.setNervesStyle(objects, NERVE_CONFIG.SELECTED_COLOUR);
|
|
151
|
-
setEmissiveColour(fullList, _this.selectColour, false,
|
|
145
|
+
setEmissiveColour(fullList, _this.selectColour, false, 'select');
|
|
152
146
|
currentSelectedObjects = objects;
|
|
153
147
|
return isDifferent(currentSelectedObjects, previousSelectedObjects);
|
|
154
|
-
}
|
|
148
|
+
};
|
|
155
149
|
|
|
156
|
-
const getFullListOfObjects = function(objects) {
|
|
150
|
+
const getFullListOfObjects = function (objects) {
|
|
157
151
|
_temp2.length = 0;
|
|
158
152
|
for (let i = 0; i < objects.length; i++) {
|
|
159
|
-
if (objects[i].material)
|
|
160
|
-
_temp2.push(objects[i]);
|
|
153
|
+
if (objects[i].material) _temp2.push(objects[i]);
|
|
161
154
|
}
|
|
162
155
|
return _temp2;
|
|
163
|
-
}
|
|
156
|
+
};
|
|
164
157
|
|
|
165
158
|
/**
|
|
166
159
|
*
|
|
@@ -168,13 +161,13 @@ const GraphicsHighlight = function() {
|
|
|
168
161
|
* @param {*} colour use colour as flag to set or reset the style
|
|
169
162
|
* @returns
|
|
170
163
|
*/
|
|
171
|
-
this.setNervesStyle = function(target, colour) {
|
|
164
|
+
this.setNervesStyle = function (target, colour) {
|
|
172
165
|
const currentObjects = objectsToZincObjects(target);
|
|
173
166
|
if (currentObjects && currentObjects.length) {
|
|
174
|
-
const radius = colour ?
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
167
|
+
const radius = colour ? NERVE_CONFIG.ZOOM_RADIUS : NERVE_CONFIG.DEFAULT_RADIUS;
|
|
168
|
+
const radialSegments = colour
|
|
169
|
+
? NERVE_CONFIG.ZOOM_RADIAL_SEGMENTS
|
|
170
|
+
: NERVE_CONFIG.DEFAULT_RADIAL_SEGMENTS;
|
|
178
171
|
currentObjects.forEach((currentObject) => {
|
|
179
172
|
if (
|
|
180
173
|
currentObject.isTubeLines &&
|
|
@@ -183,35 +176,35 @@ const GraphicsHighlight = function() {
|
|
|
183
176
|
) {
|
|
184
177
|
currentObject.setTubeLines(radius, radialSegments);
|
|
185
178
|
let hexString = colour ? colour : currentObject.userData?.defaultColour;
|
|
186
|
-
hexString = hexString.replace(
|
|
179
|
+
hexString = hexString.replace('#', '0x');
|
|
187
180
|
currentObject.setColourHex(hexString);
|
|
188
181
|
}
|
|
189
182
|
});
|
|
190
183
|
}
|
|
191
|
-
}
|
|
184
|
+
};
|
|
192
185
|
|
|
193
|
-
this.resetHighlighted = function() {
|
|
186
|
+
this.resetHighlighted = function () {
|
|
194
187
|
const fullList = getFullListOfObjects(currentHighlightedObjects);
|
|
195
188
|
this.setNervesStyle(currentHighlightedObjects);
|
|
196
|
-
setEmissiveColour(fullList, _this.originalColour, true,
|
|
189
|
+
setEmissiveColour(fullList, _this.originalColour, true, 'reset');
|
|
197
190
|
currentHighlightedObjects = [];
|
|
198
|
-
}
|
|
191
|
+
};
|
|
199
192
|
|
|
200
|
-
this.resetSelected = function() {
|
|
193
|
+
this.resetSelected = function () {
|
|
201
194
|
const fullList = getFullListOfObjects(currentSelectedObjects);
|
|
202
195
|
this.setNervesStyle(currentHighlightedObjects);
|
|
203
|
-
setEmissiveColour(fullList, _this.originalColour, true,
|
|
196
|
+
setEmissiveColour(fullList, _this.originalColour, true, 'reset');
|
|
204
197
|
currentSelectedObjects = [];
|
|
205
|
-
}
|
|
198
|
+
};
|
|
206
199
|
|
|
207
|
-
this.getSelected = function() {
|
|
200
|
+
this.getSelected = function () {
|
|
208
201
|
return currentSelectedObjects;
|
|
209
|
-
}
|
|
202
|
+
};
|
|
210
203
|
|
|
211
|
-
this.reset = function() {
|
|
204
|
+
this.reset = function () {
|
|
212
205
|
_this.resetSelected();
|
|
213
206
|
_this.resetHighlighted();
|
|
214
|
-
}
|
|
215
|
-
}
|
|
207
|
+
};
|
|
208
|
+
};
|
|
216
209
|
|
|
217
210
|
export { GraphicsHighlight as default };
|
|
@@ -7,13 +7,13 @@ const getRelativePath = (from, to) => {
|
|
|
7
7
|
}
|
|
8
8
|
const upSteps = new Array(fromParts.length).fill('..');
|
|
9
9
|
return [...upSteps, ...toParts].join('/') || '.';
|
|
10
|
-
}
|
|
10
|
+
};
|
|
11
11
|
|
|
12
12
|
const processTextureFile = (textureData, flatarray, objectURLs, filesMapping) => {
|
|
13
13
|
if (textureData && textureData.images && textureData.images.source) {
|
|
14
14
|
const images = textureData.images.source;
|
|
15
15
|
for (let i = 0; i < images.length; i++) {
|
|
16
|
-
const index = flatarray.findIndex(element => {
|
|
16
|
+
const index = flatarray.findIndex((element) => {
|
|
17
17
|
return element[0].includes(images[i]);
|
|
18
18
|
});
|
|
19
19
|
if (index > -1) {
|
|
@@ -24,16 +24,18 @@ const processTextureFile = (textureData, flatarray, objectURLs, filesMapping) =>
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
const content = JSON.stringify(textureData);
|
|
27
|
-
let blob = new Blob([content], { type:
|
|
28
|
-
return URL.createObjectURL(blob)
|
|
27
|
+
let blob = new Blob([content], { type: 'application/json' });
|
|
28
|
+
return URL.createObjectURL(blob);
|
|
29
29
|
}
|
|
30
|
-
}
|
|
30
|
+
};
|
|
31
31
|
|
|
32
32
|
const getJSON = async (URL) => {
|
|
33
33
|
return fetch(URL)
|
|
34
34
|
.then((response) => response.json())
|
|
35
|
-
.then((responseJson) => {
|
|
36
|
-
|
|
35
|
+
.then((responseJson) => {
|
|
36
|
+
return responseJson;
|
|
37
|
+
});
|
|
38
|
+
};
|
|
37
39
|
|
|
38
40
|
const createMetadataObjectURLs = async (text, list, flatarray) => {
|
|
39
41
|
let content = text;
|
|
@@ -42,7 +44,7 @@ const createMetadataObjectURLs = async (text, list, flatarray) => {
|
|
|
42
44
|
for (const [key, file] of Object.entries(list)) {
|
|
43
45
|
if (content.includes(key)) {
|
|
44
46
|
const objectURL = URL.createObjectURL(file);
|
|
45
|
-
const re = new RegExp(key,
|
|
47
|
+
const re = new RegExp(key, 'g');
|
|
46
48
|
content = content.replace(re, objectURL);
|
|
47
49
|
objectURLs.push(objectURL);
|
|
48
50
|
filesMapping[objectURL] = key;
|
|
@@ -51,64 +53,63 @@ const createMetadataObjectURLs = async (text, list, flatarray) => {
|
|
|
51
53
|
const data = JSON.parse(content);
|
|
52
54
|
for (let i = 0; i < data.length; i++) {
|
|
53
55
|
if (data[i] && data[i].Type) {
|
|
54
|
-
if (data[i].Type ===
|
|
56
|
+
if (data[i].Type === 'Texture') {
|
|
55
57
|
const textureData = await getJSON(data[i].URL);
|
|
56
58
|
URL.revokeObjectURL(data[i].URL);
|
|
57
|
-
const newURL = processTextureFile(textureData, flatarray, objectURLs,
|
|
58
|
-
filesMapping);
|
|
59
|
+
const newURL = processTextureFile(textureData, flatarray, objectURLs, filesMapping);
|
|
59
60
|
data[i].URL = newURL;
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
let newContent = JSON.stringify(data);
|
|
64
|
-
let blob = new Blob([newContent], { type:
|
|
65
|
+
let blob = new Blob([newContent], { type: 'application/json' });
|
|
65
66
|
const metaURL = URL.createObjectURL(blob);
|
|
66
67
|
objectURLs.push(metaURL);
|
|
67
68
|
return {
|
|
68
69
|
objectURLs,
|
|
69
70
|
filesMapping,
|
|
70
71
|
url: metaURL,
|
|
71
|
-
format:
|
|
72
|
+
format: 'metadata',
|
|
72
73
|
};
|
|
73
74
|
};
|
|
74
75
|
|
|
75
76
|
const createNiftiURL = (content, zipped) => {
|
|
76
|
-
let type =
|
|
77
|
+
let type = zipped ? 'application/x-gzip' : 'image/nii';
|
|
77
78
|
let blob = new Blob([content], { type });
|
|
78
79
|
const url = URL.createObjectURL(blob);
|
|
79
80
|
return url;
|
|
80
81
|
};
|
|
81
82
|
|
|
82
83
|
const createGLTFURL = (content, binary) => {
|
|
83
|
-
let type =
|
|
84
|
+
let type = binary ? 'model/gltf+binary' : 'model/gltf+json';
|
|
84
85
|
let blob = new Blob([content], { type });
|
|
85
86
|
const gltfURL = URL.createObjectURL(blob);
|
|
86
|
-
const objectURLs = [
|
|
87
|
+
const objectURLs = [gltfURL];
|
|
87
88
|
return {
|
|
88
89
|
objectURLs,
|
|
89
90
|
url: gltfURL,
|
|
90
|
-
format:
|
|
91
|
+
format: 'gltf',
|
|
91
92
|
};
|
|
92
93
|
};
|
|
93
94
|
|
|
94
95
|
const createURLFromFiles = async (flatarray) => {
|
|
95
96
|
let list = {};
|
|
96
|
-
let rootPath =
|
|
97
|
+
let rootPath = '';
|
|
97
98
|
let metadata = undefined;
|
|
98
99
|
let gltf = undefined;
|
|
99
100
|
let binary = false;
|
|
100
101
|
for (let i = 0; i < flatarray.length; i++) {
|
|
101
|
-
if (flatarray[i][1].name.includes(
|
|
102
|
-
rootPath = flatarray[i][0].replace(flatarray[i][1].name,
|
|
102
|
+
if (flatarray[i][1].name.includes('metadata.json')) {
|
|
103
|
+
rootPath = flatarray[i][0].replace(flatarray[i][1].name, '');
|
|
103
104
|
metadata = { rootPath, file: flatarray[i][1] };
|
|
104
105
|
break;
|
|
105
106
|
}
|
|
106
|
-
if (flatarray[i][1].name.includes(
|
|
107
|
+
if (flatarray[i][1].name.includes('.glb')) {
|
|
107
108
|
gltf = { rootPath, file: flatarray[i][1] };
|
|
108
109
|
binary = true;
|
|
109
110
|
break;
|
|
110
111
|
}
|
|
111
|
-
if (flatarray[i][1].name.includes(
|
|
112
|
+
if (flatarray[i][1].name.includes('.gltf')) {
|
|
112
113
|
gltf = { rootPath, file: flatarray[i][1] };
|
|
113
114
|
binary = false;
|
|
114
115
|
break;
|
|
@@ -128,15 +129,15 @@ const createURLFromFiles = async (flatarray) => {
|
|
|
128
129
|
throw new Error('Cant process local file');
|
|
129
130
|
}
|
|
130
131
|
const text = await response.text();
|
|
131
|
-
URL.revokeObjectURL(metaFileURL)
|
|
132
|
+
URL.revokeObjectURL(metaFileURL);
|
|
132
133
|
return await createMetadataObjectURLs(text, list, flatarray);
|
|
133
134
|
} catch (error) {
|
|
134
|
-
console.error(
|
|
135
|
+
console.error('Fetch failed:', error);
|
|
135
136
|
}
|
|
136
137
|
}
|
|
137
138
|
if (gltf) {
|
|
138
139
|
return createGLTFURL(gltf.file, binary);
|
|
139
140
|
}
|
|
140
|
-
}
|
|
141
|
+
};
|
|
141
142
|
|
|
142
|
-
export { createNiftiURL, createURLFromFiles }
|
|
143
|
+
export { createNiftiURL, createURLFromFiles };
|