larvitar 0.18.2 → 1.2.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.
Files changed (229) hide show
  1. package/.github/workflows/deploy.yml +3 -12
  2. package/MIGRATION.md +25 -0
  3. package/README.md +28 -27
  4. package/docs/documentation/Mixins.polygonSegmentationMixin%20-%20segmentation%20operations%20for%20polyline.html +171 -0
  5. package/docs/documentation/Tools.Annotation.ContoursTool.html +218 -0
  6. package/docs/documentation/Tools.Annotation.DiameterTool.html +219 -0
  7. package/docs/documentation/Tools.Annotation.SeedsTool.html +214 -0
  8. package/docs/documentation/Tools.Brush.BrushTool.html +218 -0
  9. package/docs/documentation/Tools.Brush.ThresholdsBrushTool.html +218 -0
  10. package/docs/documentation/Tools.PolylineScissorsTool.html +218 -0
  11. package/docs/documentation/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  12. package/docs/documentation/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  13. package/docs/documentation/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  14. package/docs/documentation/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  15. package/docs/documentation/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  16. package/docs/documentation/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  17. package/docs/documentation/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  18. package/docs/documentation/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  19. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  20. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  21. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  22. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  23. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  24. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  25. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  26. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  27. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  28. package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  29. package/docs/documentation/global.html +1303 -0
  30. package/docs/documentation/imageAnonymization.js.html +245 -0
  31. package/docs/documentation/imageColormaps.js.html +283 -0
  32. package/docs/documentation/imageContours.js.html +278 -0
  33. package/docs/documentation/imageIo.js.html +291 -0
  34. package/docs/documentation/imageLayers.js.html +188 -0
  35. package/docs/documentation/imageLoading.js.html +297 -0
  36. package/docs/documentation/imageParsing.js.html +385 -0
  37. package/docs/documentation/imagePresets.js.html +207 -0
  38. package/docs/documentation/imageRendering.js.html +849 -0
  39. package/docs/documentation/imageReslice.js.html +162 -0
  40. package/docs/documentation/imageStore.js.html +360 -0
  41. package/docs/documentation/imageTools.js.html +784 -0
  42. package/docs/documentation/imageUtils.js.html +1609 -0
  43. package/docs/documentation/image_colormaps.js.html +283 -0
  44. package/docs/documentation/image_contours.js.html +279 -0
  45. package/docs/documentation/image_io.js.html +288 -0
  46. package/docs/documentation/image_layers.js.html +188 -0
  47. package/docs/documentation/image_loading.js.html +294 -0
  48. package/docs/documentation/image_parsing.js.html +391 -0
  49. package/docs/documentation/image_presets.js.html +207 -0
  50. package/docs/documentation/image_rendering.js.html +845 -0
  51. package/docs/documentation/image_reslice.js.html +164 -0
  52. package/docs/documentation/image_store.js.html +359 -0
  53. package/docs/documentation/image_tools.js.html +792 -0
  54. package/docs/documentation/image_utils.js.html +1609 -0
  55. package/docs/documentation/index.html +175 -0
  56. package/docs/documentation/loaders_commonLoader.js.html +306 -0
  57. package/docs/documentation/loaders_dicomLoader.js.html +130 -0
  58. package/docs/documentation/loaders_fileLoader.js.html +155 -0
  59. package/docs/documentation/loaders_multiframeLoader.js.html +443 -0
  60. package/docs/documentation/loaders_niftiLoader.js.html +150 -0
  61. package/docs/documentation/loaders_nrrdLoader.js.html +545 -0
  62. package/docs/documentation/loaders_resliceLoader.js.html +258 -0
  63. package/docs/documentation/module-imaging_contours.html +954 -0
  64. package/docs/documentation/module-imaging_imageAnonymization.html +544 -0
  65. package/docs/documentation/module-imaging_imageColormaps.html +1012 -0
  66. package/docs/documentation/module-imaging_imageContours.html +954 -0
  67. package/docs/documentation/module-imaging_imageIo.html +1057 -0
  68. package/docs/documentation/module-imaging_imageLayers.html +904 -0
  69. package/docs/documentation/module-imaging_imageLoading.html +1301 -0
  70. package/docs/documentation/module-imaging_imageParsing.html +1356 -0
  71. package/docs/documentation/module-imaging_imagePresets.html +679 -0
  72. package/docs/documentation/module-imaging_imageRendering.html +3223 -0
  73. package/docs/documentation/module-imaging_imageReslice.html +413 -0
  74. package/docs/documentation/module-imaging_imageStore-Larvitar_Store.html +284 -0
  75. package/docs/documentation/module-imaging_imageStore.html +1560 -0
  76. package/docs/documentation/module-imaging_imageTools.html +3617 -0
  77. package/docs/documentation/module-imaging_imageUtils.html +7253 -0
  78. package/docs/documentation/module-imaging_io.html +1057 -0
  79. package/docs/documentation/module-imaging_layers.html +904 -0
  80. package/docs/documentation/module-imaging_loading.html +1301 -0
  81. package/docs/documentation/module-imaging_parsing.html +1375 -0
  82. package/docs/documentation/module-imaging_presets.html +679 -0
  83. package/docs/documentation/module-imaging_rendering.html +8094 -0
  84. package/docs/documentation/module-imaging_reslice.html +411 -0
  85. package/docs/documentation/module-imaging_store-Larvitar_Store.html +284 -0
  86. package/docs/documentation/module-imaging_store.html +1537 -0
  87. package/docs/documentation/module-imaging_strategies_eraseFreehand.html +708 -0
  88. package/docs/documentation/module-imaging_strategies_fillFreehand.html +708 -0
  89. package/docs/documentation/module-imaging_tools.html +3617 -0
  90. package/docs/documentation/module-imaging_tools_custom_contourTool.html +207 -0
  91. package/docs/documentation/module-imaging_tools_custom_diameterTool.html +205 -0
  92. package/docs/documentation/module-imaging_tools_custom_editMaskTool.html +205 -0
  93. package/docs/documentation/module-imaging_tools_custom_polygonScissorsTool.html +203 -0
  94. package/docs/documentation/module-imaging_tools_custom_thresholdBrushTool.html +684 -0
  95. package/docs/documentation/module-imaging_tools_default.html +205 -0
  96. package/docs/documentation/module-imaging_tools_interaction.html +530 -0
  97. package/docs/documentation/module-imaging_tools_io.html +832 -0
  98. package/docs/documentation/module-imaging_tools_main.html +2028 -0
  99. package/docs/documentation/module-imaging_tools_polygonSegmentationMixin.html +567 -0
  100. package/docs/documentation/module-imaging_tools_segmentation.html +3586 -0
  101. package/docs/documentation/module-imaging_tools_state.html +494 -0
  102. package/docs/documentation/module-imaging_utils.html +7253 -0
  103. package/docs/documentation/module-loaders_commonLoader.html +1313 -0
  104. package/docs/documentation/module-loaders_dicomLoader.html +522 -0
  105. package/docs/documentation/module-loaders_fileLoader.html +593 -0
  106. package/docs/documentation/module-loaders_multiframeLoader.html +1169 -0
  107. package/docs/documentation/module-loaders_niftiLoader.html +565 -0
  108. package/docs/documentation/module-loaders_nrrdLoader.html +1459 -0
  109. package/docs/documentation/module-loaders_resliceLoader.html +590 -0
  110. package/docs/documentation/module-monitors_memory.html +980 -0
  111. package/docs/documentation/module-tools_default.html +740 -0
  112. package/docs/documentation/module.exports_module.exports.html +203 -0
  113. package/docs/documentation/monitors_memory.js.html +189 -0
  114. package/docs/documentation/parsers_nrrd.js.html +569 -0
  115. package/docs/documentation/scripts/collapse.js +20 -0
  116. package/docs/documentation/scripts/linenumber.js +25 -0
  117. package/docs/documentation/scripts/nav.js +12 -0
  118. package/docs/documentation/scripts/polyfill.js +4 -0
  119. package/docs/documentation/scripts/prettify/Apache-License-2.0.txt +202 -0
  120. package/docs/documentation/scripts/prettify/lang-css.js +2 -0
  121. package/docs/documentation/scripts/prettify/prettify.js +28 -0
  122. package/docs/documentation/scripts/search.js +83 -0
  123. package/docs/documentation/styles/jsdoc.css +765 -0
  124. package/docs/documentation/styles/prettify.css +80 -0
  125. package/docs/documentation/tools_contourTool.js.html +1963 -0
  126. package/docs/documentation/tools_custom_contourTool.js.html +1968 -0
  127. package/docs/documentation/tools_custom_diameterTool.js.html +225 -0
  128. package/docs/documentation/tools_custom_editMaskTool.js.html +225 -0
  129. package/docs/documentation/tools_custom_polylineScissorsTool.js.html +143 -0
  130. package/docs/documentation/tools_custom_thresholdsBrushTool.js.html +245 -0
  131. package/docs/documentation/tools_default.js.html +576 -0
  132. package/docs/documentation/tools_diameterTool.js.html +219 -0
  133. package/docs/documentation/tools_editMaskTool.js.html +219 -0
  134. package/docs/documentation/tools_interaction.js.html +258 -0
  135. package/docs/documentation/tools_io.js.html +297 -0
  136. package/docs/documentation/tools_main.js.html +443 -0
  137. package/docs/documentation/tools_polygonSegmentationMixin.js.html +329 -0
  138. package/docs/documentation/tools_polylineScissorsTool.js.html +136 -0
  139. package/docs/documentation/tools_seedTool.js.html +423 -0
  140. package/docs/documentation/tools_segmentation.js.html +558 -0
  141. package/docs/documentation/tools_state.js.html +163 -0
  142. package/docs/documentation/tools_strategies_eraseFreehand.js.html +160 -0
  143. package/docs/documentation/tools_strategies_fillFreehand.js.html +163 -0
  144. package/docs/documentation/tools_thresholdsBrushTool.js.html +239 -0
  145. package/docs/documentation/tools_tools.default.js.html +569 -0
  146. package/docs/documentation/tools_tools.interaction.js.html +251 -0
  147. package/docs/documentation/tools_tools.io.js.html +288 -0
  148. package/docs/documentation/tools_tools.main.js.html +442 -0
  149. package/docs/documentation/tools_tools.segmentation.js.html +445 -0
  150. package/docs/documentation/tools_tools.state.js.html +157 -0
  151. package/docs/examples/base.html +170 -0
  152. package/docs/examples/colorMaps.html +181 -0
  153. package/docs/examples/defaultTools.html +246 -0
  154. package/docs/examples/demo/anon1 +0 -0
  155. package/docs/examples/demo/anon10 +0 -0
  156. package/docs/examples/demo/anon11 +0 -0
  157. package/docs/examples/demo/anon12 +0 -0
  158. package/docs/examples/demo/anon13 +0 -0
  159. package/docs/examples/demo/anon14 +0 -0
  160. package/docs/examples/demo/anon15 +0 -0
  161. package/docs/examples/demo/anon16 +0 -0
  162. package/docs/examples/demo/anon17 +0 -0
  163. package/docs/examples/demo/anon18 +0 -0
  164. package/docs/examples/demo/anon19 +0 -0
  165. package/docs/examples/demo/anon2 +0 -0
  166. package/docs/examples/demo/anon20 +0 -0
  167. package/docs/examples/demo/anon21 +0 -0
  168. package/docs/examples/demo/anon22 +0 -0
  169. package/docs/examples/demo/anon23 +0 -0
  170. package/docs/examples/demo/anon24 +0 -0
  171. package/docs/examples/demo/anon3 +0 -0
  172. package/docs/examples/demo/anon4 +0 -0
  173. package/docs/examples/demo/anon5 +0 -0
  174. package/docs/examples/demo/anon6 +0 -0
  175. package/docs/examples/demo/anon7 +0 -0
  176. package/docs/examples/demo/anon8 +0 -0
  177. package/docs/examples/demo/anon9 +0 -0
  178. package/docs/examples/demo/example.nrrd +0 -0
  179. package/docs/examples/demo/segmentation.nrrd +0 -0
  180. package/docs/examples/demo/xa_integris.dcm +0 -0
  181. package/docs/examples/index.html +129 -0
  182. package/docs/examples/larvitar.js +108623 -0
  183. package/docs/examples/layers.html +250 -0
  184. package/docs/examples/masks.html +273 -0
  185. package/docs/examples/multiframe.html +200 -0
  186. package/docs/examples/nrrd.html +96 -0
  187. package/docs/examples/reslice.html +174 -0
  188. package/docs/index.html +92 -0
  189. package/imaging/dataDictionary.json +21865 -21865
  190. package/imaging/imageAnonymization.js +161 -0
  191. package/imaging/{image_colormaps.js → imageColormaps.js} +2 -2
  192. package/imaging/{image_contours.js → imageContours.js} +1 -2
  193. package/imaging/{image_io.js → imageIo.js} +18 -15
  194. package/imaging/{image_layers.js → imageLayers.js} +2 -2
  195. package/imaging/{image_loading.js → imageLoading.js} +9 -6
  196. package/imaging/imageParsing.js +301 -0
  197. package/imaging/{image_presets.js → imagePresets.js} +2 -2
  198. package/imaging/{image_rendering.js → imageRendering.js} +36 -32
  199. package/imaging/imageReslice.js +78 -0
  200. package/imaging/{image_store.js → imageStore.js} +8 -7
  201. package/imaging/{image_tools.js → imageTools.js} +15 -23
  202. package/imaging/{image_utils.js → imageUtils.js} +1 -1
  203. package/imaging/loaders/commonLoader.js +1 -1
  204. package/imaging/loaders/dicomLoader.js +1 -1
  205. package/imaging/loaders/fileLoader.js +2 -2
  206. package/imaging/loaders/multiframeLoader.js +6 -2
  207. package/imaging/loaders/nrrdLoader.js +11 -7
  208. package/imaging/tools/{contourTool.js → custom/contourTool.js} +25 -20
  209. package/imaging/tools/{diameterTool.js → custom/diameterTool.js} +9 -3
  210. package/imaging/tools/{editMaskTool.js → custom/editMaskTool.js} +7 -1
  211. package/imaging/tools/{polylineScissorsTool.js → custom/polylineScissorsTool.js} +12 -5
  212. package/imaging/tools/{seedTool.js → custom/seedTool.js} +3 -3
  213. package/imaging/tools/{thresholdsBrushTool.js → custom/thresholdsBrushTool.js} +7 -1
  214. package/imaging/tools/{tools.default.js → default.js} +10 -3
  215. package/imaging/tools/{tools.interaction.js → interaction.js} +13 -6
  216. package/imaging/tools/{tools.io.js → io.js} +15 -6
  217. package/imaging/tools/{tools.main.js → main.js} +16 -14
  218. package/imaging/tools/polygonSegmentationMixin.js +8 -4
  219. package/imaging/tools/{tools.segmentation.js → segmentation.js} +171 -58
  220. package/imaging/tools/segmentations.md +38 -0
  221. package/imaging/tools/setLabelMap3D.js +248 -0
  222. package/imaging/tools/{tools.state.js → state.js} +7 -1
  223. package/imaging/tools/strategies/eraseFreehand.js +8 -9
  224. package/imaging/tools/strategies/fillFreehand.js +8 -9
  225. package/index.js +44 -39
  226. package/modules/vuex/larvitar.js +13 -3
  227. package/package.json +13 -10
  228. package/imaging/image_parsing.js +0 -307
  229. package/imaging/image_reslice.js +0 -80
