larvitar 2.1.8 → 2.1.10
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 +2 -2
- package/dist/imaging/imageStore.d.ts +1 -1
- package/dist/imaging/tools/custom/LengthPlotTool.d.ts +119 -0
- package/dist/imaging/tools/custom/ManualLengthPlotTool.d.ts +131 -0
- package/dist/larvitar.js +673 -3
- package/dist/larvitar.js.map +1 -1
- package/imaging/tools/types.d.ts +3 -2
- package/imaging/types.d.ts +1 -0
- package/package.json +1 -1
package/dist/larvitar.js
CHANGED
|
@@ -158687,6 +158687,7 @@ const storeViewportData = function (image, elementId, viewport, data) {
|
|
|
158687
158687
|
(0, imageStore_1.set)(["isTimeserie", elementId, data.isTimeserie]);
|
|
158688
158688
|
(0, imageStore_1.set)(["isPDF", elementId, false]);
|
|
158689
158689
|
(0, imageStore_1.set)(["waveform", elementId, data.waveform]);
|
|
158690
|
+
(0, imageStore_1.set)(["dsa", elementId, data.dsa]);
|
|
158690
158691
|
};
|
|
158691
158692
|
exports.storeViewportData = storeViewportData;
|
|
158692
158693
|
/**
|
|
@@ -158856,6 +158857,7 @@ const getSeriesData = function (series, defaultProps) {
|
|
|
158856
158857
|
data.isColor = series.color;
|
|
158857
158858
|
data.isPDF = series.isPDF;
|
|
158858
158859
|
data.waveform = series.waveform;
|
|
158860
|
+
data.dsa = series.dsa ? true : false;
|
|
158859
158861
|
if (instance) {
|
|
158860
158862
|
data.rows = instance.metadata.x00280010;
|
|
158861
158863
|
data.cols = instance.metadata.x00280011;
|
|
@@ -159028,6 +159030,7 @@ const DEFAULT_VIEWPORT = {
|
|
|
159028
159030
|
isDSAEnabled: false,
|
|
159029
159031
|
isPDF: false,
|
|
159030
159032
|
waveform: false,
|
|
159033
|
+
dsa: false,
|
|
159031
159034
|
viewport: {
|
|
159032
159035
|
scale: 0.0,
|
|
159033
159036
|
rotation: 0.0,
|
|
@@ -159102,6 +159105,7 @@ const setValue = (store, data) => {
|
|
|
159102
159105
|
case "isMultiframe":
|
|
159103
159106
|
case "isPDF":
|
|
159104
159107
|
case "waveform":
|
|
159108
|
+
case "dsa":
|
|
159105
159109
|
case "isTimeserie":
|
|
159106
159110
|
case "isDSAEnabled":
|
|
159107
159111
|
case "ready":
|
|
@@ -163226,6 +163230,633 @@ function revTidMask(metadataInfo, imageIds, index) {
|
|
|
163226
163230
|
}
|
|
163227
163231
|
|
|
163228
163232
|
|
|
163233
|
+
/***/ }),
|
|
163234
|
+
|
|
163235
|
+
/***/ 2775:
|
|
163236
|
+
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
163237
|
+
|
|
163238
|
+
"use strict";
|
|
163239
|
+
|
|
163240
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
163241
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
163242
|
+
};
|
|
163243
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
163244
|
+
//external imports
|
|
163245
|
+
const plotly_js_dist_min_1 = __importDefault(__webpack_require__(2479));
|
|
163246
|
+
const cornerstone_core_1 = __importDefault(__webpack_require__(7371));
|
|
163247
|
+
const cornerstone_tools_1 = __importDefault(__webpack_require__(4030));
|
|
163248
|
+
const getToolState = cornerstone_tools_1.default.getToolState;
|
|
163249
|
+
const toolColors = cornerstone_tools_1.default.toolColors;
|
|
163250
|
+
const draw = cornerstone_tools_1.default.importInternal("drawing/draw");
|
|
163251
|
+
const drawLine = cornerstone_tools_1.default.importInternal("drawing/drawLine");
|
|
163252
|
+
const setShadow = cornerstone_tools_1.default.importInternal("drawing/setShadow");
|
|
163253
|
+
const getNewContext = cornerstone_tools_1.default.importInternal("drawing/getNewContext");
|
|
163254
|
+
const drawHandles = cornerstone_tools_1.default.importInternal("drawing/drawHandles");
|
|
163255
|
+
const { lengthCursor } = cornerstone_tools_1.default.importInternal("tools/cursors");
|
|
163256
|
+
const throttle = cornerstone_tools_1.default.importInternal("util/throttle");
|
|
163257
|
+
const getModule = cornerstone_tools_1.default.getModule;
|
|
163258
|
+
const getPixelSpacing = cornerstone_tools_1.default.importInternal("util/getPixelSpacing");
|
|
163259
|
+
const lineSegDistance = cornerstone_tools_1.default.importInternal("util/lineSegDistance");
|
|
163260
|
+
const BaseAnnotationTool = cornerstone_tools_1.default.importInternal("base/BaseAnnotationTool");
|
|
163261
|
+
const default_1 = __webpack_require__(6694);
|
|
163262
|
+
// import cornerstoneTools from "cornerstone-tools";
|
|
163263
|
+
class LengthPlotTool extends BaseAnnotationTool {
|
|
163264
|
+
constructor(props = {}) {
|
|
163265
|
+
const defaultProps = {
|
|
163266
|
+
name: "LengthPlot",
|
|
163267
|
+
supportedInteractionTypes: ["Mouse"],
|
|
163268
|
+
svgCursor: lengthCursor,
|
|
163269
|
+
configuration: {
|
|
163270
|
+
drawHandles: true,
|
|
163271
|
+
drawHandlesOnHover: false,
|
|
163272
|
+
hideHandlesIfMoving: false,
|
|
163273
|
+
renderDashed: false,
|
|
163274
|
+
digits: 2,
|
|
163275
|
+
offset: 15
|
|
163276
|
+
}
|
|
163277
|
+
};
|
|
163278
|
+
super(props, defaultProps);
|
|
163279
|
+
this.name = "LengthPlot";
|
|
163280
|
+
this.plotlydata = [];
|
|
163281
|
+
this.measuring = false;
|
|
163282
|
+
this.configuration = {
|
|
163283
|
+
drawHandles: true,
|
|
163284
|
+
drawHandlesOnHover: false,
|
|
163285
|
+
hideHandlesIfMoving: false,
|
|
163286
|
+
renderDashed: false,
|
|
163287
|
+
digits: 2,
|
|
163288
|
+
offset: 15
|
|
163289
|
+
};
|
|
163290
|
+
this.eventData;
|
|
163291
|
+
this.datahandles;
|
|
163292
|
+
this.abovehandles;
|
|
163293
|
+
this.belowhandles;
|
|
163294
|
+
this.plotlydata = [];
|
|
163295
|
+
this.measuring = false;
|
|
163296
|
+
this.handleMouseUp = this.handleMouseUp.bind(this);
|
|
163297
|
+
this.throttledUpdateCachedStats = throttle(this.updateCachedStats, 110);
|
|
163298
|
+
}
|
|
163299
|
+
getRandomColor() {
|
|
163300
|
+
const letters = "0123456789ABCDEF";
|
|
163301
|
+
let color = "#";
|
|
163302
|
+
for (let i = 0; i < 6; i++) {
|
|
163303
|
+
color += letters[Math.floor(Math.random() * 16)];
|
|
163304
|
+
}
|
|
163305
|
+
return color;
|
|
163306
|
+
}
|
|
163307
|
+
handleMouseUp() {
|
|
163308
|
+
this.measuring = false;
|
|
163309
|
+
const eventData = this.eventData;
|
|
163310
|
+
const handleData = (handles) => {
|
|
163311
|
+
const points = this.getPointsAlongLine(handles.start, handles.end, getPixelSpacing(eventData.image).colPixelSpacing);
|
|
163312
|
+
const pixelValues = this.getPixelValuesAlongLine(handles.start, points, getPixelSpacing(eventData.image).colPixelSpacing, eventData);
|
|
163313
|
+
let color = "green";
|
|
163314
|
+
return { points, pixelValues, color };
|
|
163315
|
+
};
|
|
163316
|
+
const aboveResults = handleData(this.abovehandles);
|
|
163317
|
+
aboveResults.color = "red";
|
|
163318
|
+
const belowResults = handleData(this.belowhandles);
|
|
163319
|
+
belowResults.color = "blue";
|
|
163320
|
+
const data = [handleData(this.datahandles), aboveResults, belowResults];
|
|
163321
|
+
this.createPlot(...data);
|
|
163322
|
+
}
|
|
163323
|
+
createNewMeasurement(eventData) {
|
|
163324
|
+
this.eventData = eventData;
|
|
163325
|
+
clearToolData(eventData.element, this.name);
|
|
163326
|
+
eventData.element.addEventListener("mouseup", () => this.handleMouseUp());
|
|
163327
|
+
this.measuring = true;
|
|
163328
|
+
const goodEventData = eventData && eventData.currentPoints && eventData.currentPoints.image;
|
|
163329
|
+
if (!goodEventData) {
|
|
163330
|
+
console.error(`required eventData not supplied to tool ${this.name}'s createNewMeasurement`);
|
|
163331
|
+
return;
|
|
163332
|
+
}
|
|
163333
|
+
let color = "green";
|
|
163334
|
+
const { x, y } = eventData.currentPoints.image;
|
|
163335
|
+
return {
|
|
163336
|
+
visible: true,
|
|
163337
|
+
active: true,
|
|
163338
|
+
color: color,
|
|
163339
|
+
invalidated: true,
|
|
163340
|
+
handles: {
|
|
163341
|
+
start: {
|
|
163342
|
+
x,
|
|
163343
|
+
y,
|
|
163344
|
+
highlight: true,
|
|
163345
|
+
active: false
|
|
163346
|
+
},
|
|
163347
|
+
end: {
|
|
163348
|
+
x,
|
|
163349
|
+
y,
|
|
163350
|
+
highlight: true,
|
|
163351
|
+
active: true
|
|
163352
|
+
},
|
|
163353
|
+
textBox: {
|
|
163354
|
+
active: false,
|
|
163355
|
+
hasMoved: false,
|
|
163356
|
+
movesIndependently: false,
|
|
163357
|
+
drawnIndependently: true,
|
|
163358
|
+
allowedOutsideImage: true,
|
|
163359
|
+
hasBoundingBox: true
|
|
163360
|
+
}
|
|
163361
|
+
}
|
|
163362
|
+
};
|
|
163363
|
+
}
|
|
163364
|
+
pointNearTool(element, data, coords) {
|
|
163365
|
+
const hasStartAndEndHandles = data && data.handles && data.handles.start && data.handles.end;
|
|
163366
|
+
const validParameters = hasStartAndEndHandles;
|
|
163367
|
+
if (!validParameters) {
|
|
163368
|
+
console.warn(`invalid parameters supplied to tool ${this.name}'s pointNearTool`);
|
|
163369
|
+
return false;
|
|
163370
|
+
}
|
|
163371
|
+
if (data.visible === false) {
|
|
163372
|
+
return false;
|
|
163373
|
+
}
|
|
163374
|
+
return (lineSegDistance(element, data.handles.start, data.handles.end, coords) <
|
|
163375
|
+
25);
|
|
163376
|
+
}
|
|
163377
|
+
updateCachedStats(image, element, data) {
|
|
163378
|
+
const { rowPixelSpacing, colPixelSpacing } = getPixelSpacing(image);
|
|
163379
|
+
const dx = (data.handles.end.x - data.handles.start.x) * (colPixelSpacing || 1);
|
|
163380
|
+
const dy = (data.handles.end.y - data.handles.start.y) * (rowPixelSpacing || 1);
|
|
163381
|
+
const length = Math.sqrt(dx * dx + dy * dy);
|
|
163382
|
+
data.length = length;
|
|
163383
|
+
data.invalidated = false;
|
|
163384
|
+
}
|
|
163385
|
+
renderToolData(evt) {
|
|
163386
|
+
const eventData = evt.detail;
|
|
163387
|
+
const { element } = eventData;
|
|
163388
|
+
const { handleRadius, drawHandlesOnHover, hideHandlesIfMoving, renderDashed } = this.configuration;
|
|
163389
|
+
const toolData = getToolState(evt.currentTarget, this.name);
|
|
163390
|
+
if (!toolData) {
|
|
163391
|
+
return;
|
|
163392
|
+
}
|
|
163393
|
+
const context = getNewContext(eventData.canvasContext.canvas);
|
|
163394
|
+
const lineDash = getModule("globalConfiguration").configuration
|
|
163395
|
+
.lineDash;
|
|
163396
|
+
let start;
|
|
163397
|
+
let end;
|
|
163398
|
+
for (let i = 0; i < toolData.data.length; i++) {
|
|
163399
|
+
const data = toolData.data[i];
|
|
163400
|
+
if (data.visible === false) {
|
|
163401
|
+
continue;
|
|
163402
|
+
}
|
|
163403
|
+
draw(context, (context) => {
|
|
163404
|
+
setShadow(context, this.configuration);
|
|
163405
|
+
const color = toolColors.getColorIfActive(data);
|
|
163406
|
+
const lineOptions = { color };
|
|
163407
|
+
if (renderDashed) {
|
|
163408
|
+
lineOptions.lineDash = lineDash;
|
|
163409
|
+
}
|
|
163410
|
+
start = data.handles.start;
|
|
163411
|
+
end = data.handles.end;
|
|
163412
|
+
data.handles.end.y = data.handles.start.y;
|
|
163413
|
+
drawLine(context, element, data.handles.start, data.handles.end, lineOptions);
|
|
163414
|
+
const offset = default_1.DEFAULT_TOOLS["LengthPlot"].offset === this.configuration.offset ||
|
|
163415
|
+
default_1.DEFAULT_TOOLS["LengthPlot"].offset === undefined
|
|
163416
|
+
? this.configuration.offset
|
|
163417
|
+
: default_1.DEFAULT_TOOLS["LengthPlot"].offset; //offset customisable
|
|
163418
|
+
//const offset = this.configuration.offset;
|
|
163419
|
+
const aboveHandles = {
|
|
163420
|
+
start: { x: start.x, y: start.y - offset },
|
|
163421
|
+
end: { x: end.x, y: end.y - offset }
|
|
163422
|
+
};
|
|
163423
|
+
const belowHandles = {
|
|
163424
|
+
start: { x: start.x, y: start.y + offset },
|
|
163425
|
+
end: { x: end.x, y: end.y + offset }
|
|
163426
|
+
};
|
|
163427
|
+
const abovelineOptions = { color: "red" };
|
|
163428
|
+
const belowlineOptions = { color: "blue" };
|
|
163429
|
+
drawLine(context, element, aboveHandles.start, aboveHandles.end, abovelineOptions);
|
|
163430
|
+
drawLine(context, element, belowHandles.start, belowHandles.end, belowlineOptions);
|
|
163431
|
+
const handleOptions = {
|
|
163432
|
+
color,
|
|
163433
|
+
handleRadius,
|
|
163434
|
+
drawHandlesIfActive: drawHandlesOnHover,
|
|
163435
|
+
hideHandlesIfMoving
|
|
163436
|
+
};
|
|
163437
|
+
const abovehandleOptions = {
|
|
163438
|
+
color: abovelineOptions.color,
|
|
163439
|
+
handleRadius,
|
|
163440
|
+
drawHandlesIfActive: drawHandlesOnHover,
|
|
163441
|
+
hideHandlesIfMoving
|
|
163442
|
+
};
|
|
163443
|
+
const belowhandleOptions = {
|
|
163444
|
+
color: belowlineOptions.color,
|
|
163445
|
+
handleRadius,
|
|
163446
|
+
drawHandlesIfActive: drawHandlesOnHover,
|
|
163447
|
+
hideHandlesIfMoving
|
|
163448
|
+
};
|
|
163449
|
+
if (this.configuration.drawHandles) {
|
|
163450
|
+
drawHandles(context, eventData, data.handles, handleOptions);
|
|
163451
|
+
this.datahandles = data.handles;
|
|
163452
|
+
this.abovehandles = aboveHandles;
|
|
163453
|
+
this.belowhandles = belowHandles;
|
|
163454
|
+
drawHandles(context, eventData, aboveHandles, abovehandleOptions);
|
|
163455
|
+
drawHandles(context, eventData, belowHandles, belowhandleOptions);
|
|
163456
|
+
}
|
|
163457
|
+
});
|
|
163458
|
+
}
|
|
163459
|
+
}
|
|
163460
|
+
getPointsAlongLine(startHandle, endHandle, colPixelSpacing) {
|
|
163461
|
+
let points = [];
|
|
163462
|
+
const addPoints = (start, end, step) => {
|
|
163463
|
+
const startX = Math.floor(start.x) + 1;
|
|
163464
|
+
const numPoints = Math.floor(end.x) - startX;
|
|
163465
|
+
points = new Array(numPoints + 1);
|
|
163466
|
+
for (let i = 0; i <= numPoints; i++) {
|
|
163467
|
+
points[i] = (startX + i) * step;
|
|
163468
|
+
}
|
|
163469
|
+
};
|
|
163470
|
+
if (endHandle.x > startHandle.x) {
|
|
163471
|
+
addPoints(startHandle, endHandle, colPixelSpacing);
|
|
163472
|
+
}
|
|
163473
|
+
if (endHandle.x < startHandle.x) {
|
|
163474
|
+
addPoints(endHandle, startHandle, colPixelSpacing);
|
|
163475
|
+
}
|
|
163476
|
+
return points;
|
|
163477
|
+
}
|
|
163478
|
+
getPixelValuesAlongLine(startHandle, points, colPixelSpacing, eventData) {
|
|
163479
|
+
const pixelValues = new Array(points.length);
|
|
163480
|
+
const yPoint = Math.floor(startHandle.y);
|
|
163481
|
+
const addPixelValues = (xPoints, startIndex) => {
|
|
163482
|
+
const pixelValuesBatch = cornerstone_core_1.default.getStoredPixels(eventData.element, xPoints[0], yPoint, xPoints.length, 1);
|
|
163483
|
+
for (let i = 0; i < pixelValuesBatch.length; i++) {
|
|
163484
|
+
pixelValues[startIndex + i] = pixelValuesBatch[i];
|
|
163485
|
+
}
|
|
163486
|
+
};
|
|
163487
|
+
for (let i = 0; i < points.length; i++) {
|
|
163488
|
+
const xPoint = Math.floor(points[i] / colPixelSpacing);
|
|
163489
|
+
addPixelValues([xPoint], i);
|
|
163490
|
+
}
|
|
163491
|
+
return pixelValues;
|
|
163492
|
+
}
|
|
163493
|
+
createPlot(...dataSets) {
|
|
163494
|
+
const traces = dataSets.map(({ points, pixelValues, color }) => ({
|
|
163495
|
+
x: points,
|
|
163496
|
+
y: pixelValues,
|
|
163497
|
+
type: "lines",
|
|
163498
|
+
line: {
|
|
163499
|
+
color
|
|
163500
|
+
}
|
|
163501
|
+
}));
|
|
163502
|
+
this.plotlydata = traces;
|
|
163503
|
+
const allXValues = dataSets.flatMap(dataSet => dataSet.points);
|
|
163504
|
+
const allYValues = dataSets.flatMap(dataSet => dataSet.pixelValues);
|
|
163505
|
+
const layout = {
|
|
163506
|
+
xaxis: {
|
|
163507
|
+
range: [Math.min(...allXValues), Math.max(...allXValues)],
|
|
163508
|
+
title: "position (mm)"
|
|
163509
|
+
},
|
|
163510
|
+
yaxis: {
|
|
163511
|
+
range: [Math.min(...allYValues), Math.max(...allYValues)],
|
|
163512
|
+
title: "GreyScaleValue (HU)"
|
|
163513
|
+
},
|
|
163514
|
+
title: "GreyScaleValues vs position",
|
|
163515
|
+
responsive: true
|
|
163516
|
+
};
|
|
163517
|
+
const myPlotDiv = document.getElementById("myPlot");
|
|
163518
|
+
plotly_js_dist_min_1.default.react(myPlotDiv, traces, layout);
|
|
163519
|
+
}
|
|
163520
|
+
clearPlotlyData() {
|
|
163521
|
+
const myPlotDiv = document.getElementById("myPlot");
|
|
163522
|
+
plotly_js_dist_min_1.default.purge(myPlotDiv);
|
|
163523
|
+
this.plotlydata = [];
|
|
163524
|
+
}
|
|
163525
|
+
}
|
|
163526
|
+
exports["default"] = LengthPlotTool;
|
|
163527
|
+
function clearToolData(element, toolName) {
|
|
163528
|
+
const toolData = getToolState(element, toolName);
|
|
163529
|
+
if (toolData && toolData.data && toolData.data.length > 0) {
|
|
163530
|
+
toolData.data.forEach((data) => {
|
|
163531
|
+
data.visible = false;
|
|
163532
|
+
});
|
|
163533
|
+
}
|
|
163534
|
+
}
|
|
163535
|
+
//to set custom offset do this: DEFAULT_TOOLS["LengthPlot"].offset=parseInt(document.getElementById("offset").value,10)
|
|
163536
|
+
//create plot in viewport in layeout doable like this:
|
|
163537
|
+
//const currentDiv = eventData.element //viewport element
|
|
163538
|
+
//const newDiv = document.createElement("div");
|
|
163539
|
+
//newDiv.id=currentDiv.id+"-Plotly"
|
|
163540
|
+
//newDiv.style="width: 100%; max-width: 600px; height: 500px;"
|
|
163541
|
+
//currentDiv.appendChild(newDiv);
|
|
163542
|
+
//offsetInput=document.createElement("input");
|
|
163543
|
+
// Set the attributes for the input element
|
|
163544
|
+
//offsetInput.type = "number";
|
|
163545
|
+
//offsetInput.classList.add("manualInput");
|
|
163546
|
+
//offsetInput.id = currentDiv.id+"-offset";
|
|
163547
|
+
//offsetInput.placeholder = "offset";
|
|
163548
|
+
//newDiv.appendChild(offsetInput);
|
|
163549
|
+
|
|
163550
|
+
|
|
163551
|
+
/***/ }),
|
|
163552
|
+
|
|
163553
|
+
/***/ 893:
|
|
163554
|
+
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
163555
|
+
|
|
163556
|
+
"use strict";
|
|
163557
|
+
|
|
163558
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
163559
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
163560
|
+
};
|
|
163561
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
163562
|
+
//external imports
|
|
163563
|
+
const plotly_js_dist_min_1 = __importDefault(__webpack_require__(2479));
|
|
163564
|
+
const cornerstone_core_1 = __importDefault(__webpack_require__(7371));
|
|
163565
|
+
const cornerstone_tools_1 = __importDefault(__webpack_require__(4030));
|
|
163566
|
+
const getToolState = cornerstone_tools_1.default.getToolState; //check
|
|
163567
|
+
const toolColors = cornerstone_tools_1.default.toolColors;
|
|
163568
|
+
const draw = cornerstone_tools_1.default.importInternal("drawing/draw");
|
|
163569
|
+
const drawLine = cornerstone_tools_1.default.importInternal("drawing/drawLine");
|
|
163570
|
+
const setShadow = cornerstone_tools_1.default.importInternal("drawing/setShadow");
|
|
163571
|
+
const getNewContext = cornerstone_tools_1.default.importInternal("drawing/getNewContext");
|
|
163572
|
+
const drawHandles = cornerstone_tools_1.default.importInternal("drawing/drawHandles");
|
|
163573
|
+
const { lengthCursor } = cornerstone_tools_1.default.importInternal("tools/cursors");
|
|
163574
|
+
const throttle = cornerstone_tools_1.default.importInternal("util/throttle");
|
|
163575
|
+
const getModule = cornerstone_tools_1.default.getModule;
|
|
163576
|
+
const getPixelSpacing = cornerstone_tools_1.default.importInternal("util/getPixelSpacing");
|
|
163577
|
+
const lineSegDistance = cornerstone_tools_1.default.importInternal("util/lineSegDistance");
|
|
163578
|
+
const BaseAnnotationTool = cornerstone_tools_1.default.importInternal("base/BaseAnnotationTool");
|
|
163579
|
+
/**
|
|
163580
|
+
* @public
|
|
163581
|
+
* @class LengthTool
|
|
163582
|
+
* @memberof Tools.Annotation
|
|
163583
|
+
* @classdesc Tool for measuring distances.
|
|
163584
|
+
* @extends Tools.Base.BaseAnnotationTool
|
|
163585
|
+
*/
|
|
163586
|
+
class ManualLengthPlotTool extends BaseAnnotationTool {
|
|
163587
|
+
constructor(props = {}) {
|
|
163588
|
+
const defaultProps = {
|
|
163589
|
+
name: "HorizontalTool",
|
|
163590
|
+
supportedInteractionTypes: ["Mouse"],
|
|
163591
|
+
svgCursor: lengthCursor,
|
|
163592
|
+
configuration: {
|
|
163593
|
+
drawHandles: true,
|
|
163594
|
+
drawHandlesOnHover: false,
|
|
163595
|
+
hideHandlesIfMoving: false,
|
|
163596
|
+
renderDashed: false,
|
|
163597
|
+
digits: 2
|
|
163598
|
+
}
|
|
163599
|
+
};
|
|
163600
|
+
super(props, defaultProps);
|
|
163601
|
+
this.name = "ManualLengthPlot";
|
|
163602
|
+
this.plotlydata = [];
|
|
163603
|
+
this.measuring = false;
|
|
163604
|
+
this.lineNumber = null;
|
|
163605
|
+
this.greenlineY = null;
|
|
163606
|
+
this.newMeasurement = false;
|
|
163607
|
+
this.configuration = {
|
|
163608
|
+
drawHandles: true,
|
|
163609
|
+
drawHandlesOnHover: false,
|
|
163610
|
+
hideHandlesIfMoving: false,
|
|
163611
|
+
renderDashed: false,
|
|
163612
|
+
digits: 2
|
|
163613
|
+
};
|
|
163614
|
+
this.handleMouseUp = () => {
|
|
163615
|
+
const eventData = this.eventData;
|
|
163616
|
+
const { element } = eventData;
|
|
163617
|
+
//const toolData: ToolData = getToolState(element, this.name);
|
|
163618
|
+
const points = this.getPointsAlongLine(this.datahandles.start, this.datahandles.end, getPixelSpacing(eventData.image).colPixelSpacing);
|
|
163619
|
+
const pixelValues = this.getPixelValuesAlongLine(this.datahandles.start, points, getPixelSpacing(eventData.image).colPixelSpacing, eventData);
|
|
163620
|
+
// Plot the graph using the extracted points and pixel values
|
|
163621
|
+
this.createPlot(points, pixelValues);
|
|
163622
|
+
};
|
|
163623
|
+
this.handleMouseUp = this.handleMouseUp.bind(this);
|
|
163624
|
+
// Add event listeners to start and stop measurements
|
|
163625
|
+
this.throttledUpdateCachedStats = throttle(this.updateCachedStats, 110);
|
|
163626
|
+
}
|
|
163627
|
+
getColor(y) {
|
|
163628
|
+
let color = "red";
|
|
163629
|
+
if (this.lineNumber === null || this.lineNumber === 3) {
|
|
163630
|
+
color = "green";
|
|
163631
|
+
this.greenlineY = y;
|
|
163632
|
+
this.lineNumber = 1;
|
|
163633
|
+
}
|
|
163634
|
+
else if (y > this.greenlineY) {
|
|
163635
|
+
color = this.color === "blue" ? "red" : "blue";
|
|
163636
|
+
this.lineNumber = this.lineNumber + 1;
|
|
163637
|
+
}
|
|
163638
|
+
else if (y < this.greenlineY) {
|
|
163639
|
+
color = this.color === "red" ? "blue" : "red";
|
|
163640
|
+
this.lineNumber = this.lineNumber + 1;
|
|
163641
|
+
}
|
|
163642
|
+
return color;
|
|
163643
|
+
}
|
|
163644
|
+
clearCanvasAndPlot(eventData) {
|
|
163645
|
+
// Clear the canvas
|
|
163646
|
+
const { element } = eventData;
|
|
163647
|
+
const toolData = getToolState(element, this.name);
|
|
163648
|
+
if (toolData && toolData.data && toolData.data.length > 0) {
|
|
163649
|
+
toolData.data.forEach((data) => {
|
|
163650
|
+
data.visible = false;
|
|
163651
|
+
});
|
|
163652
|
+
}
|
|
163653
|
+
// Clear the Plotly plot
|
|
163654
|
+
const myPlotDiv = document.getElementById("myPlot");
|
|
163655
|
+
plotly_js_dist_min_1.default.purge(myPlotDiv);
|
|
163656
|
+
this.plotlydata = [];
|
|
163657
|
+
}
|
|
163658
|
+
createNewMeasurement(eventData) {
|
|
163659
|
+
this.newMeasurement = true;
|
|
163660
|
+
if (this.lineNumber === 3) {
|
|
163661
|
+
this.clearCanvasAndPlot(eventData);
|
|
163662
|
+
}
|
|
163663
|
+
eventData.element.addEventListener("mouseup", () => this.handleMouseUp());
|
|
163664
|
+
this.eventData = eventData;
|
|
163665
|
+
const goodEventData = eventData && eventData.currentPoints && eventData.currentPoints.image;
|
|
163666
|
+
if (!goodEventData) {
|
|
163667
|
+
console.error(`required eventData not supplied to tool ${this.name}'s createNewMeasurement`);
|
|
163668
|
+
return;
|
|
163669
|
+
}
|
|
163670
|
+
const { x, y } = eventData.currentPoints.image;
|
|
163671
|
+
let color = this.getColor(y);
|
|
163672
|
+
this.color = color;
|
|
163673
|
+
return {
|
|
163674
|
+
visible: true,
|
|
163675
|
+
active: true,
|
|
163676
|
+
color: color,
|
|
163677
|
+
invalidated: true,
|
|
163678
|
+
handles: {
|
|
163679
|
+
start: {
|
|
163680
|
+
x,
|
|
163681
|
+
y,
|
|
163682
|
+
highlight: true,
|
|
163683
|
+
active: false
|
|
163684
|
+
},
|
|
163685
|
+
end: {
|
|
163686
|
+
x,
|
|
163687
|
+
y,
|
|
163688
|
+
highlight: true,
|
|
163689
|
+
active: true
|
|
163690
|
+
},
|
|
163691
|
+
textBox: {
|
|
163692
|
+
active: false,
|
|
163693
|
+
hasMoved: false,
|
|
163694
|
+
movesIndependently: false,
|
|
163695
|
+
drawnIndependently: true,
|
|
163696
|
+
allowedOutsideImage: true,
|
|
163697
|
+
hasBoundingBox: true
|
|
163698
|
+
}
|
|
163699
|
+
}
|
|
163700
|
+
};
|
|
163701
|
+
}
|
|
163702
|
+
/**
|
|
163703
|
+
*
|
|
163704
|
+
*
|
|
163705
|
+
* @param {*} element
|
|
163706
|
+
* @param {*} data
|
|
163707
|
+
* @param {*} coords
|
|
163708
|
+
* @returns {Boolean}
|
|
163709
|
+
*/
|
|
163710
|
+
pointNearTool(element, data, coords) {
|
|
163711
|
+
const hasStartAndEndHandles = data && data.handles && data.handles.start && data.handles.end;
|
|
163712
|
+
const validParameters = hasStartAndEndHandles;
|
|
163713
|
+
if (!validParameters) {
|
|
163714
|
+
console.warn(`invalid parameters supplied to tool ${this.name}'s pointNearTool`);
|
|
163715
|
+
return false;
|
|
163716
|
+
}
|
|
163717
|
+
if (data.visible === false) {
|
|
163718
|
+
return false;
|
|
163719
|
+
}
|
|
163720
|
+
return (lineSegDistance(element, data.handles.start, data.handles.end, coords) <
|
|
163721
|
+
25);
|
|
163722
|
+
}
|
|
163723
|
+
updateCachedStats(image, element, data) {
|
|
163724
|
+
const { rowPixelSpacing, colPixelSpacing } = getPixelSpacing(image);
|
|
163725
|
+
// Set rowPixelSpacing and columnPixelSpacing to 1 if they are undefined (or zero)
|
|
163726
|
+
const dx = (data.handles.end.x - data.handles.start.x) * (colPixelSpacing || 1);
|
|
163727
|
+
const dy = (data.handles.end.y - data.handles.start.y) * (rowPixelSpacing || 1);
|
|
163728
|
+
// Calculate the length, and create the text variable with the millimeters or pixels suffix
|
|
163729
|
+
const length = Math.sqrt(dx * dx + dy * dy);
|
|
163730
|
+
// Store the length inside the tool for outside access
|
|
163731
|
+
data.length = length;
|
|
163732
|
+
data.invalidated = false;
|
|
163733
|
+
}
|
|
163734
|
+
renderToolData(evt) {
|
|
163735
|
+
const eventData = evt.detail;
|
|
163736
|
+
const { image, element } = eventData;
|
|
163737
|
+
const { handleRadius, drawHandlesOnHover, hideHandlesIfMoving, renderDashed } = this.configuration;
|
|
163738
|
+
const toolData = getToolState(evt.currentTarget, this.name);
|
|
163739
|
+
if (!toolData) {
|
|
163740
|
+
return;
|
|
163741
|
+
}
|
|
163742
|
+
// We have tool data for this element - iterate over each one and draw it
|
|
163743
|
+
const context = getNewContext(eventData.canvasContext.canvas);
|
|
163744
|
+
const lineDash = getModule("globalConfiguration").configuration
|
|
163745
|
+
.lineDash;
|
|
163746
|
+
let start;
|
|
163747
|
+
let end;
|
|
163748
|
+
for (let i = 0; i < toolData.data.length; i++) {
|
|
163749
|
+
const data = toolData.data[i];
|
|
163750
|
+
if (data.visible === false) {
|
|
163751
|
+
continue;
|
|
163752
|
+
}
|
|
163753
|
+
draw(context, (context) => {
|
|
163754
|
+
// Configurable shadow
|
|
163755
|
+
setShadow(context, this.configuration);
|
|
163756
|
+
const color = toolColors.getColorIfActive(data);
|
|
163757
|
+
if (data.active) {
|
|
163758
|
+
this.color = color;
|
|
163759
|
+
this.datahandles = data.handles;
|
|
163760
|
+
}
|
|
163761
|
+
const lineOptions = { color };
|
|
163762
|
+
if (renderDashed) {
|
|
163763
|
+
lineOptions.lineDash = lineDash;
|
|
163764
|
+
}
|
|
163765
|
+
start = data.handles.start;
|
|
163766
|
+
end = data.handles.end;
|
|
163767
|
+
data.handles.end.y = data.handles.start.y;
|
|
163768
|
+
// Draw the measurement line
|
|
163769
|
+
drawLine(context, element, data.handles.start, data.handles.end, lineOptions);
|
|
163770
|
+
// Draw the handles
|
|
163771
|
+
const handleOptions = {
|
|
163772
|
+
color,
|
|
163773
|
+
handleRadius,
|
|
163774
|
+
drawHandlesIfActive: drawHandlesOnHover,
|
|
163775
|
+
hideHandlesIfMoving
|
|
163776
|
+
};
|
|
163777
|
+
if (this.configuration.drawHandles) {
|
|
163778
|
+
drawHandles(context, eventData, data.handles, handleOptions);
|
|
163779
|
+
}
|
|
163780
|
+
this.currentuuid = data.uuid;
|
|
163781
|
+
// Update textbox stats
|
|
163782
|
+
if (data.invalidated === true) {
|
|
163783
|
+
if (data.length) {
|
|
163784
|
+
this.throttledUpdateCachedStats(image, element, data);
|
|
163785
|
+
}
|
|
163786
|
+
else {
|
|
163787
|
+
this.updateCachedStats(image, element, data);
|
|
163788
|
+
}
|
|
163789
|
+
}
|
|
163790
|
+
});
|
|
163791
|
+
}
|
|
163792
|
+
}
|
|
163793
|
+
getPointsAlongLine(startHandle, endHandle, colPixelSpacing) {
|
|
163794
|
+
const points = [];
|
|
163795
|
+
const numPoints = Math.floor(endHandle.x) - Math.floor(startHandle.x);
|
|
163796
|
+
let x = Math.floor(startHandle.x) + 1;
|
|
163797
|
+
points.push(x * colPixelSpacing);
|
|
163798
|
+
for (let i = 0; i < numPoints; i++) {
|
|
163799
|
+
x = x + 1;
|
|
163800
|
+
points.push(x * colPixelSpacing); //from pixels to mm
|
|
163801
|
+
}
|
|
163802
|
+
return points;
|
|
163803
|
+
}
|
|
163804
|
+
getPixelValuesAlongLine(startHandle, points, colPixelSpacing, eventData) {
|
|
163805
|
+
const pixelValues = [];
|
|
163806
|
+
const yPoint = Math.floor(startHandle.y); // Adjust this if needed
|
|
163807
|
+
for (let i = 0; i < points.length; i++) {
|
|
163808
|
+
const xPoint = Math.floor(points[i] / colPixelSpacing);
|
|
163809
|
+
const pixelValue = cornerstone_core_1.default.getStoredPixels(eventData.element, xPoint, yPoint, 1, 1)[0];
|
|
163810
|
+
// Use cornerstone to get pixel value at the specified location
|
|
163811
|
+
//const pixelValue = cornerstone.getPixelValue(image, xPoint, yPoint);
|
|
163812
|
+
pixelValues.push(pixelValue);
|
|
163813
|
+
}
|
|
163814
|
+
return pixelValues;
|
|
163815
|
+
}
|
|
163816
|
+
createPlot(points, pixelValues) {
|
|
163817
|
+
// Create a new trace for each measurement
|
|
163818
|
+
const trace = {
|
|
163819
|
+
x: points,
|
|
163820
|
+
y: pixelValues,
|
|
163821
|
+
type: "lines",
|
|
163822
|
+
line: {
|
|
163823
|
+
color: this.color
|
|
163824
|
+
}
|
|
163825
|
+
};
|
|
163826
|
+
// Add the trace to the existing data array
|
|
163827
|
+
if (this.newMeasurement) {
|
|
163828
|
+
this.plotlydata.push(trace);
|
|
163829
|
+
}
|
|
163830
|
+
else {
|
|
163831
|
+
const indexOfExistentData = this.plotlydata.findIndex(obj => obj.line.color === this.color);
|
|
163832
|
+
this.plotlydata[indexOfExistentData] = trace;
|
|
163833
|
+
}
|
|
163834
|
+
const data = [...this.plotlydata];
|
|
163835
|
+
// Combine all traces into a single data array
|
|
163836
|
+
// Adjust the axis range based on all data
|
|
163837
|
+
const allXValues = data.flatMap(trace => trace.x);
|
|
163838
|
+
const allYValues = data.flatMap(trace => trace.y);
|
|
163839
|
+
const layout = {
|
|
163840
|
+
xaxis: {
|
|
163841
|
+
range: [Math.min(...allXValues), Math.max(...allXValues)],
|
|
163842
|
+
title: "position (mm)"
|
|
163843
|
+
},
|
|
163844
|
+
yaxis: {
|
|
163845
|
+
range: [Math.min(...allYValues), Math.max(...allYValues)],
|
|
163846
|
+
title: "GreyScaleValue (HU)"
|
|
163847
|
+
},
|
|
163848
|
+
title: "GreyScaleValues vs position",
|
|
163849
|
+
responsive: true
|
|
163850
|
+
};
|
|
163851
|
+
// Display using Plotly
|
|
163852
|
+
const myPlotDiv = document.getElementById("myPlot");
|
|
163853
|
+
plotly_js_dist_min_1.default.react(myPlotDiv, data, layout);
|
|
163854
|
+
this.newMeasurement = false;
|
|
163855
|
+
}
|
|
163856
|
+
}
|
|
163857
|
+
exports["default"] = ManualLengthPlotTool;
|
|
163858
|
+
|
|
163859
|
+
|
|
163229
163860
|
/***/ }),
|
|
163230
163861
|
|
|
163231
163862
|
/***/ 4585:
|
|
@@ -163858,12 +164489,13 @@ exports.registerExternalTool = exports.setDefaultToolsProps = exports.getDefault
|
|
|
163858
164489
|
*/
|
|
163859
164490
|
const lodash_1 = __webpack_require__(6486);
|
|
163860
164491
|
const thresholdsBrushTool_1 = __importDefault(__webpack_require__(7073));
|
|
163861
|
-
// import Slice4DScrollMouseWheelTool from "./custom/4dSliceScrollTool";
|
|
163862
164492
|
const polylineScissorsTool_1 = __importDefault(__webpack_require__(8990));
|
|
163863
164493
|
const rectangleRoiOverlayTool_1 = __importDefault(__webpack_require__(1828));
|
|
163864
164494
|
const ellipticalRoiOverlayTool_1 = __importDefault(__webpack_require__(3211));
|
|
163865
164495
|
const BorderMagnifyTool_1 = __importDefault(__webpack_require__(7819));
|
|
163866
164496
|
const customMouseWheelScrollTool_1 = __importDefault(__webpack_require__(4585));
|
|
164497
|
+
const LengthPlotTool_1 = __importDefault(__webpack_require__(2775));
|
|
164498
|
+
const ManualLengthPlotTool_1 = __importDefault(__webpack_require__(893));
|
|
163867
164499
|
/**
|
|
163868
164500
|
* These tools are added with `addDefaultTools()`
|
|
163869
164501
|
*/
|
|
@@ -164069,6 +164701,42 @@ const DEFAULT_TOOLS = {
|
|
|
164069
164701
|
cleanable: true,
|
|
164070
164702
|
class: "LengthTool"
|
|
164071
164703
|
},
|
|
164704
|
+
LengthPlot: {
|
|
164705
|
+
name: "LengthPlot",
|
|
164706
|
+
viewports: "all",
|
|
164707
|
+
configuration: {
|
|
164708
|
+
drawHandles: true,
|
|
164709
|
+
drawHandlesOnHover: false,
|
|
164710
|
+
hideHandlesIfMoving: false,
|
|
164711
|
+
renderDashed: false,
|
|
164712
|
+
digits: 2,
|
|
164713
|
+
offset: 15
|
|
164714
|
+
},
|
|
164715
|
+
options: {
|
|
164716
|
+
mouseButtonMask: 1,
|
|
164717
|
+
supportedInteractionTypes: ["Mouse"]
|
|
164718
|
+
},
|
|
164719
|
+
cleanable: true,
|
|
164720
|
+
class: "LengthPlotTool"
|
|
164721
|
+
},
|
|
164722
|
+
ManualLengthPlot: {
|
|
164723
|
+
name: "ManualLengthPlot",
|
|
164724
|
+
viewports: "all",
|
|
164725
|
+
configuration: {
|
|
164726
|
+
drawHandles: true,
|
|
164727
|
+
drawHandlesOnHover: false,
|
|
164728
|
+
hideHandlesIfMoving: false,
|
|
164729
|
+
renderDashed: false,
|
|
164730
|
+
digits: 2,
|
|
164731
|
+
offset: 15
|
|
164732
|
+
},
|
|
164733
|
+
options: {
|
|
164734
|
+
mouseButtonMask: 1,
|
|
164735
|
+
supportedInteractionTypes: ["Mouse"]
|
|
164736
|
+
},
|
|
164737
|
+
cleanable: true,
|
|
164738
|
+
class: "ManualLengthPlotTool"
|
|
164739
|
+
},
|
|
164072
164740
|
Angle: {
|
|
164073
164741
|
name: "Angle",
|
|
164074
164742
|
viewports: "all",
|
|
@@ -164299,7 +164967,9 @@ const dvTools = {
|
|
|
164299
164967
|
RectangleRoiOverlayTool: rectangleRoiOverlayTool_1.default,
|
|
164300
164968
|
EllipticalRoiOverlayTool: ellipticalRoiOverlayTool_1.default,
|
|
164301
164969
|
BorderMagnifyTool: BorderMagnifyTool_1.default,
|
|
164302
|
-
CustomMouseWheelScrollTool: customMouseWheelScrollTool_1.default
|
|
164970
|
+
CustomMouseWheelScrollTool: customMouseWheelScrollTool_1.default,
|
|
164971
|
+
LengthPlotTool: LengthPlotTool_1.default,
|
|
164972
|
+
ManualLengthPlotTool: ManualLengthPlotTool_1.default
|
|
164303
164973
|
};
|
|
164304
164974
|
exports.dvTools = dvTools;
|
|
164305
164975
|
/**
|
|
@@ -166848,7 +167518,7 @@ module.exports = JSON.parse('{"x00000000":{"tag":"x00000000","vr":"UL","vm":"1",
|
|
|
166848
167518
|
/***/ ((module) => {
|
|
166849
167519
|
|
|
166850
167520
|
"use strict";
|
|
166851
|
-
module.exports = JSON.parse('{"name":"larvitar","keywords":["DICOM","imaging","medical","cornerstone"],"version":"2.1.
|
|
167521
|
+
module.exports = JSON.parse('{"name":"larvitar","keywords":["DICOM","imaging","medical","cornerstone"],"version":"2.1.10","description":"typescript library for parsing, loading, rendering and interacting with DICOM images","repository":{"url":"https://github.com/dvisionlab/Larvitar.git","type":"git"},"main":"dist/larvitar.js","types":"dist/index.d.ts","files":["dist","imaging/**/*.d.ts"],"scripts":{"coverage":"typescript-coverage-report","generate-docs":"node_modules/.bin/jsdoc -c jsdoc.json","build":"webpack --config ./bundler/webpack.prod.js && cp ./dist/larvitar.js ./docs/examples/larvitar.js","dev":"webpack --progress --config ./bundler/webpack.dev.js && cp ./dist/larvitar.js ./docs/examples/larvitar.js","dev-wip":"webpack serve --config ./bundler/webpack.dev-wip.js"},"author":"Simone Manini <simone.manini@dvisionlab.com> (https://www.dvisionlab.com)","contributors":["Mattia Ronzoni <mattia.ronzoni@dvisionlab.com> (https://www.dvisionlab.com)","Sara Zanchi <sara.zanchi@dvisionlab.com> (https://www.dvisionlab.com)","Ale Re <ale.re@dvisionlab.com> (https://www.dvisionlab.com)","Laura Borghesi Re <laura.borghesi@dvisionlab.com> (https://www.dvisionlab.com)"],"license":"MIT","dependencies":{"@rollup/plugin-commonjs":"^17.1.0","cornerstone-core":"^2.6.1","cornerstone-file-image-loader":"^0.3.0","cornerstone-tools":"^6.0.7","cornerstone-wado-image-loader":"^4.13.2","cornerstone-web-image-loader":"^2.1.1","crypto-js":"^4.1.1","dicom-character-set":"^1.0.3","dicom-parser":"^1.8.13","docdash":"^1.2.0","hammerjs":"^2.0.8","jpeg-lossless-decoder-js":"^2.0.7","keycode-js":"^3.1.0","lodash":"^4.17.15","pako":"^1.0.10","papaparse":"^5.3.0","pdfjs-dist":"^3.8.162","plotly.js-dist-min":"^2.27.1","uuid":"^8.3.2"},"devDependencies":{"@babel/core":"^7.21.8","@types/cornerstone-core":"^2.3.0","@types/crypto-js":"^4.1.1","@types/hammerjs":"^2.0.41","@types/lodash":"^4.14.192","@types/papaparse":"^5.3.7","@types/pdfjs-dist":"^2.10.378","@types/plotly.js":"^2.12.30","@types/plotly.js-dist-min":"^2.3.4","@types/uuid":"^9.0.1","babel-loader":"^9.1.2","clean-webpack-plugin":"^4.0.0","copy-webpack-plugin":"^11.0.0","fs":"^0.0.1-security","html-loader":"^4.2.0","html-webpack-plugin":"^5.5.0","ip":"^1.1.8","jsdoc":"^3.6.4","portfinder-sync":"^0.0.2","ts-loader":"^9.4.2","typescript":"^5.0.2","typescript-coverage-report":"^0.7.0","webpack":"^5.76.3","webpack-bundle-analyzer":"^4.8.0","webpack-cli":"^5.0.1","webpack-dev-server":"^4.13.1"}}');
|
|
166852
167522
|
|
|
166853
167523
|
/***/ })
|
|
166854
167524
|
|