@niivue/niivue 0.44.1 → 0.44.2-dev.2
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 +9 -0
- package/build/index.d.ts +31 -6
- package/build/index.js +531 -135
- package/build/index.js.map +1 -1
- package/build/index.min.js +1 -1
- package/dist/index.d.ts +106 -18
- package/dist/index.js +26377 -30692
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/package.json +18 -17
- package/src/index.html +46 -7
- package/src/index_segment.html +233 -0
- package/src/index_sync.html +333 -0
- package/src/niivue/index.ts +1054 -147
- package/src/niivue.css +0 -1
- package/src/nvdocument.ts +40 -5
- package/src/nvimage/index.ts +4 -1
- package/src/nvimage/utils.ts +61 -42
- package/src/nvlabel.ts +34 -1
- package/src/nvmesh-loaders.ts +24 -1
- package/src/shader-srcs.ts +84 -3
- package/src/types.ts +13 -0
- package/dist/niivue.umd.js +0 -1792
package/build/index.js
CHANGED
|
@@ -4,16 +4,13 @@ var __export = (target, all) => {
|
|
|
4
4
|
for (var name in all)
|
|
5
5
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
6
|
};
|
|
7
|
-
var __publicField = (obj, key, value) =>
|
|
8
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
9
|
-
return value;
|
|
10
|
-
};
|
|
7
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
11
8
|
|
|
12
9
|
// src/niivue/index.ts
|
|
13
10
|
import { mat4 as mat46, vec2, vec3 as vec311, vec4 as vec48 } from "gl-matrix";
|
|
14
11
|
|
|
15
12
|
// package.json
|
|
16
|
-
var version = "0.
|
|
13
|
+
var version = "0.45.1";
|
|
17
14
|
|
|
18
15
|
// src/logger.ts
|
|
19
16
|
var _Log = class _Log {
|
|
@@ -1271,11 +1268,11 @@ uniform mat4 mvpMtx;
|
|
|
1271
1268
|
uniform mat4 normMtx;
|
|
1272
1269
|
out vec4 vClr;
|
|
1273
1270
|
out vec3 vN;
|
|
1274
|
-
out vec4
|
|
1271
|
+
out vec4 vPc;
|
|
1275
1272
|
void main(void) {
|
|
1276
1273
|
vec3 lightPosition = vec3(0.0, 0.0, -10.0);
|
|
1277
|
-
|
|
1278
|
-
gl_Position =
|
|
1274
|
+
vPc = mvpMtx * vec4(pos, 1.0);
|
|
1275
|
+
gl_Position = vPc;
|
|
1279
1276
|
vN = normalize((normMtx * vec4(norm.xyz,1.0)).xyz);
|
|
1280
1277
|
//vV = -vec3(modelMtx*vec4(pos,1.0));
|
|
1281
1278
|
vClr = clr;
|
|
@@ -1420,6 +1417,45 @@ void main() {
|
|
|
1420
1417
|
s *= specularWhite;
|
|
1421
1418
|
color = vec4(d3 + s3 + s, opacity);
|
|
1422
1419
|
}`;
|
|
1420
|
+
var fragMeshShaderCrevice = `#version 300 es
|
|
1421
|
+
precision highp int;
|
|
1422
|
+
precision highp float;
|
|
1423
|
+
uniform float opacity;
|
|
1424
|
+
in vec4 vClr;
|
|
1425
|
+
in vec3 vN;
|
|
1426
|
+
in vec4 vPc;
|
|
1427
|
+
out vec4 color;
|
|
1428
|
+
void main() {
|
|
1429
|
+
vec3 n = normalize(vN);
|
|
1430
|
+
// Compute curvature
|
|
1431
|
+
vec3 dx = dFdx(n);
|
|
1432
|
+
vec3 dy = dFdy(n);
|
|
1433
|
+
vec3 xneg = n - dx;
|
|
1434
|
+
vec3 xpos = n + dx;
|
|
1435
|
+
vec3 yneg = n - dy;
|
|
1436
|
+
vec3 ypos = n + dy;
|
|
1437
|
+
float depth = length(vPc.xyz);
|
|
1438
|
+
float curv = (cross(xneg, xpos).y - cross(yneg, ypos).x) / depth;
|
|
1439
|
+
//at this stage 0.5 for flat, with valleys dark and ridges bright
|
|
1440
|
+
curv = 1.0 - (curv + 0.5);
|
|
1441
|
+
//clamp
|
|
1442
|
+
curv = min(max(curv, 0.0), 1.0);
|
|
1443
|
+
// easing function
|
|
1444
|
+
curv = pow(curv, 0.5);
|
|
1445
|
+
//modulate ambient and diffuse with curvature
|
|
1446
|
+
vec3 r = vec3(0.0, 0.0, 1.0); //rayDir: for orthographic projections moving in Z direction (no need for normal matrix)
|
|
1447
|
+
float ambient = 0.6;
|
|
1448
|
+
float diffuse = 0.6;
|
|
1449
|
+
float specular = 0.2;
|
|
1450
|
+
float shininess = 10.0;
|
|
1451
|
+
vec3 lightPosition = vec3(0.0, 10.0, -2.0);
|
|
1452
|
+
vec3 l = normalize(lightPosition);
|
|
1453
|
+
float lightNormDot = dot(n, l);
|
|
1454
|
+
vec3 a = vClr.rgb * ambient * curv;
|
|
1455
|
+
vec3 d = max(lightNormDot, 0.0) * vClr.rgb * diffuse;
|
|
1456
|
+
float s = specular * pow(max(dot(reflect(l, n), r), 0.0), shininess);
|
|
1457
|
+
color = vec4(a + d + s, opacity);
|
|
1458
|
+
}`;
|
|
1423
1459
|
var fragMeshShader = `#version 300 es
|
|
1424
1460
|
precision highp int;
|
|
1425
1461
|
precision highp float;
|
|
@@ -12357,6 +12393,12 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12357
12393
|
while (lines[pos].length < 1) {
|
|
12358
12394
|
pos++;
|
|
12359
12395
|
}
|
|
12396
|
+
if (lines[pos].startsWith("METADATA")) {
|
|
12397
|
+
while (lines[pos].length > 1) {
|
|
12398
|
+
pos++;
|
|
12399
|
+
}
|
|
12400
|
+
pos++;
|
|
12401
|
+
}
|
|
12360
12402
|
items = lines[pos].trim().split(/\s+/);
|
|
12361
12403
|
pos++;
|
|
12362
12404
|
if (items[0].includes("LINES")) {
|
|
@@ -12535,7 +12577,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12535
12577
|
layer.values = obj;
|
|
12536
12578
|
}
|
|
12537
12579
|
}
|
|
12538
|
-
} else if (ext === "CRV" || ext === "CURV") {
|
|
12580
|
+
} else if (ext === "CRV" || ext === "CURV" || ext === "THICKNESS" || ext === "AREA") {
|
|
12539
12581
|
layer.values = _NVMeshLoaders.readCURV(buffer, n_vert);
|
|
12540
12582
|
layer.isTransparentBelowCalMin = false;
|
|
12541
12583
|
} else if (ext === "GII") {
|
|
@@ -12560,6 +12602,9 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12560
12602
|
layer.values = _NVMeshLoaders.readSMP(buffer, n_vert);
|
|
12561
12603
|
} else if (ext === "STC") {
|
|
12562
12604
|
layer.values = _NVMeshLoaders.readSTC(buffer, n_vert);
|
|
12605
|
+
} else if (_NVMeshLoaders.isCurv(buffer)) {
|
|
12606
|
+
layer.values = _NVMeshLoaders.readCURV(buffer, n_vert);
|
|
12607
|
+
layer.isTransparentBelowCalMin = false;
|
|
12563
12608
|
} else {
|
|
12564
12609
|
log.warn("Unknown layer overlay format " + name);
|
|
12565
12610
|
return layer;
|
|
@@ -12733,6 +12778,17 @@ var NVMeshLoaders = class _NVMeshLoaders {
|
|
|
12733
12778
|
return f32;
|
|
12734
12779
|
}
|
|
12735
12780
|
// readSTC()
|
|
12781
|
+
static isCurv(buffer) {
|
|
12782
|
+
const view = new DataView(buffer);
|
|
12783
|
+
const sig0 = view.getUint8(0);
|
|
12784
|
+
const sig1 = view.getUint8(1);
|
|
12785
|
+
const sig2 = view.getUint8(2);
|
|
12786
|
+
if (sig0 !== 255 || sig1 !== 255 || sig2 !== 255) {
|
|
12787
|
+
utiltiesLogger.debug("Unable to recognize file type: does not appear to be FreeSurfer format.");
|
|
12788
|
+
return false;
|
|
12789
|
+
}
|
|
12790
|
+
return true;
|
|
12791
|
+
}
|
|
12736
12792
|
// read freesurfer curv big-endian format
|
|
12737
12793
|
// https://github.com/bonilhamusclab/MRIcroS/blob/master/%2BfileUtils/%2Bpial/readPial.m
|
|
12738
12794
|
// http://www.grahamwideman.com/gw/brain/fs/surfacefileformats.htm
|
|
@@ -18369,76 +18425,90 @@ function getBestTransform(imageDirections, voxelDimensions, imagePosition) {
|
|
|
18369
18425
|
}
|
|
18370
18426
|
return m;
|
|
18371
18427
|
}
|
|
18372
|
-
function str2Buffer(str) {
|
|
18428
|
+
function str2Buffer(str, maxLen = 80) {
|
|
18429
|
+
str = str.replace(/[`$]/g, "");
|
|
18373
18430
|
const bytes = [];
|
|
18374
|
-
|
|
18431
|
+
const len = Math.min(maxLen, str.length);
|
|
18432
|
+
for (let i = 0; i < len; i++) {
|
|
18375
18433
|
const char = str.charCodeAt(i);
|
|
18376
18434
|
bytes.push(char & 255);
|
|
18377
18435
|
}
|
|
18378
18436
|
return bytes;
|
|
18379
18437
|
}
|
|
18380
|
-
function hdrToArrayBuffer(hdr, isDrawing8 = false) {
|
|
18438
|
+
function hdrToArrayBuffer(hdr, isDrawing8 = false, isInputEndian = false) {
|
|
18381
18439
|
const SHORT_SIZE = 2;
|
|
18382
18440
|
const FLOAT32_SIZE = 4;
|
|
18441
|
+
let isLittleEndian = true;
|
|
18442
|
+
if (isInputEndian) {
|
|
18443
|
+
isLittleEndian = hdr.littleEndian;
|
|
18444
|
+
}
|
|
18383
18445
|
const byteArray = new Uint8Array(348);
|
|
18384
18446
|
const view = new DataView(byteArray.buffer);
|
|
18385
|
-
view.setInt32(0, 348,
|
|
18447
|
+
view.setInt32(0, 348, isLittleEndian);
|
|
18448
|
+
view.setUint8(38, 114);
|
|
18386
18449
|
view.setUint8(39, hdr.dim_info);
|
|
18387
18450
|
for (let i = 0; i < 8; i++) {
|
|
18388
|
-
view.setUint16(40 + SHORT_SIZE * i, hdr.dims[i],
|
|
18451
|
+
view.setUint16(40 + SHORT_SIZE * i, hdr.dims[i], isLittleEndian);
|
|
18389
18452
|
}
|
|
18390
|
-
view.setFloat32(56, hdr.intent_p1,
|
|
18391
|
-
view.setFloat32(60, hdr.intent_p2,
|
|
18392
|
-
view.setFloat32(64, hdr.intent_p3,
|
|
18393
|
-
view.setInt16(68, hdr.intent_code,
|
|
18453
|
+
view.setFloat32(56, hdr.intent_p1, isLittleEndian);
|
|
18454
|
+
view.setFloat32(60, hdr.intent_p2, isLittleEndian);
|
|
18455
|
+
view.setFloat32(64, hdr.intent_p3, isLittleEndian);
|
|
18456
|
+
view.setInt16(68, hdr.intent_code, isLittleEndian);
|
|
18394
18457
|
if (isDrawing8) {
|
|
18395
|
-
view.setInt16(70, 2,
|
|
18396
|
-
view.setInt16(72, 8,
|
|
18458
|
+
view.setInt16(70, 2, isLittleEndian);
|
|
18459
|
+
view.setInt16(72, 8, isLittleEndian);
|
|
18397
18460
|
} else {
|
|
18398
|
-
view.setInt16(70, hdr.datatypeCode,
|
|
18399
|
-
view.setInt16(72, hdr.numBitsPerVoxel,
|
|
18461
|
+
view.setInt16(70, hdr.datatypeCode, isLittleEndian);
|
|
18462
|
+
view.setInt16(72, hdr.numBitsPerVoxel, isLittleEndian);
|
|
18400
18463
|
}
|
|
18401
|
-
view.setInt16(74, hdr.slice_start,
|
|
18464
|
+
view.setInt16(74, hdr.slice_start, isLittleEndian);
|
|
18402
18465
|
for (let i = 0; i < 8; i++) {
|
|
18403
|
-
view.setFloat32(76 + FLOAT32_SIZE * i, hdr.pixDims[i],
|
|
18466
|
+
view.setFloat32(76 + FLOAT32_SIZE * i, hdr.pixDims[i], isLittleEndian);
|
|
18404
18467
|
}
|
|
18405
18468
|
if (isDrawing8) {
|
|
18406
|
-
view.setFloat32(108, 352,
|
|
18407
|
-
view.setFloat32(112, 1,
|
|
18408
|
-
view.setFloat32(116, 0,
|
|
18469
|
+
view.setFloat32(108, 352, isLittleEndian);
|
|
18470
|
+
view.setFloat32(112, 1, isLittleEndian);
|
|
18471
|
+
view.setFloat32(116, 0, isLittleEndian);
|
|
18409
18472
|
} else {
|
|
18410
|
-
view.setFloat32(108,
|
|
18411
|
-
view.setFloat32(112, hdr.scl_slope,
|
|
18412
|
-
view.setFloat32(116, hdr.scl_inter,
|
|
18473
|
+
view.setFloat32(108, 352, isLittleEndian);
|
|
18474
|
+
view.setFloat32(112, hdr.scl_slope, isLittleEndian);
|
|
18475
|
+
view.setFloat32(116, hdr.scl_inter, isLittleEndian);
|
|
18413
18476
|
}
|
|
18414
|
-
view.setInt16(120, hdr.slice_end,
|
|
18477
|
+
view.setInt16(120, hdr.slice_end, isLittleEndian);
|
|
18415
18478
|
view.setUint8(122, hdr.slice_code);
|
|
18416
|
-
|
|
18479
|
+
if (hdr.xyzt_units === 0) {
|
|
18480
|
+
view.setUint8(123, 10);
|
|
18481
|
+
} else {
|
|
18482
|
+
view.setUint8(123, hdr.xyzt_units);
|
|
18483
|
+
}
|
|
18417
18484
|
if (isDrawing8) {
|
|
18418
|
-
view.setFloat32(124, 0,
|
|
18419
|
-
view.setFloat32(128, 0,
|
|
18485
|
+
view.setFloat32(124, 0, isLittleEndian);
|
|
18486
|
+
view.setFloat32(128, 0, isLittleEndian);
|
|
18420
18487
|
} else {
|
|
18421
|
-
view.setFloat32(124, hdr.cal_max,
|
|
18422
|
-
view.setFloat32(128, hdr.cal_min,
|
|
18488
|
+
view.setFloat32(124, hdr.cal_max, isLittleEndian);
|
|
18489
|
+
view.setFloat32(128, hdr.cal_min, isLittleEndian);
|
|
18423
18490
|
}
|
|
18424
|
-
view.setFloat32(132, hdr.slice_duration,
|
|
18425
|
-
view.setFloat32(136, hdr.toffset,
|
|
18491
|
+
view.setFloat32(132, hdr.slice_duration, isLittleEndian);
|
|
18492
|
+
view.setFloat32(136, hdr.toffset, isLittleEndian);
|
|
18426
18493
|
byteArray.set(str2Buffer(hdr.description), 148);
|
|
18427
18494
|
byteArray.set(str2Buffer(hdr.aux_file), 228);
|
|
18428
|
-
view.setInt16(252, hdr.qform_code,
|
|
18429
|
-
|
|
18430
|
-
|
|
18431
|
-
|
|
18432
|
-
|
|
18433
|
-
|
|
18434
|
-
view.setFloat32(
|
|
18435
|
-
view.setFloat32(
|
|
18495
|
+
view.setInt16(252, hdr.qform_code, isLittleEndian);
|
|
18496
|
+
if (hdr.sform_code < 1 || hdr.sform_code < 1) {
|
|
18497
|
+
view.setInt16(254, 1, isLittleEndian);
|
|
18498
|
+
} else {
|
|
18499
|
+
view.setInt16(254, hdr.sform_code, isLittleEndian);
|
|
18500
|
+
}
|
|
18501
|
+
view.setFloat32(256, hdr.quatern_b, isLittleEndian);
|
|
18502
|
+
view.setFloat32(260, hdr.quatern_c, isLittleEndian);
|
|
18503
|
+
view.setFloat32(264, hdr.quatern_d, isLittleEndian);
|
|
18504
|
+
view.setFloat32(268, hdr.qoffset_x, isLittleEndian);
|
|
18505
|
+
view.setFloat32(272, hdr.qoffset_y, isLittleEndian);
|
|
18506
|
+
view.setFloat32(276, hdr.qoffset_z, isLittleEndian);
|
|
18436
18507
|
const flattened = hdr.affine.flat();
|
|
18437
18508
|
for (let i = 0; i < 12; i++) {
|
|
18438
|
-
view.setFloat32(280 + FLOAT32_SIZE * i, flattened[i],
|
|
18509
|
+
view.setFloat32(280 + FLOAT32_SIZE * i, flattened[i], isLittleEndian);
|
|
18439
18510
|
}
|
|
18440
|
-
|
|
18441
|
-
byteArray.set(str2Buffer(hdr.magic), 344);
|
|
18511
|
+
view.setInt32(344, 3222382, true);
|
|
18442
18512
|
return byteArray;
|
|
18443
18513
|
}
|
|
18444
18514
|
function getExtents(positions, forceOriginInVolume = true) {
|
|
@@ -19982,7 +20052,7 @@ var NVImage = class _NVImage {
|
|
|
19982
20052
|
hdr.datatypeCode = 64 /* DT_FLOAT64 */;
|
|
19983
20053
|
break;
|
|
19984
20054
|
default:
|
|
19985
|
-
throw new Error("Unsupported
|
|
20055
|
+
throw new Error("Unsupported MHA data type: " + items[0]);
|
|
19986
20056
|
}
|
|
19987
20057
|
}
|
|
19988
20058
|
if (line.startsWith("ObjectType") && !items[0].includes("Image")) {
|
|
@@ -20004,6 +20074,9 @@ var NVImage = class _NVImage {
|
|
|
20004
20074
|
[mat33[2], mat33[5], mat33[8], offset[2]],
|
|
20005
20075
|
[0, 0, 0, 1]
|
|
20006
20076
|
];
|
|
20077
|
+
while (bytes[pos] === 10) {
|
|
20078
|
+
pos++;
|
|
20079
|
+
}
|
|
20007
20080
|
hdr.vox_offset = pos;
|
|
20008
20081
|
if (isDetached && pairedImgData) {
|
|
20009
20082
|
if (isGz) {
|
|
@@ -22211,6 +22284,7 @@ var DEFAULT_OPTIONS = {
|
|
|
22211
22284
|
multiplanarPadPixels: 0,
|
|
22212
22285
|
// @deprecated
|
|
22213
22286
|
multiplanarForceRender: false,
|
|
22287
|
+
multiplanarEqualSize: false,
|
|
22214
22288
|
multiplanarShowRender: 2 /* AUTO */,
|
|
22215
22289
|
// auto is the same behaviour as multiplanarForceRender: false
|
|
22216
22290
|
isRadiologicalConvention: false,
|
|
@@ -22251,6 +22325,7 @@ var DEFAULT_OPTIONS = {
|
|
|
22251
22325
|
clickToSegmentBright: true
|
|
22252
22326
|
};
|
|
22253
22327
|
var INITIAL_SCENE_DATA = {
|
|
22328
|
+
gamma: 1,
|
|
22254
22329
|
azimuth: 110,
|
|
22255
22330
|
elevation: 10,
|
|
22256
22331
|
crosshairPos: vec38.create(),
|
|
@@ -22489,6 +22564,9 @@ var NVDocument = class _NVDocument {
|
|
|
22489
22564
|
data.opts.meshThicknessOn2D = "infinity";
|
|
22490
22565
|
}
|
|
22491
22566
|
data.labels = [...this.data.labels];
|
|
22567
|
+
for (const label of data.labels) {
|
|
22568
|
+
delete label.onClick;
|
|
22569
|
+
}
|
|
22492
22570
|
data.customData = this.customData;
|
|
22493
22571
|
if (this.volumes.length) {
|
|
22494
22572
|
let imageOptions = this.imageOptionsArray[0];
|
|
@@ -22744,6 +22822,19 @@ var LabelLineTerminator = /* @__PURE__ */ ((LabelLineTerminator2) => {
|
|
|
22744
22822
|
LabelLineTerminator2["RING"] = "ring";
|
|
22745
22823
|
return LabelLineTerminator2;
|
|
22746
22824
|
})(LabelLineTerminator || {});
|
|
22825
|
+
var LabelAnchorPoint = /* @__PURE__ */ ((LabelAnchorPoint2) => {
|
|
22826
|
+
LabelAnchorPoint2[LabelAnchorPoint2["NONE"] = 0 /* NONE */] = "NONE";
|
|
22827
|
+
LabelAnchorPoint2[LabelAnchorPoint2["TOPLEFT"] = 9] = "TOPLEFT";
|
|
22828
|
+
LabelAnchorPoint2[LabelAnchorPoint2["TOPCENTER"] = 10] = "TOPCENTER";
|
|
22829
|
+
LabelAnchorPoint2[LabelAnchorPoint2["TOPRIGHT"] = 12] = "TOPRIGHT";
|
|
22830
|
+
LabelAnchorPoint2[LabelAnchorPoint2["MIDDLELEFT"] = 17] = "MIDDLELEFT";
|
|
22831
|
+
LabelAnchorPoint2[LabelAnchorPoint2["MIDDLECENTER"] = 18] = "MIDDLECENTER";
|
|
22832
|
+
LabelAnchorPoint2[LabelAnchorPoint2["MIDDLERIGHT"] = 20] = "MIDDLERIGHT";
|
|
22833
|
+
LabelAnchorPoint2[LabelAnchorPoint2["BOTTOMLEFT"] = 33] = "BOTTOMLEFT";
|
|
22834
|
+
LabelAnchorPoint2[LabelAnchorPoint2["BOTTOMCENTER"] = 34] = "BOTTOMCENTER";
|
|
22835
|
+
LabelAnchorPoint2[LabelAnchorPoint2["BOTTOMRIGHT"] = 36] = "BOTTOMRIGHT";
|
|
22836
|
+
return LabelAnchorPoint2;
|
|
22837
|
+
})(LabelAnchorPoint || {});
|
|
22747
22838
|
var NVLabel3DStyle = class {
|
|
22748
22839
|
/**
|
|
22749
22840
|
* @param textColor - Color of text
|
|
@@ -22781,13 +22872,17 @@ var NVLabel3D = class {
|
|
|
22781
22872
|
* @param style - The style of the label
|
|
22782
22873
|
* @param points - An array of points label for label lines
|
|
22783
22874
|
*/
|
|
22784
|
-
constructor(text, style, points) {
|
|
22875
|
+
constructor(text, style, points, anchor, onClick) {
|
|
22785
22876
|
__publicField(this, "text");
|
|
22786
22877
|
__publicField(this, "style");
|
|
22787
22878
|
__publicField(this, "points");
|
|
22879
|
+
__publicField(this, "anchor");
|
|
22880
|
+
__publicField(this, "onClick");
|
|
22788
22881
|
this.text = text;
|
|
22789
22882
|
this.style = style;
|
|
22790
22883
|
this.points = points;
|
|
22884
|
+
this.anchor = anchor || 0 /* NONE */;
|
|
22885
|
+
this.onClick = onClick;
|
|
22791
22886
|
}
|
|
22792
22887
|
};
|
|
22793
22888
|
|
|
@@ -23929,6 +24024,7 @@ var Niivue = class _Niivue {
|
|
|
23929
24024
|
* @param options - options object to set modifiable Niivue properties
|
|
23930
24025
|
*/
|
|
23931
24026
|
constructor(options = DEFAULT_OPTIONS) {
|
|
24027
|
+
__publicField(this, "loaders", {});
|
|
23932
24028
|
__publicField(this, "canvas", null);
|
|
23933
24029
|
// the reference to the canvas element on the page
|
|
23934
24030
|
__publicField(this, "_gl", null);
|
|
@@ -24101,6 +24197,10 @@ var Niivue = class _Niivue {
|
|
|
24101
24197
|
Name: "Hemispheric",
|
|
24102
24198
|
Frag: fragMeshHemiShader
|
|
24103
24199
|
},
|
|
24200
|
+
{
|
|
24201
|
+
Name: "Crevice",
|
|
24202
|
+
Frag: fragMeshShaderCrevice
|
|
24203
|
+
},
|
|
24104
24204
|
{
|
|
24105
24205
|
Name: "Edge",
|
|
24106
24206
|
Frag: fragMeshEdgeShader
|
|
@@ -24534,6 +24634,11 @@ var Niivue = class _Niivue {
|
|
|
24534
24634
|
}
|
|
24535
24635
|
const thisMM = this.frac2mm(this.scene.crosshairPos);
|
|
24536
24636
|
if (this.otherNV instanceof _Niivue) {
|
|
24637
|
+
const thisGamma = this.scene.gamma;
|
|
24638
|
+
const otherGamma = this.otherNV.scene.gamma;
|
|
24639
|
+
if (thisGamma !== otherGamma) {
|
|
24640
|
+
this.otherNV.setGamma(thisGamma);
|
|
24641
|
+
}
|
|
24537
24642
|
if (this.syncOpts["2d"]) {
|
|
24538
24643
|
this.otherNV.scene.crosshairPos = this.otherNV.mm2frac(thisMM);
|
|
24539
24644
|
this.otherNV.scene.pan2Dxyzmm = vec48.clone(this.scene.pan2Dxyzmm);
|
|
@@ -24550,6 +24655,11 @@ var Niivue = class _Niivue {
|
|
|
24550
24655
|
if (this.otherNV[i] === this) {
|
|
24551
24656
|
continue;
|
|
24552
24657
|
}
|
|
24658
|
+
const thisGamma = this.scene.gamma;
|
|
24659
|
+
const otherGamma = this.otherNV[i].scene.gamma;
|
|
24660
|
+
if (thisGamma !== otherGamma) {
|
|
24661
|
+
this.otherNV[i].setGamma(thisGamma);
|
|
24662
|
+
}
|
|
24553
24663
|
if (this.syncOpts["2d"]) {
|
|
24554
24664
|
this.otherNV[i].scene.crosshairPos = this.otherNV[i].mm2frac(thisMM);
|
|
24555
24665
|
this.otherNV[i].scene.pan2Dxyzmm = vec48.clone(this.scene.pan2Dxyzmm);
|
|
@@ -24665,6 +24775,10 @@ var Niivue = class _Niivue {
|
|
|
24665
24775
|
const [x, y] = [pos.x * this.uiData.dpr, pos.y * this.uiData.dpr];
|
|
24666
24776
|
const label = this.getLabelAtPoint([x, y]);
|
|
24667
24777
|
if (label) {
|
|
24778
|
+
if (label.onClick) {
|
|
24779
|
+
label.onClick(label);
|
|
24780
|
+
return;
|
|
24781
|
+
}
|
|
24668
24782
|
for (const mesh of this.meshes) {
|
|
24669
24783
|
if (mesh.type !== "connectome" /* CONNECTOME */) {
|
|
24670
24784
|
continue;
|
|
@@ -24979,6 +25093,15 @@ var Niivue = class _Niivue {
|
|
|
24979
25093
|
this.drawScene();
|
|
24980
25094
|
this.uiData.prevX = this.uiData.currX;
|
|
24981
25095
|
this.uiData.prevY = this.uiData.currY;
|
|
25096
|
+
} else if (!this.uiData.mousedown && this.opts.clickToSegment) {
|
|
25097
|
+
const pos = this.getNoPaddingNoBorderCanvasRelativeMousePosition(e, this.gl.canvas);
|
|
25098
|
+
if (!pos) {
|
|
25099
|
+
return;
|
|
25100
|
+
}
|
|
25101
|
+
const x = pos.x * this.uiData.dpr;
|
|
25102
|
+
const y = pos.y * this.uiData.dpr;
|
|
25103
|
+
this.mousePos = [x, y];
|
|
25104
|
+
this.drawScene();
|
|
24982
25105
|
}
|
|
24983
25106
|
}
|
|
24984
25107
|
// not included in public docs
|
|
@@ -25216,6 +25339,11 @@ var Niivue = class _Niivue {
|
|
|
25216
25339
|
if (ext === "GZ") {
|
|
25217
25340
|
ext = re.exec(fullname.slice(0, -3))[1];
|
|
25218
25341
|
ext = ext.toUpperCase();
|
|
25342
|
+
} else if (ext === "CBOR") {
|
|
25343
|
+
const endExt = ext;
|
|
25344
|
+
ext = re.exec(fullname.slice(0, -5))[1];
|
|
25345
|
+
ext = ext.toUpperCase();
|
|
25346
|
+
ext = `${ext}.${endExt}`;
|
|
25219
25347
|
}
|
|
25220
25348
|
return upperCase ? ext : ext.toLowerCase();
|
|
25221
25349
|
}
|
|
@@ -25236,6 +25364,28 @@ var Niivue = class _Niivue {
|
|
|
25236
25364
|
}
|
|
25237
25365
|
async addVolumesFromUrl(imageOptionsArray) {
|
|
25238
25366
|
const promises = imageOptionsArray.map(async (imageItem) => {
|
|
25367
|
+
const ext = this.getFileExt(imageItem.name || imageItem.url);
|
|
25368
|
+
if (this.loaders[ext]) {
|
|
25369
|
+
let itemToLoad = imageItem.url;
|
|
25370
|
+
const toExt = this.loaders[ext].toExt;
|
|
25371
|
+
let name = imageItem.name || imageItem.url;
|
|
25372
|
+
name = name.split("/").pop();
|
|
25373
|
+
if (typeof imageItem.url === "string") {
|
|
25374
|
+
const url = imageItem.url;
|
|
25375
|
+
try {
|
|
25376
|
+
const response = await fetch(url);
|
|
25377
|
+
if (!response.ok) {
|
|
25378
|
+
throw new Error(`Failed to load file: ${response.statusText}`);
|
|
25379
|
+
}
|
|
25380
|
+
itemToLoad = await response.arrayBuffer();
|
|
25381
|
+
} catch (error) {
|
|
25382
|
+
throw new Error(`Failed to load url ${url}: ${error}`);
|
|
25383
|
+
}
|
|
25384
|
+
}
|
|
25385
|
+
const buffer = await this.loaders[ext].loader(itemToLoad);
|
|
25386
|
+
imageItem.url = buffer;
|
|
25387
|
+
imageItem.name = `${name}.${toExt}`;
|
|
25388
|
+
}
|
|
25239
25389
|
const imageOptions = {
|
|
25240
25390
|
url: imageItem.url,
|
|
25241
25391
|
headers: imageItem.headers,
|
|
@@ -25375,6 +25525,40 @@ var Niivue = class _Niivue {
|
|
|
25375
25525
|
this.addVolume(volume);
|
|
25376
25526
|
});
|
|
25377
25527
|
}
|
|
25528
|
+
/* useLoader
|
|
25529
|
+
|
|
25530
|
+
registers an external file loader for niivue to use when reading files.
|
|
25531
|
+
|
|
25532
|
+
the loader must return an array buffer of the file contents for niivue
|
|
25533
|
+
to parse and the extension of the file so niivue can infer the file type to load.
|
|
25534
|
+
|
|
25535
|
+
example:
|
|
25536
|
+
|
|
25537
|
+
const myCustomLoader = (File) => {
|
|
25538
|
+
// ... do parsing here ...
|
|
25539
|
+
return {
|
|
25540
|
+
arrayBuffer: ArrayBuffer,
|
|
25541
|
+
fileExt: 'iwi.cbor',
|
|
25542
|
+
positions: Float32Array | [], // allows for mesh loading to mz3
|
|
25543
|
+
indices: Uint32Array | [], // allows for mesh loading to mz3
|
|
25544
|
+
}
|
|
25545
|
+
|
|
25546
|
+
nv.useLoader({
|
|
25547
|
+
loader: myCustomLoader,
|
|
25548
|
+
fileExt: 'iwi.cbor',
|
|
25549
|
+
toExt: 'nii'
|
|
25550
|
+
})
|
|
25551
|
+
|
|
25552
|
+
*/
|
|
25553
|
+
useLoader(loader, fileExt, toExt) {
|
|
25554
|
+
this.loaders = {
|
|
25555
|
+
...this.loaders,
|
|
25556
|
+
[fileExt.toUpperCase()]: {
|
|
25557
|
+
loader,
|
|
25558
|
+
toExt
|
|
25559
|
+
}
|
|
25560
|
+
};
|
|
25561
|
+
}
|
|
25378
25562
|
// not included in public docs
|
|
25379
25563
|
dropListener(e) {
|
|
25380
25564
|
e.stopPropagation();
|
|
@@ -25503,7 +25687,6 @@ var Niivue = class _Niivue {
|
|
|
25503
25687
|
this.loadDrawing(volume);
|
|
25504
25688
|
} else {
|
|
25505
25689
|
this.addVolume(volume);
|
|
25506
|
-
this.setDrawingEnabled(true);
|
|
25507
25690
|
}
|
|
25508
25691
|
}).catch((e2) => {
|
|
25509
25692
|
throw e2;
|
|
@@ -27047,6 +27230,37 @@ var Niivue = class _Niivue {
|
|
|
27047
27230
|
this.document.meshes = this.meshes;
|
|
27048
27231
|
return this.document.download(fileName, compress2);
|
|
27049
27232
|
}
|
|
27233
|
+
// generic loadImages that wraps loadVolumes and loadMeshes
|
|
27234
|
+
async loadImages(images) {
|
|
27235
|
+
const volumes = [];
|
|
27236
|
+
const meshes = [];
|
|
27237
|
+
for (const image of images) {
|
|
27238
|
+
if ("url" in image) {
|
|
27239
|
+
const ext = this.getFileExt(image.url);
|
|
27240
|
+
if (this.loaders[ext]) {
|
|
27241
|
+
const toExt = this.loaders[ext].toExt.toUpperCase();
|
|
27242
|
+
if (MESH_EXTENSIONS.includes(toExt)) {
|
|
27243
|
+
meshes.push(image);
|
|
27244
|
+
} else {
|
|
27245
|
+
volumes.push(image);
|
|
27246
|
+
}
|
|
27247
|
+
continue;
|
|
27248
|
+
}
|
|
27249
|
+
if (MESH_EXTENSIONS.includes(ext.toUpperCase())) {
|
|
27250
|
+
meshes.push(image);
|
|
27251
|
+
} else {
|
|
27252
|
+
volumes.push(image);
|
|
27253
|
+
}
|
|
27254
|
+
}
|
|
27255
|
+
}
|
|
27256
|
+
if (volumes.length > 0) {
|
|
27257
|
+
await this.loadVolumes(volumes);
|
|
27258
|
+
}
|
|
27259
|
+
if (meshes.length > 0) {
|
|
27260
|
+
await this.loadMeshes(meshes);
|
|
27261
|
+
}
|
|
27262
|
+
return this;
|
|
27263
|
+
}
|
|
27050
27264
|
/**
|
|
27051
27265
|
* load an array of volume objects
|
|
27052
27266
|
* @param volumeList - the array of objects to load. each object must have a resolvable "url" property at a minimum
|
|
@@ -27066,27 +27280,7 @@ var Niivue = class _Niivue {
|
|
|
27066
27280
|
this.volumes = [];
|
|
27067
27281
|
this.gl.clearColor(0, 0, 0, 1);
|
|
27068
27282
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
27069
|
-
|
|
27070
|
-
await this.addVolumesFromUrl(volumeList);
|
|
27071
|
-
return this;
|
|
27072
|
-
}
|
|
27073
|
-
const imageOptions = {
|
|
27074
|
-
url: volumeList[0].url,
|
|
27075
|
-
headers: volumeList[0].headers,
|
|
27076
|
-
name: volumeList[0].name,
|
|
27077
|
-
colormap: volumeList[0].colormap ? volumeList[0].colormap : volumeList[0].colorMap,
|
|
27078
|
-
colormapNegative: volumeList[0].colormapNegative ? volumeList[0].colormapNegative : volumeList[0].colorMapNegative,
|
|
27079
|
-
opacity: volumeList[0].opacity,
|
|
27080
|
-
urlImgData: volumeList[0].urlImgData,
|
|
27081
|
-
cal_min: volumeList[0].cal_min,
|
|
27082
|
-
cal_max: volumeList[0].cal_max,
|
|
27083
|
-
trustCalMinMax: this.opts.trustCalMinMax,
|
|
27084
|
-
isManifest: volumeList[0].isManifest,
|
|
27085
|
-
frame4D: volumeList[0].frame4D,
|
|
27086
|
-
limitFrames4D: volumeList[0].limitFrames4D || this.opts.limitFrames4D,
|
|
27087
|
-
colorbarVisible: volumeList[0].colorbarVisible
|
|
27088
|
-
};
|
|
27089
|
-
await this.addVolumeFromUrl(imageOptions);
|
|
27283
|
+
await this.addVolumesFromUrl(volumeList);
|
|
27090
27284
|
return this;
|
|
27091
27285
|
}
|
|
27092
27286
|
/**
|
|
@@ -27116,7 +27310,29 @@ var Niivue = class _Niivue {
|
|
|
27116
27310
|
*/
|
|
27117
27311
|
async addMeshesFromUrl(meshOptions) {
|
|
27118
27312
|
const promises = meshOptions.map(async (meshItem) => {
|
|
27119
|
-
const ext = this.getFileExt(meshItem.url);
|
|
27313
|
+
const ext = this.getFileExt(meshItem.name || meshItem.url);
|
|
27314
|
+
if (this.loaders[ext]) {
|
|
27315
|
+
let itemToLoad = meshItem.url;
|
|
27316
|
+
const toExt = this.loaders[ext].toExt;
|
|
27317
|
+
let name = meshItem.name || meshItem.url;
|
|
27318
|
+
name = name.split("/").pop();
|
|
27319
|
+
if (typeof meshItem.url === "string") {
|
|
27320
|
+
const url = meshItem.url;
|
|
27321
|
+
try {
|
|
27322
|
+
const response = await fetch(url);
|
|
27323
|
+
if (!response.ok) {
|
|
27324
|
+
throw new Error(`Failed to load file: ${response.statusText}`);
|
|
27325
|
+
}
|
|
27326
|
+
itemToLoad = await response.arrayBuffer();
|
|
27327
|
+
} catch (error) {
|
|
27328
|
+
throw new Error(`Failed to load url ${url}: ${error}`);
|
|
27329
|
+
}
|
|
27330
|
+
}
|
|
27331
|
+
const { positions, indices } = await this.loaders[ext].loader(itemToLoad);
|
|
27332
|
+
meshItem.name = `${name}.${toExt}`;
|
|
27333
|
+
const mz3 = NVMeshUtilities.createMZ3(positions, indices, false);
|
|
27334
|
+
meshItem.buffer = mz3;
|
|
27335
|
+
}
|
|
27120
27336
|
if (ext === "JCON" || ext === "JSON") {
|
|
27121
27337
|
const response = await fetch(meshItem.url, {});
|
|
27122
27338
|
const json = await response.json();
|
|
@@ -27157,13 +27373,7 @@ var Niivue = class _Niivue {
|
|
|
27157
27373
|
this.meshes = [];
|
|
27158
27374
|
this.gl.clearColor(0, 0, 0, 1);
|
|
27159
27375
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
27160
|
-
|
|
27161
|
-
await this.addMeshesFromUrl(meshList);
|
|
27162
|
-
this.updateGLVolume();
|
|
27163
|
-
this.drawScene();
|
|
27164
|
-
return this;
|
|
27165
|
-
}
|
|
27166
|
-
await this.addMeshFromUrl(meshList[0]);
|
|
27376
|
+
await this.addMeshesFromUrl(meshList);
|
|
27167
27377
|
this.updateGLVolume();
|
|
27168
27378
|
this.drawScene();
|
|
27169
27379
|
return this;
|
|
@@ -29728,6 +29938,7 @@ var Niivue = class _Niivue {
|
|
|
29728
29938
|
* @see {@link https://niivue.github.io/niivue/features/colormaps.html | live demo usage}
|
|
29729
29939
|
*/
|
|
29730
29940
|
setGamma(gamma = 1) {
|
|
29941
|
+
this.scene.gamma = gamma;
|
|
29731
29942
|
cmapper.gamma = gamma;
|
|
29732
29943
|
this.updateGLVolume();
|
|
29733
29944
|
}
|
|
@@ -30091,6 +30302,7 @@ var Niivue = class _Niivue {
|
|
|
30091
30302
|
}
|
|
30092
30303
|
if (this.opts.drawingEnabled) {
|
|
30093
30304
|
const pt = this.frac2vox(this.scene.crosshairPos);
|
|
30305
|
+
const ptMM = this.frac2mm(this.scene.crosshairPos);
|
|
30094
30306
|
if (this.opts.clickToSegment) {
|
|
30095
30307
|
const radius = this.opts.clickToSegmentRadius;
|
|
30096
30308
|
const steps = this.opts.clickToSegmentSteps;
|
|
@@ -30099,11 +30311,12 @@ var Niivue = class _Niivue {
|
|
|
30099
30311
|
this.drawPenAxCorSag = axCorSag;
|
|
30100
30312
|
for (let i2 = 1; i2 <= steps; i2++) {
|
|
30101
30313
|
const angle = i2 / steps * 2 * Math.PI;
|
|
30102
|
-
|
|
30103
|
-
|
|
30104
|
-
const
|
|
30105
|
-
xVox =
|
|
30106
|
-
yVox =
|
|
30314
|
+
const xMM = ptMM[0] + radius * Math.cos(angle);
|
|
30315
|
+
const yMM = ptMM[1] + radius * Math.sin(angle);
|
|
30316
|
+
const zMM = ptMM[2];
|
|
30317
|
+
const xVox = this.back.mm2vox([xMM, yMM, zMM])[0];
|
|
30318
|
+
const yVox = this.back.mm2vox([xMM, yMM, zMM])[1];
|
|
30319
|
+
const zVox = this.back.mm2vox([xMM, yMM, zMM])[2];
|
|
30107
30320
|
this.drawPt(xVox, yVox, zVox, this.opts.penValue);
|
|
30108
30321
|
this.drawPenFillPts.push([xVox, yVox, pt[2]]);
|
|
30109
30322
|
if (i2 === steps) {
|
|
@@ -30387,9 +30600,21 @@ var Niivue = class _Niivue {
|
|
|
30387
30600
|
const labels = [...this.document.labels, ...definedMeshLabels];
|
|
30388
30601
|
return labels;
|
|
30389
30602
|
}
|
|
30603
|
+
getConnectomeLabels() {
|
|
30604
|
+
const connectomes = this.meshes.filter((m) => m.type === "connectome" /* CONNECTOME */);
|
|
30605
|
+
const meshNodes = connectomes.flatMap((m) => m.nodes);
|
|
30606
|
+
const meshLabels = meshNodes.map((n) => n.label);
|
|
30607
|
+
const definedMeshLabels = meshLabels.filter((l) => l !== void 0);
|
|
30608
|
+
const nonAnchoredLabels = this.document.labels.filter((l) => l.anchor == null || l.anchor === 0 /* NONE */);
|
|
30609
|
+
const nonAnchoredLabelSet = new Set(definedMeshLabels);
|
|
30610
|
+
for (const label of nonAnchoredLabels) {
|
|
30611
|
+
nonAnchoredLabelSet.add(label);
|
|
30612
|
+
}
|
|
30613
|
+
return Array.from(nonAnchoredLabelSet);
|
|
30614
|
+
}
|
|
30390
30615
|
getBulletMarginWidth() {
|
|
30391
30616
|
let bulletMargin = 0;
|
|
30392
|
-
const labels = this.
|
|
30617
|
+
const labels = this.getConnectomeLabels();
|
|
30393
30618
|
if (labels.length === 0) {
|
|
30394
30619
|
return 0;
|
|
30395
30620
|
}
|
|
@@ -30406,7 +30631,7 @@ var Niivue = class _Niivue {
|
|
|
30406
30631
|
return bulletMargin;
|
|
30407
30632
|
}
|
|
30408
30633
|
getLegendPanelWidth() {
|
|
30409
|
-
const labels = this.
|
|
30634
|
+
const labels = this.getConnectomeLabels();
|
|
30410
30635
|
if (!this.opts.showLegend || labels.length === 0) {
|
|
30411
30636
|
return 0;
|
|
30412
30637
|
}
|
|
@@ -30432,7 +30657,7 @@ var Niivue = class _Niivue {
|
|
|
30432
30657
|
return width;
|
|
30433
30658
|
}
|
|
30434
30659
|
getLegendPanelHeight() {
|
|
30435
|
-
const labels = this.
|
|
30660
|
+
const labels = this.getConnectomeLabels();
|
|
30436
30661
|
let height = 0;
|
|
30437
30662
|
const scale = 1;
|
|
30438
30663
|
const verticalMargin = this.opts.textHeight * this.gl.canvas.height * scale;
|
|
@@ -30874,7 +31099,7 @@ var Niivue = class _Niivue {
|
|
|
30874
31099
|
}
|
|
30875
31100
|
// not included in public docs
|
|
30876
31101
|
// show text labels for L/R, A/P, I/S dimensions
|
|
30877
|
-
drawSliceOrientationText(leftTopWidthHeight, axCorSag) {
|
|
31102
|
+
drawSliceOrientationText(leftTopWidthHeight, axCorSag, padLeftTop = [NaN, NaN]) {
|
|
30878
31103
|
this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);
|
|
30879
31104
|
let topText = "S";
|
|
30880
31105
|
if (axCorSag === 0 /* AXIAL */) {
|
|
@@ -30888,8 +31113,32 @@ var Niivue = class _Niivue {
|
|
|
30888
31113
|
this.drawTextRightBelow([leftTopWidthHeight[0], leftTopWidthHeight[1]], leftText + topText);
|
|
30889
31114
|
return;
|
|
30890
31115
|
}
|
|
30891
|
-
|
|
30892
|
-
|
|
31116
|
+
let drawBelow = true;
|
|
31117
|
+
let drawRight = true;
|
|
31118
|
+
if (!isNaN(padLeftTop[0])) {
|
|
31119
|
+
const ht = this.opts.textHeight * this.gl.canvas.height + 2;
|
|
31120
|
+
if (padLeftTop[1] > ht) {
|
|
31121
|
+
this.drawTextBelow(
|
|
31122
|
+
[leftTopWidthHeight[0] + leftTopWidthHeight[2] * 0.5, leftTopWidthHeight[1] + padLeftTop[1] - ht],
|
|
31123
|
+
topText
|
|
31124
|
+
);
|
|
31125
|
+
drawBelow = false;
|
|
31126
|
+
}
|
|
31127
|
+
const wid = this.textWidth(ht, leftText) + 2;
|
|
31128
|
+
if (padLeftTop[0] > wid) {
|
|
31129
|
+
this.drawTextRight(
|
|
31130
|
+
[leftTopWidthHeight[0] + padLeftTop[0] - wid, leftTopWidthHeight[1] + leftTopWidthHeight[3] * 0.5],
|
|
31131
|
+
leftText
|
|
31132
|
+
);
|
|
31133
|
+
drawRight = false;
|
|
31134
|
+
}
|
|
31135
|
+
}
|
|
31136
|
+
if (drawBelow) {
|
|
31137
|
+
this.drawTextBelow([leftTopWidthHeight[0] + leftTopWidthHeight[2] * 0.5, leftTopWidthHeight[1]], topText);
|
|
31138
|
+
}
|
|
31139
|
+
if (drawRight) {
|
|
31140
|
+
this.drawTextRight([leftTopWidthHeight[0], leftTopWidthHeight[1] + leftTopWidthHeight[3] * 0.5], leftText);
|
|
31141
|
+
}
|
|
30893
31142
|
}
|
|
30894
31143
|
// not included in public docs
|
|
30895
31144
|
xyMM2xyzMM(axCorSag, sliceFrac) {
|
|
@@ -30927,7 +31176,7 @@ var Niivue = class _Niivue {
|
|
|
30927
31176
|
}
|
|
30928
31177
|
// not included in public docs
|
|
30929
31178
|
// draw 2D tile
|
|
30930
|
-
|
|
31179
|
+
draw2DMain(leftTopWidthHeight, axCorSag, customMM = NaN) {
|
|
30931
31180
|
let frac2mmTexture = this.volumes[0].frac2mm.slice();
|
|
30932
31181
|
let screen = this.screenFieldOfViewExtendedMM(axCorSag);
|
|
30933
31182
|
let mesh2ortho = mat46.create();
|
|
@@ -30956,7 +31205,9 @@ var Niivue = class _Niivue {
|
|
|
30956
31205
|
elevation = isRadiolgical ? -90 : 90;
|
|
30957
31206
|
}
|
|
30958
31207
|
const gl = this.gl;
|
|
31208
|
+
let isStretchToScreen = false;
|
|
30959
31209
|
if (leftTopWidthHeight[2] === 0 || leftTopWidthHeight[3] === 0) {
|
|
31210
|
+
isStretchToScreen = true;
|
|
30960
31211
|
const pixPerMMw = gl.canvas.width / screen.fovMM[0];
|
|
30961
31212
|
const pixPerMMh = gl.canvas.height / screen.fovMM[1];
|
|
30962
31213
|
const pixPerMMmin = Math.min(pixPerMMw, pixPerMMh);
|
|
@@ -31103,9 +31354,32 @@ var Niivue = class _Niivue {
|
|
|
31103
31354
|
if (isNaN(customMM)) {
|
|
31104
31355
|
this.drawCrosshairs3D(false, 0.15, obj.modelViewProjectionMatrix, true, this.opts.isSliceMM);
|
|
31105
31356
|
}
|
|
31106
|
-
|
|
31357
|
+
if (isStretchToScreen) {
|
|
31358
|
+
this.drawSliceOrientationText(leftTopWidthHeight, axCorSag);
|
|
31359
|
+
}
|
|
31107
31360
|
this.readyForSync = true;
|
|
31108
31361
|
}
|
|
31362
|
+
draw2D(leftTopWidthHeight, axCorSag, customMM = NaN, imageWidthHeight = [NaN, NaN]) {
|
|
31363
|
+
const padLeftTop = [NaN, NaN];
|
|
31364
|
+
if (isNaN(imageWidthHeight[0])) {
|
|
31365
|
+
this.draw2DMain(leftTopWidthHeight, axCorSag, customMM);
|
|
31366
|
+
} else {
|
|
31367
|
+
const ltwh = leftTopWidthHeight.slice();
|
|
31368
|
+
padLeftTop[0] = Math.floor(0.5 * (ltwh[2] - imageWidthHeight[0]));
|
|
31369
|
+
padLeftTop[1] = Math.floor(0.5 * (ltwh[3] - imageWidthHeight[1]));
|
|
31370
|
+
ltwh[0] += padLeftTop[0];
|
|
31371
|
+
ltwh[1] += padLeftTop[1];
|
|
31372
|
+
ltwh[2] = imageWidthHeight[0];
|
|
31373
|
+
ltwh[3] = imageWidthHeight[1];
|
|
31374
|
+
this.draw2DMain(ltwh, axCorSag, customMM);
|
|
31375
|
+
}
|
|
31376
|
+
if (customMM === Infinity || customMM === -Infinity || axCorSag === 4 /* RENDER */) {
|
|
31377
|
+
return;
|
|
31378
|
+
}
|
|
31379
|
+
if (leftTopWidthHeight[2] !== 0 && leftTopWidthHeight[3] !== 0) {
|
|
31380
|
+
this.drawSliceOrientationText(leftTopWidthHeight, axCorSag, padLeftTop);
|
|
31381
|
+
}
|
|
31382
|
+
}
|
|
31109
31383
|
// not included in public docs
|
|
31110
31384
|
// determine 3D model view projection matrix
|
|
31111
31385
|
calculateMvpMatrix(_unused, leftTopWidthHeight = [0, 0, 0, 0], azimuth, elevation) {
|
|
@@ -31716,7 +31990,7 @@ var Niivue = class _Niivue {
|
|
|
31716
31990
|
* @param style - label style
|
|
31717
31991
|
* @param point - 3D point on the model
|
|
31718
31992
|
*/
|
|
31719
|
-
addLabel(text, style, points) {
|
|
31993
|
+
addLabel(text, style, points, anchor, onClick) {
|
|
31720
31994
|
const defaultStyle = {
|
|
31721
31995
|
textColor: this.opts.legendTextColor,
|
|
31722
31996
|
textScale: 1,
|
|
@@ -31728,7 +32002,7 @@ var Niivue = class _Niivue {
|
|
|
31728
32002
|
bulletColor: this.opts.legendTextColor
|
|
31729
32003
|
};
|
|
31730
32004
|
const labelStyle = style ? { ...defaultStyle, ...style } : { ...defaultStyle };
|
|
31731
|
-
const label = new NVLabel3D(text, labelStyle, points);
|
|
32005
|
+
const label = new NVLabel3D(text, { ...labelStyle }, points, anchor, onClick);
|
|
31732
32006
|
this.document.labels.push(label);
|
|
31733
32007
|
return label;
|
|
31734
32008
|
}
|
|
@@ -31746,6 +32020,60 @@ var Niivue = class _Niivue {
|
|
|
31746
32020
|
return screenPoint;
|
|
31747
32021
|
}
|
|
31748
32022
|
getLabelAtPoint(screenPoint) {
|
|
32023
|
+
const scale = 1;
|
|
32024
|
+
const size = this.opts.textHeight * Math.min(this.gl.canvas.height, this.gl.canvas.width) * scale;
|
|
32025
|
+
const verticalMargin = this.opts.textHeight * this.gl.canvas.height * scale;
|
|
32026
|
+
for (const label of this.document.labels) {
|
|
32027
|
+
if (label.anchor == null || label.anchor === 0 /* NONE */) {
|
|
32028
|
+
continue;
|
|
32029
|
+
}
|
|
32030
|
+
const labelSize = this.opts.textHeight * this.gl.canvas.height * label.style.textScale;
|
|
32031
|
+
const textHeight = this.textHeight(labelSize, label.text);
|
|
32032
|
+
const textWidth = this.textWidth(labelSize, label.text);
|
|
32033
|
+
if (label.anchor & 1 /* LEFT */) {
|
|
32034
|
+
if (screenPoint[0] > textWidth) {
|
|
32035
|
+
continue;
|
|
32036
|
+
}
|
|
32037
|
+
}
|
|
32038
|
+
if (label.anchor & 2 /* CENTER */) {
|
|
32039
|
+
if (screenPoint[0] < (this.gl.canvas.width - textWidth) / 2) {
|
|
32040
|
+
continue;
|
|
32041
|
+
}
|
|
32042
|
+
if (screenPoint[0] > (this.gl.canvas.width + textWidth) / 2) {
|
|
32043
|
+
continue;
|
|
32044
|
+
}
|
|
32045
|
+
}
|
|
32046
|
+
if (label.anchor & 4 /* RIGHT */) {
|
|
32047
|
+
if (screenPoint[0] < this.gl.canvas.width - textWidth) {
|
|
32048
|
+
continue;
|
|
32049
|
+
}
|
|
32050
|
+
}
|
|
32051
|
+
if (label.anchor & 8 /* TOP */) {
|
|
32052
|
+
if (screenPoint[1] < verticalMargin / 2) {
|
|
32053
|
+
continue;
|
|
32054
|
+
}
|
|
32055
|
+
if (screenPoint[1] > textHeight + verticalMargin / 2) {
|
|
32056
|
+
continue;
|
|
32057
|
+
}
|
|
32058
|
+
}
|
|
32059
|
+
if (label.anchor & 16 /* MIDDLE */) {
|
|
32060
|
+
if (screenPoint[1] < (this.gl.canvas.height - textHeight - verticalMargin) / 2) {
|
|
32061
|
+
continue;
|
|
32062
|
+
}
|
|
32063
|
+
if (screenPoint[1] > (this.gl.canvas.height + textHeight - verticalMargin / 2) / 2) {
|
|
32064
|
+
continue;
|
|
32065
|
+
}
|
|
32066
|
+
}
|
|
32067
|
+
if (label.anchor & 32 /* BOTTOM */) {
|
|
32068
|
+
if (screenPoint[1] < this.gl.canvas.height - textHeight - verticalMargin) {
|
|
32069
|
+
continue;
|
|
32070
|
+
}
|
|
32071
|
+
if (screenPoint[1] > this.gl.canvas.height - verticalMargin / 2) {
|
|
32072
|
+
continue;
|
|
32073
|
+
}
|
|
32074
|
+
}
|
|
32075
|
+
return label;
|
|
32076
|
+
}
|
|
31749
32077
|
log.debug("screenPoint", screenPoint);
|
|
31750
32078
|
const panelHeight = this.getLegendPanelHeight();
|
|
31751
32079
|
const panelWidth = this.getLegendPanelWidth();
|
|
@@ -31755,9 +32083,7 @@ var Niivue = class _Niivue {
|
|
|
31755
32083
|
if (screenPoint[0] < left || screenPoint[1] < top || screenPoint[0] > left + panelWidth || screenPoint[1] > top + panelHeight) {
|
|
31756
32084
|
return null;
|
|
31757
32085
|
}
|
|
31758
|
-
const
|
|
31759
|
-
const size = this.opts.textHeight * Math.min(this.gl.canvas.height, this.gl.canvas.width) * scale;
|
|
31760
|
-
const labels = this.getAllLabels();
|
|
32086
|
+
const labels = this.getConnectomeLabels();
|
|
31761
32087
|
for (const label of labels) {
|
|
31762
32088
|
const labelSize = this.opts.textHeight * this.gl.canvas.height * label.style.textScale;
|
|
31763
32089
|
const textHeight = this.textHeight(labelSize, label.text);
|
|
@@ -31786,7 +32112,7 @@ var Niivue = class _Niivue {
|
|
|
31786
32112
|
}
|
|
31787
32113
|
}
|
|
31788
32114
|
// not included in public docs
|
|
31789
|
-
draw3DLabel(label, pos, mvpMatrix, leftTopWidthHeight, bulletMargin
|
|
32115
|
+
draw3DLabel(label, pos, mvpMatrix, leftTopWidthHeight, bulletMargin, legendWidth, secondPass) {
|
|
31790
32116
|
const text = label.text;
|
|
31791
32117
|
const left = pos[0];
|
|
31792
32118
|
const top = pos[1];
|
|
@@ -31803,22 +32129,24 @@ var Niivue = class _Niivue {
|
|
|
31803
32129
|
this.drawCircle([rectLeft, rectTop, bulletSize, bulletSize], label.style.bulletColor);
|
|
31804
32130
|
}
|
|
31805
32131
|
let textLeft = left;
|
|
31806
|
-
if (
|
|
31807
|
-
|
|
31808
|
-
|
|
31809
|
-
|
|
32132
|
+
if (legendWidth) {
|
|
32133
|
+
if (label.style.textAlignment !== "left" /* LEFT */) {
|
|
32134
|
+
const textWidth = this.textWidth(label.style.textScale, label.text) * size;
|
|
32135
|
+
if (label.style.textAlignment === "right" /* RIGHT */) {
|
|
32136
|
+
textLeft = left + legendWidth - size * 1.5 - textWidth;
|
|
32137
|
+
} else {
|
|
32138
|
+
const remaining = legendWidth - (bulletMargin || size);
|
|
32139
|
+
textLeft += (remaining - textWidth) / 2;
|
|
32140
|
+
}
|
|
31810
32141
|
} else {
|
|
31811
|
-
|
|
31812
|
-
textLeft += (remaining - textWidth) / 2;
|
|
32142
|
+
textLeft += bulletMargin;
|
|
31813
32143
|
}
|
|
31814
|
-
} else {
|
|
31815
|
-
textLeft += bulletMargin;
|
|
31816
32144
|
}
|
|
31817
32145
|
this.drawText([textLeft, top], text, label.style.textScale, label.style.textColor);
|
|
31818
32146
|
}
|
|
31819
32147
|
// not included in public docs
|
|
31820
32148
|
draw3DLabels(mvpMatrix, leftTopWidthHeight, secondPass = false) {
|
|
31821
|
-
const labels = this.
|
|
32149
|
+
const labels = this.getConnectomeLabels();
|
|
31822
32150
|
if (!this.opts.showLegend || labels.length === 0) {
|
|
31823
32151
|
return;
|
|
31824
32152
|
}
|
|
@@ -31856,6 +32184,51 @@ var Niivue = class _Niivue {
|
|
|
31856
32184
|
}
|
|
31857
32185
|
}
|
|
31858
32186
|
}
|
|
32187
|
+
drawAnchoredLabels() {
|
|
32188
|
+
const size = this.opts.textHeight * Math.min(this.gl.canvas.height, this.gl.canvas.width) * 1;
|
|
32189
|
+
const anchoredLabels = this.document.labels.filter((l) => l.anchor != null && l.anchor !== 0 /* NONE */);
|
|
32190
|
+
for (const label of anchoredLabels) {
|
|
32191
|
+
const text = label.text;
|
|
32192
|
+
const textHeight = this.textHeight(label.style.textScale, text) * size;
|
|
32193
|
+
const textWidth = this.textWidth(label.style.textScale, text) * size;
|
|
32194
|
+
let left;
|
|
32195
|
+
let top;
|
|
32196
|
+
const scale = 1;
|
|
32197
|
+
const verticalMargin = this.opts.textHeight * this.gl.canvas.height * scale;
|
|
32198
|
+
const rectHeightDiff = verticalMargin;
|
|
32199
|
+
let rectWidthDiff = verticalMargin / 4;
|
|
32200
|
+
let rectHorizontalOffset = 0;
|
|
32201
|
+
let rectVerticalOffset = 0;
|
|
32202
|
+
if (label.anchor & 1 /* LEFT */) {
|
|
32203
|
+
left = 0;
|
|
32204
|
+
}
|
|
32205
|
+
if (label.anchor & 4 /* RIGHT */) {
|
|
32206
|
+
left = this.canvas.width - textWidth;
|
|
32207
|
+
rectHorizontalOffset -= verticalMargin / 4;
|
|
32208
|
+
}
|
|
32209
|
+
if (label.anchor & 2 /* CENTER */) {
|
|
32210
|
+
left = (this.canvas.width - textWidth) / 2;
|
|
32211
|
+
rectHorizontalOffset -= verticalMargin / 4;
|
|
32212
|
+
rectWidthDiff += verticalMargin / 4;
|
|
32213
|
+
}
|
|
32214
|
+
if (label.anchor & 8 /* TOP */) {
|
|
32215
|
+
top = 0;
|
|
32216
|
+
}
|
|
32217
|
+
if (label.anchor & 16 /* MIDDLE */) {
|
|
32218
|
+
top = (this.canvas.height - textHeight - verticalMargin) / 2;
|
|
32219
|
+
rectVerticalOffset -= verticalMargin / 4;
|
|
32220
|
+
}
|
|
32221
|
+
if (label.anchor & 32 /* BOTTOM */) {
|
|
32222
|
+
top = this.canvas.height - textHeight - verticalMargin;
|
|
32223
|
+
rectVerticalOffset -= verticalMargin / 4;
|
|
32224
|
+
}
|
|
32225
|
+
this.drawRect(
|
|
32226
|
+
[left + rectHorizontalOffset, top + rectVerticalOffset, textWidth + rectWidthDiff, textHeight + rectHeightDiff],
|
|
32227
|
+
label.style.backgroundColor
|
|
32228
|
+
);
|
|
32229
|
+
this.draw3DLabel(label, [left, top]);
|
|
32230
|
+
}
|
|
32231
|
+
}
|
|
31859
32232
|
// not included in public docs
|
|
31860
32233
|
draw3D(leftTopWidthHeight = [0, 0, 0, 0], mvpMatrix = null, modelMatrix = null, normalMatrix = null, azimuth = null, elevation = 0) {
|
|
31861
32234
|
const isMosaic = azimuth !== null;
|
|
@@ -32731,6 +33104,12 @@ var Niivue = class _Niivue {
|
|
|
32731
33104
|
}
|
|
32732
33105
|
const isDrawPenDown = isFinite(this.drawPenLocation[0]) && this.opts.drawingEnabled;
|
|
32733
33106
|
const { volScale } = this.sliceScale();
|
|
33107
|
+
const actualScale = volScale.slice();
|
|
33108
|
+
if (this.opts.multiplanarEqualSize) {
|
|
33109
|
+
volScale[0] = 1;
|
|
33110
|
+
volScale[1] = 1;
|
|
33111
|
+
volScale[2] = 1;
|
|
33112
|
+
}
|
|
32734
33113
|
if (typeof this.opts.multiplanarPadPixels !== "number") {
|
|
32735
33114
|
log.debug("multiplanarPadPixels must be numeric");
|
|
32736
33115
|
}
|
|
@@ -32768,38 +33147,43 @@ var Niivue = class _Niivue {
|
|
|
32768
33147
|
isDrawGrid = true;
|
|
32769
33148
|
}
|
|
32770
33149
|
}
|
|
33150
|
+
let ltwh = ltwh2x2;
|
|
32771
33151
|
if (isDrawColumn) {
|
|
32772
|
-
|
|
33152
|
+
ltwh = ltwh1x3;
|
|
32773
33153
|
if (isShowRender || this.opts.multiplanarShowRender === 2 /* AUTO */ && ltwh1x4[4] >= ltwh1x3[4]) {
|
|
32774
33154
|
ltwh = ltwh1x4;
|
|
32775
33155
|
} else {
|
|
32776
33156
|
isDraw3D = false;
|
|
32777
33157
|
}
|
|
32778
|
-
const sX = volScale[0] * ltwh[4];
|
|
32779
|
-
const sY = volScale[1] * ltwh[4];
|
|
32780
|
-
const sZ = volScale[2] * ltwh[4];
|
|
32781
|
-
const sMx = mx * ltwh[4];
|
|
32782
|
-
this.draw2D([ltwh[0], ltwh[1], sX, sY], 0);
|
|
32783
|
-
this.draw2D([ltwh[0], ltwh[1] + sY + pad, sX, sZ], 1);
|
|
32784
|
-
this.draw2D([ltwh[0], ltwh[1] + sY + pad + sZ + pad, sY, sZ], 2);
|
|
32785
|
-
if (isDraw3D) {
|
|
32786
|
-
this.draw3D([ltwh[0], ltwh[1] + sY + sZ + sZ + pad * 3, sMx, sMx]);
|
|
32787
|
-
}
|
|
32788
33158
|
} else if (isDrawRow) {
|
|
32789
|
-
|
|
33159
|
+
ltwh = ltwh3x1;
|
|
32790
33160
|
if (isShowRender || this.opts.multiplanarShowRender === 2 /* AUTO */ && ltwh4x1[4] >= ltwh3x1[4]) {
|
|
32791
33161
|
ltwh = ltwh4x1;
|
|
32792
33162
|
} else {
|
|
32793
33163
|
isDraw3D = false;
|
|
32794
33164
|
}
|
|
32795
|
-
|
|
32796
|
-
|
|
32797
|
-
|
|
32798
|
-
|
|
32799
|
-
|
|
32800
|
-
|
|
33165
|
+
}
|
|
33166
|
+
const sX = volScale[0] * ltwh[4];
|
|
33167
|
+
const sY = volScale[1] * ltwh[4];
|
|
33168
|
+
const sZ = volScale[2] * ltwh[4];
|
|
33169
|
+
const actualX = actualScale[0] * ltwh[4];
|
|
33170
|
+
const actualY = actualScale[1] * ltwh[4];
|
|
33171
|
+
const actualZ = actualScale[2] * ltwh[4];
|
|
33172
|
+
if (isDrawColumn) {
|
|
33173
|
+
this.draw2D([ltwh[0], ltwh[1], sX, sY], 0, NaN, [actualX, actualY]);
|
|
33174
|
+
this.draw2D([ltwh[0], ltwh[1] + sY + pad, sX, sZ], 1, NaN, [actualX, actualZ]);
|
|
33175
|
+
this.draw2D([ltwh[0], ltwh[1] + sY + pad + sZ + pad, sY, sZ], 2, NaN, [actualY, actualZ]);
|
|
33176
|
+
if (isDraw3D) {
|
|
33177
|
+
const sMx = mx * ltwh[4];
|
|
33178
|
+
this.draw3D([ltwh[0], ltwh[1] + sY + sZ + sZ + pad * 3, sMx, sMx]);
|
|
33179
|
+
}
|
|
33180
|
+
} else if (isDrawRow) {
|
|
33181
|
+
this.draw2D([ltwh[0], ltwh[1], sX, sY], 0, NaN, [actualX, actualY]);
|
|
33182
|
+
this.draw2D([ltwh[0] + sX + pad, ltwh[1], sX, sZ], 1, NaN, [actualX, actualZ]);
|
|
33183
|
+
this.draw2D([ltwh[0] + sX + sX + pad * 2, ltwh[1], sY, sZ], 2, NaN, [actualY, actualZ]);
|
|
32801
33184
|
if (isDraw3D) {
|
|
32802
|
-
|
|
33185
|
+
const sMx = mx * ltwh[4];
|
|
33186
|
+
this.draw3D([ltwh[0] + sX + sX + sY + pad * 3, ltwh[1], sMx, sMx]);
|
|
32803
33187
|
}
|
|
32804
33188
|
} else if (isDrawGrid) {
|
|
32805
33189
|
if (!isShowRender) {
|
|
@@ -32808,13 +33192,9 @@ var Niivue = class _Niivue {
|
|
|
32808
33192
|
if (this.opts.multiplanarShowRender === 2 /* AUTO */) {
|
|
32809
33193
|
isDraw3D = true;
|
|
32810
33194
|
}
|
|
32811
|
-
|
|
32812
|
-
|
|
32813
|
-
|
|
32814
|
-
const sZ = volScale[2] * ltwh[4];
|
|
32815
|
-
this.draw2D([ltwh[0], ltwh[1] + sZ + pad, sX, sY], 0);
|
|
32816
|
-
this.draw2D([ltwh[0], ltwh[1], sX, sZ], 1);
|
|
32817
|
-
this.draw2D([ltwh[0] + sX + pad, ltwh[1], sY, sZ], 2);
|
|
33195
|
+
this.draw2D([ltwh[0], ltwh[1] + sZ + pad, sX, sY], 0, NaN, [actualX, actualY]);
|
|
33196
|
+
this.draw2D([ltwh[0], ltwh[1], sX, sZ], 1, NaN, [actualX, actualZ]);
|
|
33197
|
+
this.draw2D([ltwh[0] + sX + pad, ltwh[1], sY, sZ], 2, NaN, [actualY, actualZ]);
|
|
32818
33198
|
if (isDraw3D) {
|
|
32819
33199
|
this.draw3D([ltwh[0] + sX + pad, ltwh[1] + sZ + pad, sY, sY]);
|
|
32820
33200
|
}
|
|
@@ -32879,10 +33259,25 @@ var Niivue = class _Niivue {
|
|
|
32879
33259
|
height
|
|
32880
33260
|
]);
|
|
32881
33261
|
}
|
|
33262
|
+
if (this.opts.clickToSegment) {
|
|
33263
|
+
const x = this.mousePos[0];
|
|
33264
|
+
const y = this.mousePos[1];
|
|
33265
|
+
const tileIdx = this.tileIndex(x, y);
|
|
33266
|
+
if (tileIdx > -1) {
|
|
33267
|
+
const fovMM = this.screenSlices[tileIdx].fovMM;
|
|
33268
|
+
const ltwh = this.screenSlices[tileIdx].leftTopWidthHeight;
|
|
33269
|
+
const pixPerMM = ltwh[2] / fovMM[0];
|
|
33270
|
+
const color = this.opts.crosshairColor;
|
|
33271
|
+
const segmentCursorColor = [color[0], color[1], color[2], 0.4];
|
|
33272
|
+
const radius = this.opts.clickToSegmentRadius * pixPerMM;
|
|
33273
|
+
this.drawCircle([x - radius, y - radius, radius * 2, radius * 2], segmentCursorColor, 1);
|
|
33274
|
+
}
|
|
33275
|
+
}
|
|
32882
33276
|
const pos = this.frac2mm([this.scene.crosshairPos[0], this.scene.crosshairPos[1], this.scene.crosshairPos[2]]);
|
|
32883
33277
|
posString = pos[0].toFixed(2) + "\xD7" + pos[1].toFixed(2) + "\xD7" + pos[2].toFixed(2);
|
|
32884
33278
|
this.readyForSync = true;
|
|
32885
33279
|
this.sync();
|
|
33280
|
+
this.drawAnchoredLabels();
|
|
32886
33281
|
return posString;
|
|
32887
33282
|
}
|
|
32888
33283
|
// not included in public docs
|
|
@@ -32917,6 +33312,7 @@ export {
|
|
|
32917
33312
|
DEFAULT_OPTIONS,
|
|
32918
33313
|
DRAG_MODE,
|
|
32919
33314
|
INITIAL_SCENE_DATA,
|
|
33315
|
+
LabelAnchorPoint,
|
|
32920
33316
|
LabelLineTerminator,
|
|
32921
33317
|
LabelTextAlignment,
|
|
32922
33318
|
MULTIPLANAR_TYPE,
|