@@ -0,0 +1,1963 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>tools/contourTool.js - Larvitar</title>
7
+
8
+ <meta name="description" content="Dicom Image Toolkit for CornestoneJS" />
9
+
10
+ <meta name="keywords" content="imaging, dataviz, medical, cornerstone" />
11
+ <meta name="keyword" content="imaging, dataviz, medical, cornerstone" />
12
+
13
+
14
+
15
+ <script src="scripts/prettify/prettify.js"></script>
16
+ <script src="scripts/prettify/lang-css.js"></script>
17
+ <!--[if lt IE 9]>
18
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
19
+ <![endif]-->
20
+ <link type="text/css" rel="stylesheet" href="styles/prettify.css">
21
+ <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
22
+ <script src="scripts/nav.js" defer></script>
23
+
24
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
25
+ </head>
26
+ <body>
27
+
28
+ <input type="checkbox" id="nav-trigger" class="nav-trigger" />
29
+ <label for="nav-trigger" class="navicon-button x">
30
+ <div class="navicon"></div>
31
+ </label>
32
+
33
+ <label for="nav-trigger" class="overlay"></label>
34
+
35
+ <nav >
36
+
37
+ <input type="text" id="nav-search" placeholder="Search" />
38
+
39
+
40
+ <h2><a href="index.html">Home</a></h2><h2><a href="https://github.com/dvisionlab/Larvitar" target="_blank" class="menu-item" id="repository" >Github repo</a></h2><h3>Classes</h3><ul><li><a href="module.exports_module.exports.html">module.exports#module.exports</a></li><li><a href="module-imaging_store-Larvitar_Store.html">imaging/store~Larvitar_Store</a></li><li><a href="Tools.Annotation.ContoursTool.html">Tools.Annotation.ContoursTool</a></li><li><a href="Tools.Annotation.DiameterTool.html">Tools.Annotation.DiameterTool</a></li><li><a href="Tools.Brush.BrushTool.html">Tools.Brush.BrushTool</a></li><li><a href="Tools.Brush.ThresholdsBrushTool.html">Tools.Brush.ThresholdsBrushTool</a></li><li><a href="Tools.PolylineScissorsTool.html">Tools.PolylineScissorsTool</a></li></ul><h3>Modules</h3><ul><li><a href="module-imaging_anonymization.html">imaging/anonymization</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_anonymization.html#anonymize#~anonymize">anonymize</a></li><li data-type='method' style='display: none;'><a href="module-imaging_anonymization.html#encrypt#~encrypt">encrypt</a></li></ul></li><li><a href="module-imaging_contours.html">imaging/contours</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_contours.html#extractSlicePoints#extractSlicePoints">extractSlicePoints</a></li><li data-type='method' style='display: none;'><a href="module-imaging_contours.html#populateContoursObject#populateContoursObject">populateContoursObject</a></li><li data-type='method' style='display: none;'><a href="module-imaging_contours.html#parseContours#~parseContours">parseContours</a></li></ul></li><li><a href="module-imaging_io.html">imaging/io</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_io.html#buildData#~buildData">buildData</a></li><li data-type='method' style='display: none;'><a href="module-imaging_io.html#buildDataAsync#~buildDataAsync">buildDataAsync</a></li><li data-type='method' style='display: none;'><a href="module-imaging_io.html#buildHeader#~buildHeader">buildHeader</a></li><li data-type='method' style='display: none;'><a href="module-imaging_io.html#getCachedPixelData#~getCachedPixelData">getCachedPixelData</a></li><li data-type='method' style='display: none;'><a href="module-imaging_io.html#importNRRDImage#~importNRRDImage">importNRRDImage</a></li></ul></li><li><a href="module-imaging_layers.html">imaging/layers</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_layers.html#getActiveLayer#getActiveLayer">getActiveLayer</a></li><li data-type='method' style='display: none;'><a href="module-imaging_layers.html#setActiveLayer#setActiveLayer">setActiveLayer</a></li><li data-type='method' style='display: none;'><a href="module-imaging_layers.html#updateLayer#updateLayer">updateLayer</a></li><li data-type='method' style='display: none;'><a href="module-imaging_layers.html#buildLayers#~buildLayers">buildLayers</a></li></ul></li><li><a href="module-imaging_loading.html">imaging/loading</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#initializeFileImageLoader#initializeFileImageLoader">initializeFileImageLoader</a></li><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#initializeImageLoader#initializeImageLoader">initializeImageLoader</a></li><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#initializeWebImageLoader#initializeWebImageLoader">initializeWebImageLoader</a></li><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#registerMultiFrameImageLoader#registerMultiFrameImageLoader">registerMultiFrameImageLoader</a></li><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#registerNRRDImageLoader#registerNRRDImageLoader">registerNRRDImageLoader</a></li><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#registerResliceLoader#registerResliceLoader">registerResliceLoader</a></li><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#updateLoadedStack#updateLoadedStack">updateLoadedStack</a></li><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#isNewInstance#~isNewInstance">isNewInstance</a></li></ul></li><li><a href="module-imaging_parsing.html">imaging/parsing</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_parsing.html#clearImageParsing#clearImageParsing">clearImageParsing</a></li><li data-type='method' style='display: none;'><a href="module-imaging_parsing.html#dumpDataSet#dumpDataSet">dumpDataSet</a></li><li data-type='method' style='display: none;'><a href="module-imaging_parsing.html#readFile#readFile">readFile</a></li><li data-type='method' style='display: none;'><a href="module-imaging_parsing.html#readFiles#readFiles">readFiles</a></li><li data-type='method' style='display: none;'><a href="module-imaging_parsing.html#dumpFile#~dumpFile">dumpFile</a></li><li data-type='method' style='display: none;'><a href="module-imaging_parsing.html#dumpFiles#~dumpFiles">dumpFiles</a></li><li data-type='method' style='display: none;'><a href="module-imaging_parsing.html#parseNextFile#~parseNextFile">parseNextFile</a></li></ul></li><li><a href="module-imaging_presets.html">imaging/presets</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_presets.html#getImagePresets#getImagePresets">getImagePresets</a></li><li data-type='method' style='display: none;'><a href="module-imaging_presets.html#setImageCustomPreset#setImageCustomPreset">setImageCustomPreset</a></li><li data-type='method' style='display: none;'><a href="module-imaging_presets.html#setImagePreset#setImagePreset">setImagePreset</a></li></ul></li><li><a href="module-imaging_rendering.html">imaging/rendering</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#HSVToRGB#.HSVToRGB">HSVToRGB</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#addColorMap#addColorMap">addColorMap</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#applyColorMap#applyColorMap">applyColorMap</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#clearImageCache#clearImageCache">clearImageCache</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#disableViewport#disableViewport">disableViewport</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#fillPixelData#fillPixelData">fillPixelData</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#flipImageHorizontal#flipImageHorizontal">flipImageHorizontal</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#flipImageVertical#flipImageVertical">flipImageVertical</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#getColormapsList#getColormapsList">getColormapsList</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#getSeriesData#getSeriesData">getSeriesData</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#invertImage#invertImage">invertImage</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#loadAndCacheImages#loadAndCacheImages">loadAndCacheImages</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#renderImage#renderImage">renderImage</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#renderWebImage#renderWebImage">renderWebImage</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#renderWebImage#renderWebImage">renderWebImage</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#resetViewports#resetViewports">resetViewports</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#resizeViewport#resizeViewport">resizeViewport</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#rotateImageLeft#rotateImageLeft">rotateImageLeft</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#rotateImageRight#rotateImageRight">rotateImageRight</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#storeViewportData#storeViewportData">storeViewportData</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#unloadViewport#unloadViewport">unloadViewport</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#updateImage#updateImage">updateImage</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#updateViewportData#updateViewportData">updateViewportData</a></li></ul></li><li></li><li><a href="module-imaging_reslice.html">imaging/reslice</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_reslice.html#resliceSeries#resliceSeries">resliceSeries</a></li></ul></li><li><a href="module-imaging_store.html">imaging/store</a><ul class='members'><li data-type='member' style='display: none;'><a href="module-imaging_store.html#.larvitar_store">larvitar_store</a></li></ul><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_store.html#initLarvitarStore#.initLarvitarStore">initLarvitarStore</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#addSeriesIds#~addSeriesIds">addSeriesIds</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#addViewport#~addViewport">addViewport</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#deleteViewport#~deleteViewport">deleteViewport</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#disableVuex#~disableVuex">disableVuex</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#enableVuex#~enableVuex">enableVuex</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#get#~get">get</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#removeSeriesIds#~removeSeriesIds">removeSeriesIds</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#set#~set">set</a></li></ul></li><li><a href="module-imaging_tools.html">imaging/tools</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#addContoursTool#~addContoursTool">addContoursTool</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#addDefaultTools#~addDefaultTools">addDefaultTools</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#addDiameterTool#~addDiameterTool">addDiameterTool</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#addMaskEditingTool#~addMaskEditingTool">addMaskEditingTool</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#addSeedsTool#~addSeedsTool">addSeedsTool</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#addStackStateToElement#~addStackStateToElement">addStackStateToElement</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#addToolStateSingleSlice#~addToolStateSingleSlice">addToolStateSingleSlice</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#clearCornerstoneElements#~clearCornerstoneElements">clearCornerstoneElements</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#clearMeasurements#~clearMeasurements">clearMeasurements</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#clearToolStateByName#~clearToolStateByName">clearToolStateByName</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#getCurrentMaskData#~getCurrentMaskData">getCurrentMaskData</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#getToolState#~getToolState">getToolState</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#isToolMissing#~isToolMissing">isToolMissing</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#setSegmentationConfig#~setSegmentationConfig">setSegmentationConfig</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#setToolActive#~setToolActive">setToolActive</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#setToolActive#~setToolActive">setToolActive</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#setToolEnabled#~setToolEnabled">setToolEnabled</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#setToolPassive#~setToolPassive">setToolPassive</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#syncToolStack#~syncToolStack">syncToolStack</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#updateDiameterTool#~updateDiameterTool">updateDiameterTool</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#updateStackToolState#~updateStackToolState">updateStackToolState</a></li></ul></li><li><a href="module-imaging_utils.html">imaging/utils</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#formatDate#formatDate">formatDate</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#formatDateTime#formatDateTime">formatDateTime</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getCmprMetadata#getCmprMetadata">getCmprMetadata</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getDICOMTag#getDICOMTag">getDICOMTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getDICOMTagCode#getDICOMTagCode">getDICOMTagCode</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getDistanceBetweenSlices#getDistanceBetweenSlices">getDistanceBetweenSlices</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getMaxPixelValue#getMaxPixelValue">getMaxPixelValue</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getMeanValue#getMeanValue">getMeanValue</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getMinPixelValue#getMinPixelValue">getMinPixelValue</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getNormalOrientation#getNormalOrientation">getNormalOrientation</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getPixelRepresentation#getPixelRepresentation">getPixelRepresentation</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getPixelTypedArray#getPixelTypedArray">getPixelTypedArray</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getReslicedIOP#getReslicedIOP">getReslicedIOP</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getReslicedIPP#getReslicedIPP">getReslicedIPP</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getReslicedMetadata#getReslicedMetadata">getReslicedMetadata</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getReslicedPixeldata#getReslicedPixeldata">getReslicedPixeldata</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getReslicedSliceLocation#getReslicedSliceLocation">getReslicedSliceLocation</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getSortedStack#getSortedStack">getSortedStack</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getSortedUIDs#getSortedUIDs">getSortedUIDs</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getTagValue#getTagValue">getTagValue</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getTypedArray#getTypedArray">getTypedArray</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getTypedArrayFromDataType#getTypedArrayFromDataType">getTypedArrayFromDataType</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#isElement#isElement">isElement</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#isNegativeSign#isNegativeSign">isNegativeSign</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#isStringVr#isStringVr">isStringVr</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#isValidDate#isValidDate">isValidDate</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#parseAgeTag#parseAgeTag">parseAgeTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#parseDateTag#parseDateTag">parseDateTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#parseDateTimeTag#parseDateTimeTag">parseDateTimeTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#parseDICOMFileIDTag#parseDICOMFileIDTag">parseDICOMFileIDTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#parsePatientNameTag#parsePatientNameTag">parsePatientNameTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#parseTag#parseTag">parseTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#parseTimeTag#parseTimeTag">parseTimeTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#permuteSignedArrays#permuteSignedArrays">permuteSignedArrays</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#permuteValues#permuteValues">permuteValues</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#rand#rand">rand</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#randomId#randomId">randomId</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#sortStackCallback#sortStackCallback">sortStackCallback</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#spacingArray#spacingArray">spacingArray</a></li></ul></li><li><a href="module-loaders_commonLoader.html">loaders/commonLoader</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#getImageFrame#getImageFrame">getImageFrame</a></li><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#getLarvitarImageTracker#getLarvitarImageTracker">getLarvitarImageTracker</a></li><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#getLarvitarManager#getLarvitarManager">getLarvitarManager</a></li><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#getSeriesDataFromLarvitarManager#getSeriesDataFromLarvitarManager">getSeriesDataFromLarvitarManager</a></li><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#populateLarvitarManager#populateLarvitarManager">populateLarvitarManager</a></li><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#removeSeriesFromLarvitarManager#removeSeriesFromLarvitarManager">removeSeriesFromLarvitarManager</a></li><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#resetLarvitarManager#resetLarvitarManager">resetLarvitarManager</a></li><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#updateLarvitarManager#updateLarvitarManager">updateLarvitarManager</a></li></ul></li><li><a href="module-loaders_dicomLoader.html">loaders/dicomLoader</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-loaders_dicomLoader.html#cacheImages#cacheImages">cacheImages</a></li><li data-type='method' style='display: none;'><a href="module-loaders_dicomLoader.html#getDicomImageId#getDicomImageId">getDicomImageId</a></li></ul></li><li><a href="module-loaders_fileLoader.html">loaders/fileLoader</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-loaders_fileLoader.html#getFileImageId#getFileImageId">getFileImageId</a></li><li data-type='method' style='display: none;'><a href="module-loaders_fileLoader.html#populateFileManager#populateFileManager">populateFileManager</a></li><li data-type='method' style='display: none;'><a href="module-loaders_fileLoader.html#resetFileLoader#resetFileLoader">resetFileLoader</a></li><li data-type='method' style='display: none;'><a href="module-loaders_fileLoader.html#resetFileManager#resetFileManager">resetFileManager</a></li></ul></li><li><a href="module-loaders_nrrdLoader.html">loaders/nrrdLoader</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-loaders_nrrdLoader.html#buildNrrdImage#buildNrrdImage">buildNrrdImage</a></li><li data-type='method' style='display: none;'><a href="module-loaders_nrrdLoader.html#createCustomImage#createCustomImage">createCustomImage</a></li><li data-type='method' style='display: none;'><a href="module-loaders_nrrdLoader.html#getImageIdFromSlice#getImageIdFromSlice">getImageIdFromSlice</a></li><li data-type='method' style='display: none;'><a href="module-loaders_nrrdLoader.html#getNrrdImageId#getNrrdImageId">getNrrdImageId</a></li><li data-type='method' style='display: none;'><a href="module-loaders_nrrdLoader.html#getNrrdSerieDimensions#getNrrdSerieDimensions">getNrrdSerieDimensions</a></li><li data-type='method' style='display: none;'><a href="module-loaders_nrrdLoader.html#getSliceNumberFromImageId#getSliceNumberFromImageId">getSliceNumberFromImageId</a></li><li data-type='method' style='display: none;'><a href="module-loaders_nrrdLoader.html#loadNrrdImage#loadNrrdImage">loadNrrdImage</a></li></ul></li><li><a href="module-loaders_resliceLoader.html">loaders/resliceLoader</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-loaders_resliceLoader.html#createCustomImage#createCustomImage">createCustomImage</a></li><li data-type='method' style='display: none;'><a href="module-loaders_resliceLoader.html#loadReslicedImage#loadReslicedImage">loadReslicedImage</a></li></ul></li><li><a href="module-monitors_memory.html">monitors/memory</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-monitors_memory.html#checkMemoryAllocation#checkMemoryAllocation">checkMemoryAllocation</a></li><li data-type='method' style='display: none;'><a href="module-monitors_memory.html#checkMemorySupport#checkMemorySupport">checkMemorySupport</a></li><li data-type='method' style='display: none;'><a href="module-monitors_memory.html#getAvailableMemory#getAvailableMemory">getAvailableMemory</a></li><li data-type='method' style='display: none;'><a href="module-monitors_memory.html#getMB#getMB">getMB</a></li><li data-type='method' style='display: none;'><a href="module-monitors_memory.html#getUsedMemory#getUsedMemory">getUsedMemory</a></li><li data-type='method' style='display: none;'><a href="module-monitors_memory.html#setAvailableMemory#setAvailableMemory">setAvailableMemory</a></li></ul></li><li><a href="module-tools_default.html">tools/default</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-tools_default.html#getDefaultToolsByType#~getDefaultToolsByType">getDefaultToolsByType</a></li><li data-type='method' style='display: none;'><a href="module-tools_default.html#setDefaultToolsProps#~setDefaultToolsProps">setDefaultToolsProps</a></li></ul></li></ul><h3>Events</h3><ul><li><a href="ContoursTool.html#event:_drawingDoubleTapClickCallback">ContoursTool#_drawingDoubleTapClickCallback</a></li><li><a href="ContoursTool.html#event:_drawingMouseDoubleClickCallback">ContoursTool#_drawingMouseDoubleClickCallback</a></li><li><a href="ContoursTool.html#event:_drawingMouseDownCallback">ContoursTool#_drawingMouseDownCallback</a></li><li><a href="ContoursTool.html#event:_drawingMouseDragCallback">ContoursTool#_drawingMouseDragCallback</a></li><li><a href="ContoursTool.html#event:_drawingMouseMoveCallback">ContoursTool#_drawingMouseMoveCallback</a></li><li><a href="ContoursTool.html#event:_drawingMouseUpCallback">ContoursTool#_drawingMouseUpCallback</a></li><li><a href="ContoursTool.html#event:_drawingTouchDragCallback">ContoursTool#_drawingTouchDragCallback</a></li><li><a href="ContoursTool.html#event:_drawingTouchStartCallback">ContoursTool#_drawingTouchStartCallback</a></li><li><a href="ContoursTool.html#event:_editMouseDragCallback">ContoursTool#_editMouseDragCallback</a></li><li><a href="ContoursTool.html#event:_editTouchDragCallback">ContoursTool#_editTouchDragCallback</a></li></ul><h3>Mixins</h3><ul><li><a href="Mixins.polygonSegmentationMixin%2520-%2520segmentation%2520operations%2520for%2520polyline.html">Mixins.polygonSegmentationMixin - segmentation operations for polyline</a></li></ul><h3>Global</h3><ul><li><a href="global.html#_checkIfDrawing">_checkIfDrawing</a></li><li><a href="global.html#_paint">_paint</a></li><li><a href="global.html#addDefaultTools">addDefaultTools</a></li><li><a href="global.html#addMouseKeyHandlers">addMouseKeyHandlers</a></li><li><a href="global.html#addSegmentationMask">addSegmentationMask</a></li><li><a href="global.html#addTool">addTool</a></li><li><a href="global.html#buildMultiFrameImage">buildMultiFrameImage</a></li><li><a href="global.html">clearMultiFrameCache</a></li><li><a href="global.html#clearSegmentationState">clearSegmentationState</a></li><li><a href="global.html#config">config</a></li><li><a href="global.html">createCustomImage</a></li><li><a href="global.html#csToolsCreateStack">csToolsCreateStack</a></li><li><a href="global.html#csToolsUpdateImageIndex">csToolsUpdateImageIndex</a></li><li><a href="global.html#deleteMask">deleteMask</a></li><li><a href="global.html#disableBrushTool">disableBrushTool</a></li><li><a href="global.html#download">download</a></li><li><a href="global.html#enableBrushTool">enableBrushTool</a></li><li><a href="global.html#eraseFreehand">eraseFreehand</a></li><li><a href="global.html#eraseInsideFreehand">eraseInsideFreehand</a></li><li><a href="global.html#eraseOutsideFreehand">eraseOutsideFreehand</a></li><li><a href="global.html#exportAnnotations">exportAnnotations</a></li><li><a href="global.html#extractToolInfo">extractToolInfo</a></li><li><a href="global.html#fillFreehand">fillFreehand</a></li><li><a href="global.html#fillInsideFreehand">fillInsideFreehand</a></li><li><a href="global.html#fillOutsideFreehand">fillOutsideFreehand</a></li><li><a href="global.html#forceRender">forceRender</a></li><li><a href="global.html#generateCSV">generateCSV</a></li><li><a href="global.html#generateLUT">generateLUT</a></li><li><a href="global.html#generateUniformLUT">generateUniformLUT</a></li><li><a href="global.html#getActiveLabelmapBuffer">getActiveLabelmapBuffer</a></li><li><a href="global.html#getCircleWithThreshold">getCircleWithThreshold</a></li><li><a href="global.html">getMultiFrameImageId</a></li><li><a href="global.html#HSVtoRGB">HSVtoRGB</a></li><li><a href="global.html#initializeCSTools">initializeCSTools</a></li><li><a href="global.html#initSegmentationModule">initSegmentationModule</a></li><li><a href="global.html#isDrawing">isDrawing</a></li><li><a href="global.html#isToolMissing">isToolMissing</a></li><li><a href="global.html#loadAnnotations">loadAnnotations</a></li><li><a href="global.html#loadMultiFrameImage">loadMultiFrameImage</a></li><li><a href="global.html#NRRD_TYPES_TO_TYPEDARRAY">NRRD_TYPES_TO_TYPEDARRAY</a></li><li><a href="global.html">parse</a></li><li><a href="global.html#redoLastStroke">redoLastStroke</a></li><li><a href="global.html#renderToolData">renderToolData</a></li><li><a href="global.html#restoreToolState">restoreToolState</a></li><li><a href="global.html#saveAnnotations">saveAnnotations</a></li><li><a href="global.html#saveToolState">saveToolState</a></li><li><a href="global.html#setActiveLabelmap">setActiveLabelmap</a></li><li><a href="global.html#setActiveLabelOpacity">setActiveLabelOpacity</a></li><li><a href="global.html#setActiveSegment">setActiveSegment</a></li><li><a href="global.html#setBrushProps">setBrushProps</a></li><li><a href="global.html#setInactiveLabelOpacity">setInactiveLabelOpacity</a></li><li><a href="global.html#setMaskProps">setMaskProps</a></li><li><a href="global.html">setPixelDataType</a></li><li><a href="global.html#setToolActive">setToolActive</a></li><li><a href="global.html#setToolDisabled">setToolDisabled</a></li><li><a href="global.html#setToolEnabled">setToolEnabled</a></li><li><a href="global.html#setToolPassive">setToolPassive</a></li><li><a href="global.html#setToolsStyle">setToolsStyle</a></li><li><a href="global.html#toggleContourMode">toggleContourMode</a></li><li><a href="global.html">toggleMouseHandlers</a></li><li><a href="global.html#tryUpdateImage">tryUpdateImage</a></li><li><a href="global.html#undoLastStroke">undoLastStroke</a></li></ul>
41
+
42
+ </nav>
43
+
44
+ <div id="main">
45
+
46
+ <h1 class="page-title">tools/contourTool.js</h1>
47
+
48
+
49
+
50
+
51
+
52
+
53
+
54
+ <section>
55
+ <article>
56
+ <pre class="prettyprint source linenums"><code>// external libraries
57
+ import cornerstone from "cornerstone-core";
58
+ import csTools from "cornerstone-tools";
59
+ import { each, map } from "lodash";
60
+
61
+ // internal libraries
62
+ import { addToolStateSingleSlice } from "../image_tools";
63
+
64
+ // cornerstone tools imports
65
+ const external = csTools.external;
66
+ const EVENTS = csTools.EVENTS;
67
+ const BaseAnnotationTool = csTools.importInternal("base/BaseAnnotationTool");
68
+ const getToolState = csTools.getToolState;
69
+ const addToolState = csTools.addToolState;
70
+ const removeToolState = csTools.removeToolState;
71
+ const toolStyle = csTools.toolStyle;
72
+ const toolColors = csTools.toolColors;
73
+ const triggerEvent = csTools.importInternal("util/triggerEvent");
74
+ const pointInsideBoundingBox = csTools.importInternal(
75
+ "util/pointInsideBoundingBox"
76
+ );
77
+ const calculateSUV = csTools.importInternal("util/calculateSUV");
78
+ const numbersWithCommas = csTools.importInternal("util/numbersWithCommas");
79
+ const getNewContext = csTools.importInternal("drawing/getNewContext");
80
+ const draw = csTools.importInternal("drawing/draw");
81
+ const drawJoinedLines = csTools.importInternal("drawing/drawJoinedLines");
82
+ const drawHandles = csTools.importInternal("drawing/drawHandles");
83
+ const drawLinkedTextBox = csTools.importInternal("drawing/drawLinkedTextBox");
84
+ const clipToBox = csTools.importInternal("util/clip");
85
+ const freehandRoiCursor = csTools.importInternal("cursors/freehandRoiCursor");
86
+ const getLogger = csTools.importInternal("util/getLogger");
87
+ const throttle = csTools.importInternal("util/throttle");
88
+ const logger = getLogger("tools:annotation:FreehandRoiTool");
89
+ const freehandUtils = csTools.importInternal("util/freehandUtils");
90
+
91
+ // TODO check how to import these
92
+ // const toolCursor = csTools.importInternal("store/setToolCursor");
93
+ // const hideToolCursor = toolCursor.hideToolCursor;
94
+ // const setToolCursor = toolCursor.setToolCursor;
95
+ // const findAndMoveHelpers = csTools.importInternal("util/findAndMoveHelpers");
96
+ // const moveHandleNearImagePoint = findAndMoveHelpers.moveHandleNearImagePoint;
97
+
98
+ const {
99
+ insertOrDelete,
100
+ freehandArea,
101
+ calculateFreehandStatistics,
102
+ freehandIntersect,
103
+ FreehandHandleData
104
+ } = freehandUtils;
105
+
106
+ const state = {
107
+ // Global
108
+ globalTools: {},
109
+ globalToolChangeHistory: [],
110
+ // Tracking
111
+ enabledElements: [],
112
+ tools: [],
113
+ isToolLocked: false,
114
+ activeMultiPartTool: null,
115
+ mousePositionImage: {},
116
+ // Settings
117
+ clickProximity: 6,
118
+ touchProximity: 10,
119
+ handleRadius: 6,
120
+ deleteIfHandleOutsideImage: true,
121
+ preventHandleOutsideImage: false,
122
+ // Cursor
123
+ svgCursorUrl: null
124
+ };
125
+
126
+ /**
127
+ * @public
128
+ * @class ContoursTool
129
+ * @memberof Tools.Annotation
130
+ * @classdesc Tool for drawing a set of contours
131
+ * @extends Tools.Base.BaseAnnotationTool
132
+ */
133
+ export class ContoursTool extends BaseAnnotationTool {
134
+ constructor(props = {}) {
135
+ const defaultProps = {
136
+ name: "ContoursTool",
137
+ supportedInteractionTypes: ["Mouse", "Touch"],
138
+ configuration: defaultFreehandConfiguration(),
139
+ svgCursor: freehandRoiCursor
140
+ };
141
+
142
+ super(props, defaultProps);
143
+
144
+ this.initializeContours(props.contoursParsedData, props.segmentationName);
145
+
146
+ this.isMultiPartTool = true;
147
+
148
+ this._drawing = false;
149
+ this._dragging = false;
150
+ this._modifying = false;
151
+
152
+ // Create bound callback functions for private event loops
153
+ this._drawingMouseDownCallback = this._drawingMouseDownCallback.bind(this);
154
+ this._drawingMouseMoveCallback = this._drawingMouseMoveCallback.bind(this);
155
+ this._drawingMouseDragCallback = this._drawingMouseDragCallback.bind(this);
156
+ this._drawingMouseUpCallback = this._drawingMouseUpCallback.bind(this);
157
+ this._drawingMouseDoubleClickCallback = this._drawingMouseDoubleClickCallback.bind(
158
+ this
159
+ );
160
+ this._editMouseUpCallback = this._editMouseUpCallback.bind(this);
161
+ this._editMouseDragCallback = this._editMouseDragCallback.bind(this);
162
+
163
+ this._drawingTouchStartCallback = this._drawingTouchStartCallback.bind(
164
+ this
165
+ );
166
+ this._drawingTouchDragCallback = this._drawingTouchDragCallback.bind(this);
167
+ this._drawingDoubleTapClickCallback = this._drawingDoubleTapClickCallback.bind(
168
+ this
169
+ );
170
+ this._editTouchDragCallback = this._editTouchDragCallback.bind(this);
171
+
172
+ this.throttledUpdateCachedStats = throttle(this.updateCachedStats, 110);
173
+ }
174
+
175
+ initializeContours(contourData, segmentationName) {
176
+ var elements = cornerstone.getEnabledElements();
177
+ each(elements, el => {
178
+ var slices = contourData[el.element.id][segmentationName];
179
+
180
+ for (var slice in slices) {
181
+ var linesPerSlice =
182
+ contourData[el.element.id][segmentationName][slice].lines;
183
+ var lines = map(linesPerSlice, line => {
184
+ let dataToInject = {
185
+ visible: true,
186
+ active: false,
187
+ invalidated: false,
188
+ color: "#FF0000",
189
+ handles: {
190
+ points: line
191
+ }
192
+ };
193
+ return dataToInject;
194
+ });
195
+
196
+ addToolStateSingleSlice(el.element, "ContoursTool", lines, slice);
197
+ }
198
+ });
199
+ }
200
+
201
+ createNewMeasurement(eventData) {
202
+ const goodEventData =
203
+ eventData &amp;&amp; eventData.currentPoints &amp;&amp; eventData.currentPoints.image;
204
+
205
+ if (!goodEventData) {
206
+ logger.error(
207
+ `required eventData not supplied to tool ${this.name}'s createNewMeasurement`
208
+ );
209
+
210
+ return;
211
+ }
212
+
213
+ const measurementData = {
214
+ visible: true,
215
+ active: true,
216
+ invalidated: true,
217
+ color: undefined,
218
+ handles: {
219
+ points: []
220
+ }
221
+ };
222
+
223
+ measurementData.handles.textBox = {
224
+ active: false,
225
+ hasMoved: false,
226
+ movesIndependently: false,
227
+ drawnIndependently: true,
228
+ allowedOutsideImage: true,
229
+ hasBoundingBox: true
230
+ };
231
+
232
+ return measurementData;
233
+ }
234
+
235
+ /**
236
+ *
237
+ *
238
+ * @param {*} element element
239
+ * @param {*} data data
240
+ * @param {*} coords coords
241
+ * @returns {Boolean}
242
+ */
243
+ pointNearTool(element, data, coords) {
244
+ const validParameters = data &amp;&amp; data.handles &amp;&amp; data.handles.points;
245
+
246
+ if (!validParameters) {
247
+ throw new Error(
248
+ `invalid parameters supplied to tool ${this.name}'s pointNearTool`
249
+ );
250
+ }
251
+
252
+ if (!validParameters || data.visible === false) {
253
+ return false;
254
+ }
255
+
256
+ const isPointNearTool = this._pointNearHandle(element, data, coords);
257
+
258
+ if (isPointNearTool !== undefined) {
259
+ return true;
260
+ }
261
+
262
+ return false;
263
+ }
264
+
265
+ /**
266
+ * @param {*} element
267
+ * @param {*} data
268
+ * @param {*} coords
269
+ * @returns {number} the distance in px from the provided coordinates to the
270
+ * closest rendered portion of the annotation. -1 if the distance cannot be
271
+ * calculated.
272
+ */
273
+ distanceFromPoint(element, data, coords) {
274
+ let distance = Infinity;
275
+
276
+ for (let i = 0; i &lt; data.handles.points.length; i++) {
277
+ const distanceI = external.cornerstoneMath.point.distance(
278
+ data.handles.points[i],
279
+ coords
280
+ );
281
+
282
+ distance = Math.min(distance, distanceI);
283
+ }
284
+
285
+ // If an error caused distance not to be calculated, return -1.
286
+ if (distance === Infinity) {
287
+ return -1;
288
+ }
289
+
290
+ return distance;
291
+ }
292
+
293
+ /**
294
+ * @param {*} element
295
+ * @param {*} data
296
+ * @param {*} coords
297
+ * @returns {number} the distance in canvas units from the provided coordinates to the
298
+ * closest rendered portion of the annotation. -1 if the distance cannot be
299
+ * calculated.
300
+ */
301
+ distanceFromPointCanvas(element, data, coords) {
302
+ let distance = Infinity;
303
+
304
+ if (!data) {
305
+ return -1;
306
+ }
307
+
308
+ const canvasCoords = external.cornerstone.pixelToCanvas(element, coords);
309
+
310
+ const points = data.handles.points;
311
+
312
+ for (let i = 0; i &lt; points.length; i++) {
313
+ const handleCanvas = external.cornerstone.pixelToCanvas(
314
+ element,
315
+ points[i]
316
+ );
317
+
318
+ const distanceI = external.cornerstoneMath.point.distance(
319
+ handleCanvas,
320
+ canvasCoords
321
+ );
322
+
323
+ distance = Math.min(distance, distanceI);
324
+ }
325
+
326
+ // If an error caused distance not to be calculated, return -1.
327
+ if (distance === Infinity) {
328
+ return -1;
329
+ }
330
+
331
+ return distance;
332
+ }
333
+
334
+ /**
335
+ *
336
+ *
337
+ *
338
+ * @param {Object} image image
339
+ * @param {Object} element element
340
+ * @param {Object} data data
341
+ *
342
+ * @returns {void} void
343
+ */
344
+ updateCachedStats(image, element, data) {
345
+ // Define variables for the area and mean/standard deviation
346
+ let meanStdDev, meanStdDevSUV;
347
+
348
+ const seriesModule = external.cornerstone.metaData.get(
349
+ "generalSeriesModule",
350
+ image.imageId
351
+ );
352
+ const modality = seriesModule ? seriesModule.modality : null;
353
+
354
+ const points = data.handles.points;
355
+ // If the data has been invalidated, and the tool is not currently active,
356
+ // We need to calculate it again.
357
+
358
+ // Retrieve the bounds of the ROI in image coordinates
359
+ const bounds = {
360
+ left: points[0].x,
361
+ right: points[0].x,
362
+ bottom: points[0].y,
363
+ top: points[0].x
364
+ };
365
+
366
+ for (let i = 0; i &lt; points.length; i++) {
367
+ bounds.left = Math.min(bounds.left, points[i].x);
368
+ bounds.right = Math.max(bounds.right, points[i].x);
369
+ bounds.bottom = Math.min(bounds.bottom, points[i].y);
370
+ bounds.top = Math.max(bounds.top, points[i].y);
371
+ }
372
+
373
+ const polyBoundingBox = {
374
+ left: bounds.left,
375
+ top: bounds.bottom,
376
+ width: Math.abs(bounds.right - bounds.left),
377
+ height: Math.abs(bounds.top - bounds.bottom)
378
+ };
379
+
380
+ // Store the bounding box information for the text box
381
+ data.polyBoundingBox = polyBoundingBox;
382
+
383
+ // First, make sure this is not a color image, since no mean / standard
384
+ // Deviation will be calculated for color images.
385
+ if (!image.color) {
386
+ // Retrieve the array of pixels that the ROI bounds cover
387
+ const pixels = external.cornerstone.getPixels(
388
+ element,
389
+ polyBoundingBox.left,
390
+ polyBoundingBox.top,
391
+ polyBoundingBox.width,
392
+ polyBoundingBox.height
393
+ );
394
+
395
+ // Calculate the mean &amp; standard deviation from the pixels and the object shape
396
+ meanStdDev = calculateFreehandStatistics.call(
397
+ this,
398
+ pixels,
399
+ polyBoundingBox,
400
+ data.handles.points
401
+ );
402
+
403
+ if (modality === "PT") {
404
+ // If the image is from a PET scan, use the DICOM tags to
405
+ // Calculate the SUV from the mean and standard deviation.
406
+
407
+ // Note that because we are using modality pixel values from getPixels, and
408
+ // The calculateSUV routine also rescales to modality pixel values, we are first
409
+ // Returning the values to storedPixel values before calcuating SUV with them.
410
+ // TODO: Clean this up? Should we add an option to not scale in calculateSUV?
411
+ meanStdDevSUV = {
412
+ mean: calculateSUV(
413
+ image,
414
+ (meanStdDev.mean - image.intercept) / image.slope
415
+ ),
416
+ stdDev: calculateSUV(
417
+ image,
418
+ (meanStdDev.stdDev - image.intercept) / image.slope
419
+ )
420
+ };
421
+ }
422
+
423
+ // If the mean and standard deviation values are sane, store them for later retrieval
424
+ if (meanStdDev &amp;&amp; !isNaN(meanStdDev.mean)) {
425
+ data.meanStdDev = meanStdDev;
426
+ data.meanStdDevSUV = meanStdDevSUV;
427
+ }
428
+ }
429
+
430
+ // Retrieve the pixel spacing values, and if they are not
431
+ // Real non-zero values, set them to 1
432
+ const columnPixelSpacing = image.columnPixelSpacing || 1;
433
+ const rowPixelSpacing = image.rowPixelSpacing || 1;
434
+ const scaling = columnPixelSpacing * rowPixelSpacing;
435
+
436
+ const area = freehandArea(data.handles.points, scaling);
437
+
438
+ // If the area value is sane, store it for later retrieval
439
+ if (!isNaN(area)) {
440
+ data.area = area;
441
+ }
442
+
443
+ // Set the invalidated flag to false so that this data won't automatically be recalculated
444
+ data.invalidated = false;
445
+ }
446
+
447
+ /**
448
+ *
449
+ *
450
+ * @param {*} evt
451
+ * @returns {undefined}
452
+ */
453
+ renderToolData(evt) {
454
+ const eventData = evt.detail;
455
+
456
+ // If we have no toolState for this element, return immediately as there is nothing to do
457
+ const toolState = getToolState(evt.currentTarget, this.name);
458
+
459
+ if (!toolState) {
460
+ return;
461
+ }
462
+
463
+ const { image, element } = eventData;
464
+ const config = this.configuration;
465
+ const seriesModule = external.cornerstone.metaData.get(
466
+ "generalSeriesModule",
467
+ image.imageId
468
+ );
469
+ const modality = seriesModule ? seriesModule.modality : null;
470
+
471
+ // We have tool data for this element - iterate over each one and draw it
472
+ const context = getNewContext(eventData.canvasContext.canvas);
473
+ const lineWidth = toolStyle.getToolWidth();
474
+
475
+ for (let i = 0; i &lt; toolState.data.length; i++) {
476
+ const data = toolState.data[i];
477
+
478
+ if (data.visible === false) {
479
+ continue;
480
+ }
481
+
482
+ draw(context, context => {
483
+ let color = toolColors.getColorIfActive(data);
484
+ let fillColor;
485
+
486
+ if (data.active) {
487
+ if (data.handles.invalidHandlePlacement) {
488
+ color = config.invalidColor;
489
+ fillColor = config.invalidColor;
490
+ } else {
491
+ color = toolColors.getColorIfActive(data);
492
+ fillColor = toolColors.getFillColor();
493
+ }
494
+ } else {
495
+ fillColor = toolColors.getToolColor();
496
+ }
497
+
498
+ if (data.handles.points.length) {
499
+ for (let j = 0; j &lt; data.handles.points.length; j++) {
500
+ const lines = [...data.handles.points[j].lines];
501
+ const points = data.handles.points;
502
+
503
+ if (j === points.length - 1 &amp;&amp; !data.polyBoundingBox) {
504
+ // If it's still being actively drawn, keep the last line to
505
+ // The mouse location
506
+ lines.push(config.mouseLocation.handles.start);
507
+ }
508
+ drawJoinedLines(context, element, data.handles.points[j], lines, {
509
+ color
510
+ });
511
+ }
512
+ }
513
+
514
+ // Draw handles
515
+
516
+ const options = {
517
+ color,
518
+ fill: fillColor
519
+ };
520
+
521
+ if (config.alwaysShowHandles || (data.active &amp;&amp; data.polyBoundingBox)) {
522
+ // Render all handles
523
+ options.handleRadius = config.activeHandleRadius;
524
+ drawHandles(context, eventData, data.handles.points, options);
525
+ }
526
+
527
+ if (data.canComplete) {
528
+ // Draw large handle at the origin if can complete drawing
529
+ options.handleRadius = config.completeHandleRadius;
530
+ const handle = data.handles.points[0];
531
+ drawHandles(context, eventData, [handle], options);
532
+ }
533
+
534
+ if (data.active &amp;&amp; !data.polyBoundingBox) {
535
+ // Draw handle at origin and at mouse if actively drawing
536
+ options.handleRadius = config.activeHandleRadius;
537
+ drawHandles(
538
+ context,
539
+ eventData,
540
+ config.mouseLocation.handles,
541
+ options
542
+ );
543
+
544
+ const firstHandle = data.handles.points[0];
545
+ drawHandles(context, eventData, [firstHandle], options);
546
+ }
547
+
548
+ // Update textbox stats
549
+ if (data.invalidated === true &amp;&amp; !data.active) {
550
+ if (data.meanStdDev &amp;&amp; data.meanStdDevSUV &amp;&amp; data.area) {
551
+ this.throttledUpdateCachedStats(image, element, data);
552
+ } else {
553
+ this.updateCachedStats(image, element, data);
554
+ }
555
+ }
556
+
557
+ // Only render text if polygon ROI has been completed and freehand 'shiftKey' mode was not used:
558
+ if (data.polyBoundingBox &amp;&amp; !data.handles.textBox.freehand) {
559
+ // If the textbox has not been moved by the user, it should be displayed on the right-most
560
+ // Side of the tool.
561
+ if (!data.handles.textBox.hasMoved) {
562
+ // Find the rightmost side of the polyBoundingBox at its vertical center, and place the textbox here
563
+ // Note that this calculates it in image coordinates
564
+ data.handles.textBox.x =
565
+ data.polyBoundingBox.left + data.polyBoundingBox.width;
566
+ data.handles.textBox.y =
567
+ data.polyBoundingBox.top + data.polyBoundingBox.height / 2;
568
+ }
569
+
570
+ const text = textBoxText.call(this, data);
571
+
572
+ drawLinkedTextBox(
573
+ context,
574
+ element,
575
+ data.handles.textBox,
576
+ text,
577
+ data.handles.points,
578
+ textBoxAnchorPoints,
579
+ color,
580
+ lineWidth,
581
+ 0,
582
+ true
583
+ );
584
+ }
585
+ });
586
+ }
587
+
588
+ function textBoxText(data) {
589
+ const { meanStdDev, meanStdDevSUV, area } = data;
590
+ // Define an array to store the rows of text for the textbox
591
+ const textLines = [];
592
+
593
+ // If the mean and standard deviation values are present, display them
594
+ if (meanStdDev &amp;&amp; meanStdDev.mean !== undefined) {
595
+ // If the modality is CT, add HU to denote Hounsfield Units
596
+ let moSuffix = "";
597
+
598
+ if (modality === "CT") {
599
+ moSuffix = "HU";
600
+ }
601
+ data.unit = moSuffix;
602
+
603
+ // Create a line of text to display the mean and any units that were specified (i.e. HU)
604
+ let meanText = `Mean: ${numbersWithCommas(
605
+ meanStdDev.mean.toFixed(2)
606
+ )} ${moSuffix}`;
607
+ // Create a line of text to display the standard deviation and any units that were specified (i.e. HU)
608
+ let stdDevText = `StdDev: ${numbersWithCommas(
609
+ meanStdDev.stdDev.toFixed(2)
610
+ )} ${moSuffix}`;
611
+
612
+ // If this image has SUV values to display, concatenate them to the text line
613
+ if (meanStdDevSUV &amp;&amp; meanStdDevSUV.mean !== undefined) {
614
+ const SUVtext = " SUV: ";
615
+
616
+ meanText +=
617
+ SUVtext + numbersWithCommas(meanStdDevSUV.mean.toFixed(2));
618
+ stdDevText +=
619
+ SUVtext + numbersWithCommas(meanStdDevSUV.stdDev.toFixed(2));
620
+ }
621
+
622
+ // Add these text lines to the array to be displayed in the textbox
623
+ textLines.push(meanText);
624
+ textLines.push(stdDevText);
625
+ }
626
+
627
+ // If the area is a sane value, display it
628
+ if (area) {
629
+ // Determine the area suffix based on the pixel spacing in the image.
630
+ // If pixel spacing is present, use millimeters. Otherwise, use pixels.
631
+ // This uses Char code 178 for a superscript 2
632
+ let suffix = ` mm${String.fromCharCode(178)}`;
633
+
634
+ if (!image.rowPixelSpacing || !image.columnPixelSpacing) {
635
+ suffix = ` pixels${String.fromCharCode(178)}`;
636
+ }
637
+
638
+ // Create a line of text to display the area and its units
639
+ const areaText = `Area: ${numbersWithCommas(area.toFixed(2))}${suffix}`;
640
+
641
+ // Add this text line to the array to be displayed in the textbox
642
+ textLines.push(areaText);
643
+ }
644
+
645
+ return textLines;
646
+ }
647
+
648
+ function textBoxAnchorPoints(handles) {
649
+ return handles;
650
+ }
651
+ }
652
+
653
+ addNewMeasurement(evt) {
654
+ const eventData = evt.detail;
655
+
656
+ this._startDrawing(evt);
657
+ this._addPoint(eventData);
658
+
659
+ preventPropagation(evt);
660
+ }
661
+
662
+ preMouseDownCallback(evt) {
663
+ const eventData = evt.detail;
664
+ const nearby = this._pointNearHandleAllTools(eventData);
665
+
666
+ if (eventData.event.ctrlKey) {
667
+ if (nearby !== undefined &amp;&amp; nearby.handleNearby.hasBoundingBox) {
668
+ // Ctrl + clicked textBox, do nothing but still consume event.
669
+ } else {
670
+ insertOrDelete.call(this, evt, nearby);
671
+ }
672
+
673
+ preventPropagation(evt);
674
+
675
+ return true;
676
+ }
677
+
678
+ return false;
679
+ }
680
+
681
+ handleSelectedCallback(evt, toolData, handle, interactionType = "mouse") {
682
+ const { element } = evt.detail;
683
+ const toolState = getToolState(element, this.name);
684
+ console.info(interactionType);
685
+ // if (handle.hasBoundingBox) {
686
+ // // Use default move handler.
687
+ // moveHandleNearImagePoint(evt, this, toolData, handle, interactionType);
688
+
689
+ // return;
690
+ // }
691
+
692
+ const config = this.configuration;
693
+
694
+ config.dragOrigin = {
695
+ x: handle.x,
696
+ y: handle.y
697
+ };
698
+
699
+ // Iterating over handles of all toolData instances to find the indices of the selected handle
700
+ for (let toolIndex = 0; toolIndex &lt; toolState.data.length; toolIndex++) {
701
+ const points = toolState.data[toolIndex].handles.points;
702
+
703
+ for (let p = 0; p &lt; points.length; p++) {
704
+ if (points[p] === handle) {
705
+ config.currentHandle = p;
706
+ config.currentTool = toolIndex;
707
+ }
708
+ }
709
+ }
710
+
711
+ this._modifying = true;
712
+
713
+ this._activateModify(element);
714
+
715
+ // Interupt eventDispatchers
716
+ preventPropagation(evt);
717
+ }
718
+
719
+ /**
720
+ * Event handler for MOUSE_MOVE during drawing event loop.
721
+ *
722
+ * @event
723
+ * @param {Object} evt - The event.
724
+ * @returns {undefined}
725
+ */
726
+ _drawingMouseMoveCallback(evt) {
727
+ const eventData = evt.detail;
728
+ const { currentPoints, element } = eventData;
729
+ const toolState = getToolState(element, this.name);
730
+
731
+ const config = this.configuration;
732
+ const currentTool = config.currentTool;
733
+
734
+ const data = toolState.data[currentTool];
735
+ const coords = currentPoints.canvas;
736
+
737
+ // Set the mouseLocation handle
738
+ this._getMouseLocation(eventData);
739
+ this._checkInvalidHandleLocation(data, eventData);
740
+
741
+ // Mouse move -> Polygon Mode
742
+ const handleNearby = this._pointNearHandle(element, data, coords);
743
+ const points = data.handles.points;
744
+ // If there is a handle nearby to snap to
745
+ // (and it's not the actual mouse handle)
746
+
747
+ if (
748
+ handleNearby !== undefined &amp;&amp;
749
+ !handleNearby.hasBoundingBox &amp;&amp;
750
+ handleNearby &lt; points.length - 1
751
+ ) {
752
+ config.mouseLocation.handles.start.x = points[handleNearby].x;
753
+ config.mouseLocation.handles.start.y = points[handleNearby].y;
754
+ }
755
+
756
+ // Force onImageRendered
757
+ external.cornerstone.updateImage(element);
758
+ }
759
+
760
+ /**
761
+ * Event handler for MOUSE_DRAG during drawing event loop.
762
+ *
763
+ * @event
764
+ * @param {Object} evt - The event.
765
+ * @returns {undefined}
766
+ */
767
+ _drawingMouseDragCallback(evt) {
768
+ if (!this.options.mouseButtonMask.includes(evt.detail.buttons)) {
769
+ return;
770
+ }
771
+
772
+ this._drawingDrag(evt);
773
+ }
774
+
775
+ /**
776
+ * Event handler for TOUCH_DRAG during drawing event loop.
777
+ *
778
+ * @event
779
+ * @param {Object} evt - The event.
780
+ * @returns {undefined}
781
+ */
782
+ _drawingTouchDragCallback(evt) {
783
+ this._drawingDrag(evt);
784
+ }
785
+
786
+ _drawingDrag(evt) {
787
+ const eventData = evt.detail;
788
+ const { element } = eventData;
789
+
790
+ const toolState = getToolState(element, this.name);
791
+
792
+ const config = this.configuration;
793
+ const currentTool = config.currentTool;
794
+
795
+ const data = toolState.data[currentTool];
796
+
797
+ // Set the mouseLocation handle
798
+ this._getMouseLocation(eventData);
799
+ this._checkInvalidHandleLocation(data, eventData);
800
+ this._addPointPencilMode(eventData, data.handles.points);
801
+ this._dragging = true;
802
+
803
+ // Force onImageRendered
804
+ external.cornerstone.updateImage(element);
805
+ }
806
+
807
+ /**
808
+ * Event handler for MOUSE_UP during drawing event loop.
809
+ *
810
+ * @event
811
+ * @param {Object} evt - The event.
812
+ * @returns {undefined}
813
+ */
814
+ _drawingMouseUpCallback(evt) {
815
+ const { element } = evt.detail;
816
+
817
+ if (!this._dragging) {
818
+ return;
819
+ }
820
+
821
+ this._dragging = false;
822
+
823
+ const config = this.configuration;
824
+ const currentTool = config.currentTool;
825
+ const toolState = getToolState(element, this.name);
826
+ const data = toolState.data[currentTool];
827
+
828
+ if (!freehandIntersect.end(data.handles.points) &amp;&amp; data.canComplete) {
829
+ const lastHandlePlaced = config.currentHandle;
830
+
831
+ this._endDrawing(element, lastHandlePlaced);
832
+ }
833
+
834
+ preventPropagation(evt);
835
+
836
+ return;
837
+ }
838
+
839
+ /**
840
+ * Event handler for MOUSE_DOWN during drawing event loop.
841
+ *
842
+ * @event
843
+ * @param {Object} evt - The event.
844
+ * @returns {undefined}
845
+ */
846
+ _drawingMouseDownCallback(evt) {
847
+ const eventData = evt.detail;
848
+ const { buttons, currentPoints, element } = eventData;
849
+
850
+ if (!this.options.mouseButtonMask.includes(buttons)) {
851
+ return;
852
+ }
853
+
854
+ const coords = currentPoints.canvas;
855
+
856
+ const config = this.configuration;
857
+ const currentTool = config.currentTool;
858
+ const toolState = getToolState(element, this.name);
859
+ const data = toolState.data[currentTool];
860
+
861
+ const handleNearby = this._pointNearHandle(element, data, coords);
862
+
863
+ if (!freehandIntersect.end(data.handles.points) &amp;&amp; data.canComplete) {
864
+ const lastHandlePlaced = config.currentHandle;
865
+
866
+ this._endDrawing(element, lastHandlePlaced);
867
+ } else if (handleNearby === undefined) {
868
+ this._addPoint(eventData);
869
+ }
870
+
871
+ preventPropagation(evt);
872
+
873
+ return;
874
+ }
875
+
876
+ /**
877
+ * Event handler for TOUCH_START during drawing event loop.
878
+ *
879
+ * @event
880
+ * @param {Object} evt - The event.
881
+ * @returns {undefined}
882
+ */
883
+ _drawingTouchStartCallback(evt) {
884
+ const eventData = evt.detail;
885
+ const { currentPoints, element } = eventData;
886
+
887
+ const coords = currentPoints.canvas;
888
+
889
+ const config = this.configuration;
890
+ const currentTool = config.currentTool;
891
+ const toolState = getToolState(element, this.name);
892
+ const data = toolState.data[currentTool];
893
+
894
+ const handleNearby = this._pointNearHandle(element, data, coords);
895
+
896
+ if (!freehandIntersect.end(data.handles.points) &amp;&amp; data.canComplete) {
897
+ const lastHandlePlaced = config.currentHandle;
898
+
899
+ this._endDrawing(element, lastHandlePlaced);
900
+ } else if (handleNearby === undefined) {
901
+ this._addPoint(eventData);
902
+ }
903
+
904
+ preventPropagation(evt);
905
+
906
+ return;
907
+ }
908
+
909
+ /** Ends the active drawing loop and completes the polygon.
910
+ *
911
+ * @public
912
+ * @param {Object} element - The element on which the roi is being drawn.
913
+ * @returns {null}
914
+ */
915
+ completeDrawing(element) {
916
+ if (!this._drawing) {
917
+ return;
918
+ }
919
+ const toolState = getToolState(element, this.name);
920
+ const config = this.configuration;
921
+ const data = toolState.data[config.currentTool];
922
+
923
+ if (
924
+ !freehandIntersect.end(data.handles.points) &amp;&amp;
925
+ data.handles.points.length >= 2
926
+ ) {
927
+ const lastHandlePlaced = config.currentHandle;
928
+
929
+ data.polyBoundingBox = {};
930
+ this._endDrawing(element, lastHandlePlaced);
931
+ }
932
+ }
933
+
934
+ /**
935
+ * Event handler for MOUSE_DOUBLE_CLICK during drawing event loop.
936
+ *
937
+ * @event
938
+ * @param {Object} evt - The event.
939
+ * @returns {undefined}
940
+ */
941
+ _drawingMouseDoubleClickCallback(evt) {
942
+ const { element } = evt.detail;
943
+
944
+ this.completeDrawing(element);
945
+
946
+ preventPropagation(evt);
947
+ }
948
+
949
+ /**
950
+ * Event handler for DOUBLE_TAP during drawing event loop.
951
+ *
952
+ * @event
953
+ * @param {Object} evt - The event.
954
+ * @returns {undefined}
955
+ */
956
+ _drawingDoubleTapClickCallback(evt) {
957
+ const { element } = evt.detail;
958
+
959
+ this.completeDrawing(element);
960
+
961
+ preventPropagation(evt);
962
+ }
963
+
964
+ /**
965
+ * Event handler for MOUSE_DRAG during handle drag event loop.
966
+ *
967
+ * @event
968
+ * @param {Object} evt - The event.
969
+ * @returns {undefined}
970
+ */
971
+ _editMouseDragCallback(evt) {
972
+ const eventData = evt.detail;
973
+ const { element, buttons } = eventData;
974
+
975
+ if (!this.options.mouseButtonMask.includes(buttons)) {
976
+ return;
977
+ }
978
+
979
+ const toolState = getToolState(element, this.name);
980
+
981
+ const config = this.configuration;
982
+ const data = toolState.data[config.currentTool];
983
+ const currentHandle = config.currentHandle;
984
+ const points = data.handles.points;
985
+ let handleIndex = -1;
986
+
987
+ // Set the mouseLocation handle
988
+ this._getMouseLocation(eventData);
989
+
990
+ data.handles.invalidHandlePlacement = freehandIntersect.modify(
991
+ points,
992
+ currentHandle
993
+ );
994
+ data.active = true;
995
+ data.highlight = true;
996
+ points[currentHandle].x = config.mouseLocation.handles.start.x;
997
+ points[currentHandle].y = config.mouseLocation.handles.start.y;
998
+
999
+ handleIndex = this._getPrevHandleIndex(currentHandle, points);
1000
+
1001
+ if (currentHandle >= 0) {
1002
+ const lastLineIndex = points[handleIndex].lines.length - 1;
1003
+ const lastLine = points[handleIndex].lines[lastLineIndex];
1004
+
1005
+ lastLine.x = config.mouseLocation.handles.start.x;
1006
+ lastLine.y = config.mouseLocation.handles.start.y;
1007
+ }
1008
+
1009
+ // Update the image
1010
+ external.cornerstone.updateImage(element);
1011
+ }
1012
+
1013
+ /**
1014
+ * Event handler for TOUCH_DRAG during handle drag event loop.
1015
+ *
1016
+ * @event
1017
+ * @param {Object} evt - The event.
1018
+ * @returns {void}
1019
+ */
1020
+ _editTouchDragCallback(evt) {
1021
+ const eventData = evt.detail;
1022
+ const { element } = eventData;
1023
+
1024
+ const toolState = getToolState(element, this.name);
1025
+
1026
+ const config = this.configuration;
1027
+ const data = toolState.data[config.currentTool];
1028
+ const currentHandle = config.currentHandle;
1029
+ const points = data.handles.points;
1030
+ let handleIndex = -1;
1031
+
1032
+ // Set the mouseLocation handle
1033
+ this._getMouseLocation(eventData);
1034
+
1035
+ data.handles.invalidHandlePlacement = freehandIntersect.modify(
1036
+ points,
1037
+ currentHandle
1038
+ );
1039
+ data.active = true;
1040
+ data.highlight = true;
1041
+ points[currentHandle].x = config.mouseLocation.handles.start.x;
1042
+ points[currentHandle].y = config.mouseLocation.handles.start.y;
1043
+
1044
+ handleIndex = this._getPrevHandleIndex(currentHandle, points);
1045
+
1046
+ if (currentHandle >= 0) {
1047
+ const lastLineIndex = points[handleIndex].lines.length - 1;
1048
+ const lastLine = points[handleIndex].lines[lastLineIndex];
1049
+
1050
+ lastLine.x = config.mouseLocation.handles.start.x;
1051
+ lastLine.y = config.mouseLocation.handles.start.y;
1052
+ }
1053
+
1054
+ // Update the image
1055
+ external.cornerstone.updateImage(element);
1056
+ }
1057
+
1058
+ /**
1059
+ * Returns the previous handle to the current one.
1060
+ * @param {Number} currentHandle - the current handle index
1061
+ * @param {Array} points - the handles Array of the freehand data
1062
+ * @returns {Number} - The index of the previos handle
1063
+ */
1064
+ _getPrevHandleIndex(currentHandle, points) {
1065
+ if (currentHandle === 0) {
1066
+ return points.length - 1;
1067
+ }
1068
+
1069
+ return currentHandle - 1;
1070
+ }
1071
+
1072
+ /**
1073
+ * Event handler for MOUSE_UP during handle drag event loop.
1074
+ *
1075
+ * @private
1076
+ * @param {Object} evt - The event.
1077
+ * @returns {undefined}
1078
+ */
1079
+ _editMouseUpCallback(evt) {
1080
+ const eventData = evt.detail;
1081
+ const { element } = eventData;
1082
+ const toolState = getToolState(element, this.name);
1083
+
1084
+ this._deactivateModify(element);
1085
+
1086
+ this._dropHandle(eventData, toolState);
1087
+ this._endDrawing(element);
1088
+
1089
+ external.cornerstone.updateImage(element);
1090
+ }
1091
+
1092
+ /**
1093
+ * Places a handle of the freehand tool if the new location is valid.
1094
+ * If the new location is invalid the handle snaps back to its previous position.
1095
+ *
1096
+ * @private
1097
+ * @param {Object} eventData - Data object associated with the event.
1098
+ * @param {Object} toolState - The data associated with the freehand tool.
1099
+ * @modifies {toolState}
1100
+ * @returns {undefined}
1101
+ */
1102
+ _dropHandle(eventData, toolState) {
1103
+ const config = this.configuration;
1104
+ const currentTool = config.currentTool;
1105
+ const handles = toolState.data[currentTool].handles;
1106
+ const points = handles.points;
1107
+
1108
+ // Don't allow the line being modified to intersect other lines
1109
+ if (handles.invalidHandlePlacement) {
1110
+ const currentHandle = config.currentHandle;
1111
+ const currentHandleData = points[currentHandle];
1112
+ let previousHandleData;
1113
+
1114
+ if (currentHandle === 0) {
1115
+ const lastHandleID = points.length - 1;
1116
+
1117
+ previousHandleData = points[lastHandleID];
1118
+ } else {
1119
+ previousHandleData = points[currentHandle - 1];
1120
+ }
1121
+
1122
+ // Snap back to previous position
1123
+ currentHandleData.x = config.dragOrigin.x;
1124
+ currentHandleData.y = config.dragOrigin.y;
1125
+ previousHandleData.lines[0] = currentHandleData;
1126
+
1127
+ handles.invalidHandlePlacement = false;
1128
+ }
1129
+ }
1130
+
1131
+ /**
1132
+ * Begining of drawing loop when tool is active and a click event happens far
1133
+ * from existing handles.
1134
+ *
1135
+ * @private
1136
+ * @param {Object} evt - The event.
1137
+ * @returns {undefined}
1138
+ */
1139
+ _startDrawing(evt) {
1140
+ const eventData = evt.detail;
1141
+ const measurementData = this.createNewMeasurement(eventData);
1142
+ const { element } = eventData;
1143
+ const config = this.configuration;
1144
+ let interactionType;
1145
+
1146
+ if (evt.type === EVENTS.MOUSE_DOWN_ACTIVATE) {
1147
+ interactionType = "Mouse";
1148
+ } else if (evt.type === EVENTS.TOUCH_START_ACTIVE) {
1149
+ interactionType = "Touch";
1150
+ }
1151
+ this._activateDraw(element, interactionType);
1152
+ this._getMouseLocation(eventData);
1153
+
1154
+ addToolState(element, this.name, measurementData);
1155
+
1156
+ const toolState = getToolState(element, this.name);
1157
+
1158
+ config.currentTool = toolState.data.length - 1;
1159
+
1160
+ this._activeDrawingToolReference = toolState.data[config.currentTool];
1161
+ }
1162
+
1163
+ /**
1164
+ * Adds a point on mouse click in polygon mode.
1165
+ *
1166
+ * @private
1167
+ * @param {Object} eventData - data object associated with an event.
1168
+ * @returns {undefined}
1169
+ */
1170
+ _addPoint(eventData) {
1171
+ const { currentPoints, element } = eventData;
1172
+ const toolState = getToolState(element, this.name);
1173
+
1174
+ // Get the toolState from the last-drawn polygon
1175
+ const config = this.configuration;
1176
+ const data = toolState.data[config.currentTool];
1177
+
1178
+ if (data.handles.invalidHandlePlacement) {
1179
+ return;
1180
+ }
1181
+
1182
+ const newHandleData = new FreehandHandleData(currentPoints.image);
1183
+
1184
+ // If this is not the first handle
1185
+ if (data.handles.points.length) {
1186
+ // Add the line from the current handle to the new handle
1187
+ data.handles.points[config.currentHandle - 1].lines.push(
1188
+ currentPoints.image
1189
+ );
1190
+ }
1191
+
1192
+ // Add the new handle
1193
+ data.handles.points.push(newHandleData);
1194
+
1195
+ // Increment the current handle value
1196
+ config.currentHandle += 1;
1197
+
1198
+ // Force onImageRendered to fire
1199
+ external.cornerstone.updateImage(element);
1200
+ this.fireModifiedEvent(element, data);
1201
+ }
1202
+
1203
+ /**
1204
+ * If in pencilMode, check the mouse position is farther than the minimum
1205
+ * distance between points, then add a point.
1206
+ *
1207
+ * @private
1208
+ * @param {Object} eventData - Data object associated with an event.
1209
+ * @param {Object} points - Data object associated with the tool.
1210
+ * @returns {undefined}
1211
+ */
1212
+ _addPointPencilMode(eventData, points) {
1213
+ const config = this.configuration;
1214
+ const { element } = eventData;
1215
+ const mousePoint = config.mouseLocation.handles.start;
1216
+
1217
+ const handleFurtherThanMinimumSpacing = handle =>
1218
+ this._isDistanceLargerThanSpacing(element, handle, mousePoint);
1219
+
1220
+ if (points.every(handleFurtherThanMinimumSpacing)) {
1221
+ this._addPoint(eventData);
1222
+ }
1223
+ }
1224
+
1225
+ /**
1226
+ * Ends the active drawing loop and completes the polygon.
1227
+ *
1228
+ * @private
1229
+ * @param {Object} element - The element on which the roi is being drawn.
1230
+ * @param {Object} handleNearby - the handle nearest to the mouse cursor.
1231
+ * @returns {undefined}
1232
+ */
1233
+ _endDrawing(element, handleNearby) {
1234
+ const toolState = getToolState(element, this.name);
1235
+ const config = this.configuration;
1236
+ const data = toolState.data[config.currentTool];
1237
+
1238
+ data.active = false;
1239
+ data.highlight = false;
1240
+ data.handles.invalidHandlePlacement = false;
1241
+
1242
+ // Connect the end handle to the origin handle
1243
+ if (handleNearby !== undefined) {
1244
+ const points = data.handles.points;
1245
+
1246
+ points[config.currentHandle - 1].lines.push(points[0]);
1247
+ }
1248
+
1249
+ if (this._modifying) {
1250
+ this._modifying = false;
1251
+ data.invalidated = true;
1252
+ }
1253
+
1254
+ // Reset the current handle
1255
+ config.currentHandle = 0;
1256
+ config.currentTool = -1;
1257
+ data.canComplete = false;
1258
+
1259
+ if (this._drawing) {
1260
+ this._deactivateDraw(element);
1261
+ }
1262
+
1263
+ external.cornerstone.updateImage(element);
1264
+
1265
+ this.fireModifiedEvent(element, data);
1266
+ this.fireCompletedEvent(element, data);
1267
+ }
1268
+
1269
+ /**
1270
+ * Returns a handle of a particular tool if it is close to the mouse cursor
1271
+ *
1272
+ * @private
1273
+ * @param {Object} element - The element on which the roi is being drawn.
1274
+ * @param {Object} data Data object associated with the tool.
1275
+ * @param {*} coords
1276
+ * @returns {Number|Object|Boolean}
1277
+ */
1278
+ _pointNearHandle(element, data, coords) {
1279
+ if (data.handles === undefined || data.handles.points === undefined) {
1280
+ return;
1281
+ }
1282
+
1283
+ if (data.visible === false) {
1284
+ return;
1285
+ }
1286
+
1287
+ for (let i = 0; i &lt; data.handles.points.length; i++) {
1288
+ const handleCanvas = external.cornerstone.pixelToCanvas(
1289
+ element,
1290
+ data.handles.points[i]
1291
+ );
1292
+
1293
+ if (external.cornerstoneMath.point.distance(handleCanvas, coords) &lt; 6) {
1294
+ return i;
1295
+ }
1296
+ }
1297
+
1298
+ // Check to see if mouse in bounding box of textbox
1299
+ if (data.handles.textBox) {
1300
+ if (pointInsideBoundingBox(data.handles.textBox, coords)) {
1301
+ return data.handles.textBox;
1302
+ }
1303
+ }
1304
+ }
1305
+
1306
+ /**
1307
+ * Returns a handle if it is close to the mouse cursor (all tools)
1308
+ *
1309
+ * @private
1310
+ * @param {Object} eventData - data object associated with an event.
1311
+ * @returns {Object}
1312
+ */
1313
+ _pointNearHandleAllTools(eventData) {
1314
+ const { currentPoints, element } = eventData;
1315
+ const coords = currentPoints.canvas;
1316
+ const toolState = getToolState(element, this.name);
1317
+
1318
+ if (!toolState) {
1319
+ return;
1320
+ }
1321
+
1322
+ let handleNearby;
1323
+
1324
+ for (let toolIndex = 0; toolIndex &lt; toolState.data.length; toolIndex++) {
1325
+ handleNearby = this._pointNearHandle(
1326
+ element,
1327
+ toolState.data[toolIndex],
1328
+ coords
1329
+ );
1330
+ if (handleNearby !== undefined) {
1331
+ return {
1332
+ handleNearby,
1333
+ toolIndex
1334
+ };
1335
+ }
1336
+ }
1337
+ }
1338
+
1339
+ /**
1340
+ * Gets the current mouse location and stores it in the configuration object.
1341
+ *
1342
+ * @private
1343
+ * @param {Object} eventData The data assoicated with the event.
1344
+ * @returns {undefined}
1345
+ */
1346
+ _getMouseLocation(eventData) {
1347
+ const { currentPoints, image } = eventData;
1348
+ // Set the mouseLocation handle
1349
+ const config = this.configuration;
1350
+
1351
+ config.mouseLocation.handles.start.x = currentPoints.image.x;
1352
+ config.mouseLocation.handles.start.y = currentPoints.image.y;
1353
+ clipToBox(config.mouseLocation.handles.start, image);
1354
+ }
1355
+
1356
+ /**
1357
+ * Returns true if the proposed location of a new handle is invalid.
1358
+ *
1359
+ * @private
1360
+ * @param {Object} data Data object associated with the tool.
1361
+ * @param {Object} eventData The data assoicated with the event.
1362
+ * @returns {Boolean}
1363
+ */
1364
+ _checkInvalidHandleLocation(data, eventData) {
1365
+ if (data.handles.points.length &lt; 2) {
1366
+ return true;
1367
+ }
1368
+
1369
+ let invalidHandlePlacement;
1370
+
1371
+ if (this._dragging) {
1372
+ invalidHandlePlacement = this._checkHandlesPencilMode(data, eventData);
1373
+ } else {
1374
+ invalidHandlePlacement = this._checkHandlesPolygonMode(data, eventData);
1375
+ }
1376
+
1377
+ data.handles.invalidHandlePlacement = invalidHandlePlacement;
1378
+ }
1379
+
1380
+ /**
1381
+ * Returns true if the proposed location of a new handle is invalid (in polygon mode).
1382
+ *
1383
+ * @private
1384
+ *
1385
+ * @param {Object} data - data object associated with the tool.
1386
+ * @param {Object} eventData The data assoicated with the event.
1387
+ * @returns {Boolean}
1388
+ */
1389
+ _checkHandlesPolygonMode(data, eventData) {
1390
+ const config = this.configuration;
1391
+ const { element } = eventData;
1392
+ const mousePoint = config.mouseLocation.handles.start;
1393
+ const points = data.handles.points;
1394
+ let invalidHandlePlacement = false;
1395
+
1396
+ data.canComplete = false;
1397
+
1398
+ const mouseAtOriginHandle = this._isDistanceSmallerThanCompleteSpacingCanvas(
1399
+ element,
1400
+ points[0],
1401
+ mousePoint
1402
+ );
1403
+
1404
+ if (
1405
+ mouseAtOriginHandle &amp;&amp;
1406
+ !freehandIntersect.end(points) &amp;&amp;
1407
+ points.length > 2
1408
+ ) {
1409
+ data.canComplete = true;
1410
+ invalidHandlePlacement = false;
1411
+ } else {
1412
+ invalidHandlePlacement = freehandIntersect.newHandle(mousePoint, points);
1413
+ }
1414
+
1415
+ return invalidHandlePlacement;
1416
+ }
1417
+
1418
+ /**
1419
+ * Returns true if the proposed location of a new handle is invalid (in pencilMode).
1420
+ *
1421
+ * @private
1422
+ * @param {Object} data - data object associated with the tool.
1423
+ * @param {Object} eventData The data associated with the event.
1424
+ * @returns {Boolean}
1425
+ */
1426
+ _checkHandlesPencilMode(data, eventData) {
1427
+ const config = this.configuration;
1428
+ const mousePoint = config.mouseLocation.handles.start;
1429
+ const points = data.handles.points;
1430
+ let invalidHandlePlacement = freehandIntersect.newHandle(
1431
+ mousePoint,
1432
+ points
1433
+ );
1434
+
1435
+ if (invalidHandlePlacement === false) {
1436
+ invalidHandlePlacement = this._invalidHandlePencilMode(data, eventData);
1437
+ }
1438
+
1439
+ return invalidHandlePlacement;
1440
+ }
1441
+
1442
+ /**
1443
+ * Returns true if the mouse position is far enough from previous points (in pencilMode).
1444
+ *
1445
+ * @private
1446
+ * @param {Object} data - data object associated with the tool.
1447
+ * @param {Object} eventData The data associated with the event.
1448
+ * @returns {Boolean}
1449
+ */
1450
+ _invalidHandlePencilMode(data, eventData) {
1451
+ const config = this.configuration;
1452
+ const { element } = eventData;
1453
+ const mousePoint = config.mouseLocation.handles.start;
1454
+ const points = data.handles.points;
1455
+
1456
+ const mouseAtOriginHandle = this._isDistanceSmallerThanCompleteSpacingCanvas(
1457
+ element,
1458
+ points[0],
1459
+ mousePoint
1460
+ );
1461
+
1462
+ if (mouseAtOriginHandle) {
1463
+ data.canComplete = true;
1464
+
1465
+ return false;
1466
+ }
1467
+
1468
+ data.canComplete = false;
1469
+
1470
+ // Compare with all other handles appart from the last one
1471
+ for (let i = 1; i &lt; points.length - 1; i++) {
1472
+ if (this._isDistanceSmallerThanSpacing(element, points[i], mousePoint)) {
1473
+ return true;
1474
+ }
1475
+ }
1476
+
1477
+ return false;
1478
+ }
1479
+
1480
+ /**
1481
+ * Returns true if two points are closer than this.configuration.spacing.
1482
+ *
1483
+ * @private
1484
+ * @param {Object} element The element on which the roi is being drawn.
1485
+ * @param {Object} p1 The first point, in pixel space.
1486
+ * @param {Object} p2 The second point, in pixel space.
1487
+ * @returns {boolean} True if the distance is smaller than the
1488
+ * allowed canvas spacing.
1489
+ */
1490
+ _isDistanceSmallerThanCompleteSpacingCanvas(element, p1, p2) {
1491
+ const p1Canvas = external.cornerstone.pixelToCanvas(element, p1);
1492
+ const p2Canvas = external.cornerstone.pixelToCanvas(element, p2);
1493
+
1494
+ let completeHandleRadius;
1495
+
1496
+ if (this._drawingInteractionType === "Mouse") {
1497
+ completeHandleRadius = this.configuration.completeHandleRadius;
1498
+ } else if (this._drawingInteractionType === "Touch") {
1499
+ completeHandleRadius = this.configuration.completeHandleRadiusTouch;
1500
+ }
1501
+
1502
+ return this._compareDistanceToSpacing(
1503
+ element,
1504
+ p1Canvas,
1505
+ p2Canvas,
1506
+ "&lt;",
1507
+ completeHandleRadius
1508
+ );
1509
+ }
1510
+
1511
+ /**
1512
+ * Returns true if two points are closer than this.configuration.spacing.
1513
+ *
1514
+ * @private
1515
+ * @param {Object} element The element on which the roi is being drawn.
1516
+ * @param {Object} p1 The first point, in pixel space.
1517
+ * @param {Object} p2 The second point, in pixel space.
1518
+ * @returns {boolean} True if the distance is smaller than the
1519
+ * allowed canvas spacing.
1520
+ */
1521
+ _isDistanceSmallerThanSpacing(element, p1, p2) {
1522
+ return this._compareDistanceToSpacing(element, p1, p2, "&lt;");
1523
+ }
1524
+
1525
+ /**
1526
+ * Returns true if two points are farther than this.configuration.spacing.
1527
+ *
1528
+ * @private
1529
+ * @param {Object} element The element on which the roi is being drawn.
1530
+ * @param {Object} p1 The first point, in pixel space.
1531
+ * @param {Object} p2 The second point, in pixel space.
1532
+ * @returns {boolean} True if the distance is smaller than the
1533
+ * allowed canvas spacing.
1534
+ */
1535
+ _isDistanceLargerThanSpacing(element, p1, p2) {
1536
+ return this._compareDistanceToSpacing(element, p1, p2, ">");
1537
+ }
1538
+
1539
+ /**
1540
+ * Compares the distance between two points to this.configuration.spacing.
1541
+ *
1542
+ * @private
1543
+ * @param {Object} element The element on which the roi is being drawn.
1544
+ * @param {Object} p1 The first point, in pixel space.
1545
+ * @param {Object} p2 The second point, in pixel space.
1546
+ * @param {string} comparison The comparison to make.
1547
+ * @param {number} spacing The allowed canvas spacing
1548
+ * @returns {boolean} True if the distance is smaller than the
1549
+ * allowed canvas spacing.
1550
+ */
1551
+ _compareDistanceToSpacing(
1552
+ element,
1553
+ p1,
1554
+ p2,
1555
+ comparison = ">",
1556
+ spacing = this.configuration.spacing
1557
+ ) {
1558
+ if (comparison === ">") {
1559
+ return external.cornerstoneMath.point.distance(p1, p2) > spacing;
1560
+ }
1561
+
1562
+ return external.cornerstoneMath.point.distance(p1, p2) &lt; spacing;
1563
+ }
1564
+
1565
+ /**
1566
+ * Adds drawing loop event listeners.
1567
+ *
1568
+ * @private
1569
+ * @param {Object} element - The viewport element to add event listeners to.
1570
+ * @param {string} interactionType - The interactionType used for the loop.
1571
+ * @modifies {element}
1572
+ * @returns {undefined}
1573
+ */
1574
+ _activateDraw(element, interactionType = "Mouse") {
1575
+ this._drawing = true;
1576
+ this._drawingInteractionType = interactionType;
1577
+
1578
+ state.isMultiPartToolActive = true;
1579
+ // hideToolCursor(this.element);
1580
+
1581
+ // Polygonal Mode
1582
+ element.addEventListener(EVENTS.MOUSE_DOWN, this._drawingMouseDownCallback);
1583
+ element.addEventListener(EVENTS.MOUSE_MOVE, this._drawingMouseMoveCallback);
1584
+ element.addEventListener(
1585
+ EVENTS.MOUSE_DOUBLE_CLICK,
1586
+ this._drawingMouseDoubleClickCallback
1587
+ );
1588
+
1589
+ // Drag/Pencil Mode
1590
+ element.addEventListener(EVENTS.MOUSE_DRAG, this._drawingMouseDragCallback);
1591
+ element.addEventListener(EVENTS.MOUSE_UP, this._drawingMouseUpCallback);
1592
+
1593
+ // Touch
1594
+ element.addEventListener(
1595
+ EVENTS.TOUCH_START,
1596
+ this._drawingMouseMoveCallback
1597
+ );
1598
+ element.addEventListener(
1599
+ EVENTS.TOUCH_START,
1600
+ this._drawingTouchStartCallback
1601
+ );
1602
+
1603
+ element.addEventListener(EVENTS.TOUCH_DRAG, this._drawingTouchDragCallback);
1604
+ element.addEventListener(EVENTS.TOUCH_END, this._drawingMouseUpCallback);
1605
+ element.addEventListener(
1606
+ EVENTS.DOUBLE_TAP,
1607
+ this._drawingDoubleTapClickCallback
1608
+ );
1609
+
1610
+ external.cornerstone.updateImage(element);
1611
+ }
1612
+
1613
+ /**
1614
+ * Removes drawing loop event listeners.
1615
+ *
1616
+ * @private
1617
+ * @param {Object} element - The viewport element to add event listeners to.
1618
+ * @modifies {element}
1619
+ * @returns {undefined}
1620
+ */
1621
+ _deactivateDraw(element) {
1622
+ this._drawing = false;
1623
+ state.isMultiPartToolActive = false;
1624
+ this._activeDrawingToolReference = null;
1625
+ this._drawingInteractionType = null;
1626
+ // setToolCursor(this.element, this.svgCursor);
1627
+
1628
+ element.removeEventListener(
1629
+ EVENTS.MOUSE_DOWN,
1630
+ this._drawingMouseDownCallback
1631
+ );
1632
+ element.removeEventListener(
1633
+ EVENTS.MOUSE_MOVE,
1634
+ this._drawingMouseMoveCallback
1635
+ );
1636
+ element.removeEventListener(
1637
+ EVENTS.MOUSE_DOUBLE_CLICK,
1638
+ this._drawingMouseDoubleClickCallback
1639
+ );
1640
+ element.removeEventListener(
1641
+ EVENTS.MOUSE_DRAG,
1642
+ this._drawingMouseDragCallback
1643
+ );
1644
+ element.removeEventListener(EVENTS.MOUSE_UP, this._drawingMouseUpCallback);
1645
+
1646
+ // Touch
1647
+ element.removeEventListener(
1648
+ EVENTS.TOUCH_START,
1649
+ this._drawingTouchStartCallback
1650
+ );
1651
+ element.removeEventListener(
1652
+ EVENTS.TOUCH_DRAG,
1653
+ this._drawingTouchDragCallback
1654
+ );
1655
+ element.removeEventListener(
1656
+ EVENTS.TOUCH_START,
1657
+ this._drawingMouseMoveCallback
1658
+ );
1659
+ element.removeEventListener(EVENTS.TOUCH_END, this._drawingMouseUpCallback);
1660
+
1661
+ external.cornerstone.updateImage(element);
1662
+ }
1663
+
1664
+ /**
1665
+ * Adds modify loop event listeners.
1666
+ *
1667
+ * @private
1668
+ * @param {Object} element - The viewport element to add event listeners to.
1669
+ * @modifies {element}
1670
+ * @returns {undefined}
1671
+ */
1672
+ _activateModify(element) {
1673
+ state.isToolLocked = true;
1674
+
1675
+ element.addEventListener(EVENTS.MOUSE_UP, this._editMouseUpCallback);
1676
+ element.addEventListener(EVENTS.MOUSE_DRAG, this._editMouseDragCallback);
1677
+ element.addEventListener(EVENTS.MOUSE_CLICK, this._editMouseUpCallback);
1678
+
1679
+ element.addEventListener(EVENTS.TOUCH_END, this._editMouseUpCallback);
1680
+ element.addEventListener(EVENTS.TOUCH_DRAG, this._editTouchDragCallback);
1681
+
1682
+ external.cornerstone.updateImage(element);
1683
+ }
1684
+
1685
+ /**
1686
+ * Removes modify loop event listeners.
1687
+ *
1688
+ * @private
1689
+ * @param {Object} element - The viewport element to add event listeners to.
1690
+ * @modifies {element}
1691
+ * @returns {undefined}
1692
+ */
1693
+ _deactivateModify(element) {
1694
+ state.isToolLocked = false;
1695
+
1696
+ element.removeEventListener(EVENTS.MOUSE_UP, this._editMouseUpCallback);
1697
+ element.removeEventListener(EVENTS.MOUSE_DRAG, this._editMouseDragCallback);
1698
+ element.removeEventListener(EVENTS.MOUSE_CLICK, this._editMouseUpCallback);
1699
+
1700
+ element.removeEventListener(EVENTS.TOUCH_END, this._editMouseUpCallback);
1701
+ element.removeEventListener(EVENTS.TOUCH_DRAG, this._editTouchDragCallback);
1702
+
1703
+ external.cornerstone.updateImage(element);
1704
+ }
1705
+
1706
+ passiveCallback(element) {
1707
+ this._closeToolIfDrawing(element);
1708
+ }
1709
+
1710
+ enabledCallback(element) {
1711
+ this._closeToolIfDrawing(element);
1712
+ }
1713
+
1714
+ disabledCallback(element) {
1715
+ this._closeToolIfDrawing(element);
1716
+ }
1717
+
1718
+ _closeToolIfDrawing(element) {
1719
+ if (this._drawing) {
1720
+ // Actively drawing but changed mode.
1721
+ const config = this.configuration;
1722
+ const lastHandlePlaced = config.currentHandle;
1723
+
1724
+ this._endDrawing(element, lastHandlePlaced);
1725
+ external.cornerstone.updateImage(element);
1726
+ }
1727
+ }
1728
+
1729
+ /**
1730
+ * Fire MEASUREMENT_MODIFIED event on provided element
1731
+ * @param {any} element which freehand data has been modified
1732
+ * @param {any} measurementData the measurment data
1733
+ * @returns {void}
1734
+ */
1735
+ fireModifiedEvent(element, measurementData) {
1736
+ const eventType = EVENTS.MEASUREMENT_MODIFIED;
1737
+ const eventData = {
1738
+ toolName: this.name,
1739
+ element,
1740
+ measurementData
1741
+ };
1742
+
1743
+ triggerEvent(element, eventType, eventData);
1744
+ }
1745
+
1746
+ fireCompletedEvent(element, measurementData) {
1747
+ const eventType = EVENTS.MEASUREMENT_COMPLETED;
1748
+ const eventData = {
1749
+ toolName: this.name,
1750
+ element,
1751
+ measurementData
1752
+ };
1753
+
1754
+ triggerEvent(element, eventType, eventData);
1755
+ }
1756
+
1757
+ // ===================================================================
1758
+ // Public Configuration API. .
1759
+ // ===================================================================
1760
+
1761
+ get spacing() {
1762
+ return this.configuration.spacing;
1763
+ }
1764
+
1765
+ set spacing(value) {
1766
+ if (typeof value !== "number") {
1767
+ throw new Error(
1768
+ "Attempting to set freehand spacing to a value other than a number."
1769
+ );
1770
+ }
1771
+
1772
+ this.configuration.spacing = value;
1773
+ external.cornerstone.updateImage(this.element);
1774
+ }
1775
+
1776
+ get activeHandleRadius() {
1777
+ return this.configuration.activeHandleRadius;
1778
+ }
1779
+
1780
+ set activeHandleRadius(value) {
1781
+ if (typeof value !== "number") {
1782
+ throw new Error(
1783
+ "Attempting to set freehand activeHandleRadius to a value other than a number."
1784
+ );
1785
+ }
1786
+
1787
+ this.configuration.activeHandleRadius = value;
1788
+ external.cornerstone.updateImage(this.element);
1789
+ }
1790
+
1791
+ get completeHandleRadius() {
1792
+ return this.configuration.completeHandleRadius;
1793
+ }
1794
+
1795
+ set completeHandleRadius(value) {
1796
+ if (typeof value !== "number") {
1797
+ throw new Error(
1798
+ "Attempting to set freehand completeHandleRadius to a value other than a number."
1799
+ );
1800
+ }
1801
+
1802
+ this.configuration.completeHandleRadius = value;
1803
+ external.cornerstone.updateImage(this.element);
1804
+ }
1805
+
1806
+ get alwaysShowHandles() {
1807
+ return this.configuration.alwaysShowHandles;
1808
+ }
1809
+
1810
+ set alwaysShowHandles(value) {
1811
+ if (typeof value !== "boolean") {
1812
+ throw new Error(
1813
+ "Attempting to set freehand alwaysShowHandles to a value other than a boolean."
1814
+ );
1815
+ }
1816
+
1817
+ this.configuration.alwaysShowHandles = value;
1818
+ external.cornerstone.updateImage(this.element);
1819
+ }
1820
+
1821
+ get invalidColor() {
1822
+ return this.configuration.invalidColor;
1823
+ }
1824
+
1825
+ set invalidColor(value) {
1826
+ /*
1827
+ It'd be easy to check if the color was e.g. a valid rgba color. However
1828
+ it'd be difficult to check if the color was a named CSS color without
1829
+ bloating the library, so we don't. If the canvas can't intepret the color
1830
+ it'll show up grey.
1831
+ */
1832
+
1833
+ this.configuration.invalidColor = value;
1834
+ external.cornerstone.updateImage(this.element);
1835
+ }
1836
+
1837
+ /**
1838
+ * Ends the active drawing loop and removes the polygon.
1839
+ *
1840
+ * @public
1841
+ * @param {Object} element - The element on which the roi is being drawn.
1842
+ * @returns {null}
1843
+ */
1844
+ cancelDrawing(element) {
1845
+ if (!this._drawing) {
1846
+ return;
1847
+ }
1848
+ const toolState = getToolState(element, this.name);
1849
+
1850
+ const config = this.configuration;
1851
+
1852
+ const data = toolState.data[config.currentTool];
1853
+
1854
+ data.active = false;
1855
+ data.highlight = false;
1856
+ data.handles.invalidHandlePlacement = false;
1857
+
1858
+ // Reset the current handle
1859
+ config.currentHandle = 0;
1860
+ config.currentTool = -1;
1861
+ data.canComplete = false;
1862
+
1863
+ removeToolState(element, this.name, data);
1864
+
1865
+ this._deactivateDraw(element);
1866
+
1867
+ external.cornerstone.updateImage(element);
1868
+ }
1869
+
1870
+ /**
1871
+ * New image event handler.
1872
+ *
1873
+ * @public
1874
+ * @param {Object} evt The event.
1875
+ * @returns {null}
1876
+ */
1877
+ newImageCallback(evt) {
1878
+ const config = this.configuration;
1879
+
1880
+ if (!(this._drawing &amp;&amp; this._activeDrawingToolReference)) {
1881
+ return;
1882
+ }
1883
+
1884
+ // Actively drawing but scrolled to different image.
1885
+
1886
+ const element = evt.detail.element;
1887
+ const data = this._activeDrawingToolReference;
1888
+
1889
+ data.active = false;
1890
+ data.highlight = false;
1891
+ data.handles.invalidHandlePlacement = false;
1892
+
1893
+ // Connect the end handle to the origin handle
1894
+ const points = data.handles.points;
1895
+
1896
+ points[config.currentHandle - 1].lines.push(points[0]);
1897
+
1898
+ // Reset the current handle
1899
+ config.currentHandle = 0;
1900
+ config.currentTool = -1;
1901
+ data.canComplete = false;
1902
+
1903
+ this._deactivateDraw(element);
1904
+
1905
+ external.cornerstone.updateImage(element);
1906
+ }
1907
+ }
1908
+
1909
+ function defaultFreehandConfiguration() {
1910
+ return {
1911
+ mouseLocation: {
1912
+ handles: {
1913
+ start: {
1914
+ highlight: false,
1915
+ active: false
1916
+ }
1917
+ }
1918
+ },
1919
+ spacing: 1,
1920
+ activeHandleRadius: 3,
1921
+ completeHandleRadius: 6,
1922
+ completeHandleRadiusTouch: 28,
1923
+ alwaysShowHandles: false,
1924
+ invalidColor: "#FFFF00",
1925
+ currentHandle: 0,
1926
+ currentTool: -1
1927
+ };
1928
+ }
1929
+
1930
+ function preventPropagation(evt) {
1931
+ evt.stopImmediatePropagation();
1932
+ evt.stopPropagation();
1933
+ evt.preventDefault();
1934
+ }
1935
+ </code></pre>
1936
+ </article>
1937
+ </section>
1938
+
1939
+
1940
+
1941
+
1942
+
1943
+
1944
+ </div>
1945
+
1946
+ <br class="clear">
1947
+
1948
+ <footer>
1949
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.7</a> using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
1950
+ </footer>
1951
+
1952
+ <script>prettyPrint();</script>
1953
+ <script src="scripts/polyfill.js"></script>
1954
+ <script src="scripts/linenumber.js"></script>
1955
+
1956
+ <script src="scripts/search.js" defer></script>
1957
+
1958
+
1959
+ <script src="scripts/collapse.js" defer></script>
1960
+
1961
+
1962
+ </body>
1963
+ </html>