You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2 lines
20 KiB
2 lines
20 KiB
document.addEventListener("DOMContentLoaded",onDOMContentLoaded);let _app=null,_tools=null,_layout="one";function viewerSetup(){dwv.logger.level=dwv.logger.levels.INFO,dwv.decoderScripts.jpeg2000="./decoders/pdfjs/decode-jpeg2000.js",dwv.decoderScripts["jpeg-lossless"]="./decoders/rii-mango/decode-jpegloss.js",dwv.decoderScripts["jpeg-baseline"]="./decoders/pdfjs/decode-jpegbaseline.js",dwv.decoderScripts.rle="./decoders/dwv/decode-rle.js",dwv.defaultPresets.PT={"suv5-10":{center:5,width:10},"suv6-8":{center:6,width:8}};let e=!0;"one"===_layout?addLayerGroups(1):"side"===_layout?addLayerGroups(2):"mpr"===_layout&&(e=!1,addLayerGroups(3)),_tools={Scroll:{},WindowLevel:{},ZoomAndPan:{},Opacity:{},Draw:{options:["Ruler","Circle"]}};const t=new dwv.AppOptions;t.tools=_tools,t.viewOnFirstLoadItem=e,_app=new dwv.App,_app.init(t),_app.addEventListener("error",(function(e){console.error("load error",e)})),_app.addEventListener("loadstart",(function(e){console.time("load-data-"+e.dataid);const t=[e.dataid];let n;"one"===_layout?n=getOnebyOneDataViewConfig(t):"side"===_layout?n=getOnebyTwoDataViewConfig(t):"mpr"===_layout&&(n=getMPRDataViewConfig(t));const o=n[e.dataid];for(let t=0;t<o.length;++t)_app.addDataViewConfig(e.dataid,o[t])}));const n=new Array(1),o=function(e,t){return e+t};_app.addEventListener("loadprogress",(function(e){void 0!==e.lengthComputable&&e.lengthComputable&&(n[e.dataid]=Math.ceil(e.loaded/e.total*100),document.getElementById("loadprogress").value=n.reduce(o)/1)})),_app.addEventListener("load",(function(t){e||_app.render(t.dataid)})),_app.addEventListener("loaditem",(function(e){void 0!==e.warn&&console.warn("load-warn",e.warn)})),_app.addEventListener("loadend",(function(e){console.timeEnd("load-data-"+e.dataid)}));let a=0;const d=[];_app.addEventListener("load",(function(e){if(!d.includes(e.dataid)&&(d.push(e.dataid),"image"===e.loadtype&&(console.log("metadata",getMetaDataWithNames(_app.getMetaData(e.dataid))),addDataRow(e.dataid),++a,1===a))){setAppTool();document.getElementById("changelayout").disabled=!1;document.getElementById("resetlayout").disabled=!1;document.getElementById("changesmoothing").disabled=!1}if("image"===e.loadtype&&void 0!==_app.getMetaData(e.dataid)["00080060"]&&"SEG"===_app.getMetaData(e.dataid)["00080060"].value[0]){logFramePosPats(_app.getMetaData(e.dataid));if(!1){const t=0,n=_app.getViewLayersByDataId(t)[0].getViewController(),o=_app.getImage(t).getGeometry(),a=o.getSize().getDimSize(2),d=_app.getImage(e.dataid),i=d.getGeometry().getOrigins()[0],l=new dwv.Point([i.getX(),i.getY(),i.getZ()]),r=o.worldToIndex(l).get(2)*a;n.setViewAlphaFunction((function(e,t){const n=3*(t-r);return n>=0&&0===d.getValueAtOffset(n)&&0===d.getValueAtOffset(n+1)&&0===d.getValueAtOffset(n+2)?0:255}))}}})),_app.addEventListener("positionchange",(function(e){const t=document.getElementById("position"),n=e.value[1];let o="(index: "+e.value[0]+")";e.value.length>2&&(o+=" value: "+e.value[2]),t.value=n.map(getPrecisionRound(2));document.getElementById("positionspan").innerHTML=o})),window.addEventListener("keydown",(function(e){if(_app.defaultOnKeydown(e),!isNaN(parseInt(e.key,10))){const t=_app.getActiveLayerGroup().getActiveViewLayer().getViewController();if(!t.isMask())return;const n=parseInt(e.key,10),o=t.getMaskSegmentHelper();if(o.hasSegment(n)){const a=o.getSegment(n);e.ctrlKey&&(e.altKey?(console.log("Delete segment: "+a.label),t.deleteSegment(n,_app.addToUndoStack)):(console.log("Show/hide segment: "+a.label),o.isHidden(n)?o.removeFromHidden(n):o.addToHidden(n),t.applyHiddenSegments()))}}})),window.addEventListener("resize",(function(){_app.onResize()}));const i={};if(document.cookie){const e=document.cookie.split("; "),t=e.find((e=>e.startsWith("accept=")));if(void 0!==t){const e=decodeURIComponent(t.split("=")[1]);void 0!==e&&0!==e.length&&(i.requestHeaders=[],i.requestHeaders.push({name:"Accept",value:e})),document.cookie="accept="}const n=e.find((e=>e.startsWith("access_token=")));if(void 0!==n){const e=n.split("=")[1];void 0!==e&&0!==e.length&&(void 0===i.requestHeaders&&(i.requestHeaders=[]),i.requestHeaders.push({name:"Authorization",value:"Bearer "+e})),document.cookie="access_token="}}_app.loadFromUri(window.location.href,i)}function onDOMContentLoaded(){viewerSetup();document.getElementById("position").addEventListener("change",(function(){const e=_app.getViewLayersByDataId("0")[0].getViewController(),t=this.value.split(",");e.setCurrentPosition(new dwv.Point([parseFloat(t[0]),parseFloat(t[1]),parseFloat(t[2])]))}));const e=document.getElementById("resetlayout");e.disabled=!0,e.addEventListener("click",(function(){_app.resetLayout()}));const t=document.getElementById("changelayout");t.disabled=!0,t.addEventListener("change",(function(e){const t=e.target.value;if("one"!==t&&"side"!==t&&"mpr"!==t)throw new Error("Unknown layout: "+t);let n;_layout=t;const o=_app.getDataIds();"one"===t?(addLayerGroups(1),n=getOnebyOneDataViewConfig(o)):"side"===t?(addLayerGroups(2),n=getOnebyTwoDataViewConfig(o)):"mpr"===t&&(addLayerGroups(3),n=getMPRDataViewConfig(o)),unbindAppToControls(),_app.setDataViewConfigs(n),clearDataTable();for(let e=0;e<o.length;++e)_app.render(o[e]),addDataRow(o[e]);if("one"!==t){const e=getLayerGroupDivIds(n);for(const t of e)_app.getLayerGroupByDivId(t).setShowCrosshair(!0)}setAppTool()}));const n=document.getElementById("changesmoothing");n.checked=!1,n.disabled=!0,n.addEventListener("change",(function(e){_app.setImageSmoothing(e.target.checked)})),setupBindersCheckboxes(),setupToolsCheckboxes(),setupTests(),setupAbout();document.getElementById("fileinput").addEventListener("change",(function(e){console.log("%c ----------------","color: teal;"),console.log(e.target.files),_app.loadFiles(e.target.files)}))}function addLayerGroup(e){const t=document.createElement("div");t.id=e,t.className="layerGroup";document.getElementById("dwv").appendChild(t)}function addLayerGroups(e){document.getElementById("dwv").innerHTML="";for(let t=0;t<e;++t)addLayerGroup("layerGroup"+t)}function getViewConfig(e){const t={divId:e};return"mpr"===_layout&&("layerGroup0"===e?t.orientation="axial":"layerGroup1"===e?t.orientation="coronal":"layerGroup2"===e&&(t.orientation="sagittal")),t}function partialCloneOldConfig(e,t){const n=_app.getViewConfigs(e);if(0!==n.length){const e=n[0];void 0!==e.windowCenter&&void 0!==e.windowWidth&&(t.windowCenter=e.windowCenter,t.windowWidth=e.windowWidth),void 0!==e.opacity&&(t.opacity=e.opacity),void 0!==e.colourMap&&(t.colourMap=e.colourMap)}return t}function getOnebyOneDataViewConfig(e){const t={};for(const n of e)t[n]=[partialCloneOldConfig(n,getViewConfig("layerGroup0"))];return t}function getOnebyTwoDataViewConfig(e){const t={};for(let n=0;n<e.length;++n){const o=e[n];let a;a=getViewConfig(n%2==0?"layerGroup0":"layerGroup1"),t[e[n]]=[partialCloneOldConfig(o,a)]}return t}function getMPRDataViewConfig(e){const t={};for(const n of e)t[n]=[partialCloneOldConfig(n,getViewConfig("layerGroup0")),partialCloneOldConfig(n,getViewConfig("layerGroup1")),partialCloneOldConfig(n,getViewConfig("layerGroup2"))];return t}function getLayerGroupDivIds(e){const t=[],n=Object.keys(e);for(let o=0;o<n.length;++o){const a=e[n[o]];for(let e=0;e<a.length;++e){const n=a[e].divId;t.includes(n)||t.push(n)}}return t}function getDivIds(e){const t=[];for(let n=0;n<e.length;++n)t.push(e[n].divId);return t}function getDataLayerGroupDivIds(e){const t=_app.getDataViewConfigs();let n=t[e];return void 0===n&&(n=t["*"]),getDivIds(n)}function setupBindersCheckboxes(){const e=document.getElementById("binders"),t=["WindowLevel","Position","Zoom","Offset","Opacity","ColourMap"],n=[];for(let e=0;e<t.length;++e)n.push(t[e]+"Binder");function o(e){return function(t){t.target.checked?function(e){n.push(e+"Binder"),_app.setLayerGroupsBinders(n)}(e):function(e){const t=n.indexOf(e+"Binder");-1!==t&&n.splice(t,1),_app.setLayerGroupsBinders(n)}(e)}}_app.setLayerGroupsBinders(n);for(let n=0;n<t.length;++n){const a=t[n],d=document.createElement("input");d.id="binder-"+n,d.type="checkbox",d.checked=!0,d.onchange=o(a);const i=document.createElement("label");i.htmlFor=d.id,i.appendChild(document.createTextNode(a)),e.appendChild(d),e.appendChild(i)}const a=document.createElement("input");a.id="binder-all",a.type="checkbox",a.checked=!0,a.onchange=function(){for(let e=0;e<t.length;++e)document.getElementById("binder-"+e).click()};const d=document.createElement("label");d.htmlFor=a.id,d.appendChild(document.createTextNode("all")),e.appendChild(a),e.appendChild(d)}function setupToolsCheckboxes(){const e=document.getElementById("tools"),t=Object.keys(_tools),n=function(e){return function(){setAppTool(e)}},o=function(e,t){return function(n){n.ctrlKey||n.altKey||n.shiftKey||n.key!==e||t.click()}};for(let a=0;a<t.length;++a){const d=t[a],i=document.createElement("input");i.name="tools",i.type="radio",i.id="tool-"+a,i.title=d,i.onchange=n(d),"Scroll"===d&&(i.checked=!0);const l=document.createElement("label");l.htmlFor=i.id,l.title=i.title,l.appendChild(document.createTextNode(i.title)),e.appendChild(i),e.appendChild(l);const r=getToolFeaturesHtml(d);void 0!==r&&e.appendChild(r);const c=d[0].toLowerCase();window.addEventListener("keydown",o(c,i))}}function getToolFeatures(e){let t;if("Draw"===e){t={shapeName:document.getElementById("draw-shape-select").value}}return t}function getToolFeaturesHtml(e){let t;if("Draw"===e){const e=document.createElement("select");e.id="draw-shape-select";const n=_tools.Draw.options;for(const t of n){const n=document.createElement("option");n.id="shape-"+t,n.value=t,n.appendChild(document.createTextNode(t)),e.appendChild(n)}e.onchange=function(e){_app.setToolFeatures({shapeName:e.target.value})};const o=document.createElement("input");o.type="checkbox",o.id="draw-auto-colour",o.checked=!0;const a=document.createElement("label");a.htmlFor=o.id,a.appendChild(document.createTextNode("auto colour"));const d=document.createElement("input");d.type="color",d.id="draw-colour-chooser",d.value="#ffff80",d.disabled=!0,o.onchange=function(e){_app.setToolFeatures({autoShapeColour:e.target.checked}),d.disabled=e.target.checked},d.onchange=function(e){_app.setToolFeatures({shapeColour:e.target.value})},t=document.createElement("span"),t.className="toolFeatures",t.appendChild(e),t.appendChild(o),t.appendChild(a),t.appendChild(d)}return t}function setAppTool(e){if(void 0===e){const t=document.getElementsByName("tools");for(let n=0;n<t.length;++n)if(t[n].checked){e=t[n].title;break}void 0===e&&console.warn("Cannot find tool to set the app with...")}_app.setTool(e);const t=getToolFeatures(e);void 0!==t&&_app.setToolFeatures(t)}function bindAppToControls(){_app.addEventListener("wlchange",onWLChange),_app.addEventListener("opacitychange",onOpacityChange)}function unbindAppToControls(){_app.removeEventListener("wlchange",onWLChange),_app.removeEventListener("opacitychange",onOpacityChange)}function onWLChange(e){let t="width-"+e.dataid+"-number",n=document.getElementById(t);if(n?n.value=e.value[1]:console.warn("wl change: HTML not ready?"),t="width-"+e.dataid+"-range",n=document.getElementById(t),n&&(n.value=e.value[1]),t="center-"+e.dataid+"-number",n=document.getElementById(t),n&&(n.value=e.value[0]),t="center-"+e.dataid+"-range",n=document.getElementById(t),n&&(n.value=e.value[0]),t="preset-"+e.dataid+"-select",n=document.getElementById(t),n){const t=getDataLayerGroupDivIds(e.dataid),o=_app.getLayerGroupByDivId(t[0]).getViewLayersByDataId(e.dataid);if(void 0!==o&&0!==o.length){const e="manual";if(o[0].getViewController().getCurrentWindowPresetName()===e){const t="preset-manual";let o=n.options.namedItem(t);if(!o){const a=document.createElement("option");a.id=t,a.value=e,a.appendChild(document.createTextNode(e)),o=n.appendChild(a)}n.selectedIndex=o.index}}}}function onOpacityChange(e){const t=parseFloat(e.value[0]).toPrecision(3);let n="opacity-"+e.dataid+"-number",o=document.getElementById(n);o?o.value=t:console.warn("opacity change: HTML not ready?"),n="opacity-"+e.dataid+"-range",o=document.getElementById(n),o&&(o.value=t)}function clearDataTable(){document.getElementById("layersdetails").innerHTML=""}function getControlDiv(e,t,n,o,a,d,i){const l=document.createElement("input");l.id=e+"-range",l.className="ctrl-range",l.type="range",l.min=n.toPrecision(i),l.max=o.toPrecision(i),l.step=(.01*(o-n)).toPrecision(i),l.value=a;const r=document.createElement("label");r.id=e+"-label",r.className="ctrl-label",r.htmlFor=l.id,r.appendChild(document.createTextNode(t));const c=document.createElement("input");c.id=e+"-number",c.className="ctrl-number",c.type="number",c.min=l.min,c.max=l.max,c.step=l.step,c.value=parseFloat(a).toPrecision(i),c.oninput=function(){l.value=this.value,d(this.value)},l.oninput=function(){c.value=parseFloat(this.value).toPrecision(i),d(this.value)};const s=document.createElement("div");return s.id=e+"-ctrl",s.className="ctrl",s.appendChild(r),s.appendChild(l),s.appendChild(c),s}function addDataRow(e){"0"===e&&bindAppToControls();const t=_app.getDataViewConfigs(),n=getLayerGroupDivIds(t),o=_app.getViewLayersByDataId(e)[0],a=o.getViewController(),d=a.getWindowLevel();let i,l=document.getElementById("layerstable");if(l)i=l.getElementsByTagName("tbody")[0];else{l=document.createElement("table"),l.id="layerstable";const e=l.createTHead().insertRow(0),t=function(t){const n=document.createElement("th");n.innerHTML=t,e.appendChild(n)};t("Id");for(let e=0;e<n.length;++e)t("LG"+e);t("Alpha Range"),t("Contrast"),t("Preset"),t("Alpha"),i=l.createTBody();document.getElementById("layersdetails").appendChild(l)}const r=i.insertRow();let c;const s=function(){const t=[];for(let o=0;o<n.length;++o){const a=n[o],d="layerselect-"+a+"-"+e,i=document.getElementById(d);i&&i.checked&&t.push(a)}return t},p=function(t,n){const o=document.createElement("input");return o.type="radio",o.name="layerselect-"+t,o.id="layerselect-"+n+"-"+e,o.checked=!0,o.onchange=function(e){const t=e.target.id.split("-"),n=t[1],o=t[2],a=_app.getLayerGroupByDivId(n);a.setActiveDrawLayerByDataId(o),a.setActiveViewLayerByDataId(o)},o},u=function(t,n){const o=document.createElement("button");return o.name="layeradd-"+t,o.id="layeradd-"+n+"-"+e,o.title="Add layer",o.appendChild(document.createTextNode("+")),o.onclick=function(){_app.addDataViewConfig(e,getViewConfig(n));const a=o.parentElement;a.replaceChildren(),a.appendChild(p(t,n)),a.appendChild(g(t,n)),a.appendChild(m(t,n,"axial")),a.appendChild(m(t,n,"coronal")),a.appendChild(m(t,n,"sagittal"))},o},g=function(t,n){const o=document.createElement("button");return o.name="layerrem-"+t,o.id="layerrem-"+n+"-"+e,o.title="Remove layer",o.appendChild(document.createTextNode("-")),o.onclick=function(){_app.removeDataViewConfig(e,getViewConfig(n));const a=o.parentElement;a.replaceChildren(),a.appendChild(u(t,n))},o},m=function(t,n,o){const a=document.createElement("button"),d=o[0].toUpperCase();return a.name="layerupd-"+t+"_"+d,a.id="layerupd-"+n+"-"+e+"_"+d,a.title="Change layer orientation to "+o,a.appendChild(document.createTextNode(d)),a.onclick=function(){const t={orientation:o};_app.updateDataViewConfig(e,n,t)},a};c=r.insertCell(),c.appendChild(document.createTextNode(e));let h=t[e];void 0===h&&(h=t["*"]);const f=getDivIds(h);for(let e=0;e<n.length;++e){const t=n[e];c=r.insertCell(),f.includes(t)?(c.appendChild(p(e,t)),c.appendChild(g(e,t)),c.appendChild(m(e,t,"axial")),c.appendChild(m(e,t,"coronal")),c.appendChild(m(e,t,"sagittal"))):c.appendChild(u(e,t))}const y=_app.getImage(o.getDataId()),v=y.getDataRange(),C=y.getRescaledDataRange();c=r.insertCell();const w="value-min-"+e,E="value-max-"+e,L=function(){const e=parseFloat(document.getElementById(w+"-number").value),t=parseFloat(document.getElementById(E+"-number").value),n=function(n){return n>=e&&n<=t?255:0},o=s();for(let e=0;e<o.length;++e){_app.getLayerGroupByDivId(o[e]).getActiveViewLayer().getViewController().setViewAlphaFunction(n)}};c.appendChild(getControlDiv(w,"min",v.min,v.max,v.min,L,4)),c.appendChild(getControlDiv(E,"max",v.min,v.max,v.max,L,4)),c=r.insertCell();const _="width-"+e,I="center-"+e,b=function(){const e=parseFloat(document.getElementById(_+"-number").value),t=parseFloat(document.getElementById(I+"-number").value),n=s();for(let o=0;o<n.length;++o){_app.getLayerGroupByDivId(n[o]).getActiveViewLayer().getViewController().setWindowLevel(t,e)}};c.appendChild(getControlDiv(_,"width",0,C.max-C.min,d.width,b,4)),c.appendChild(getControlDiv(I,"center",C.min,C.max,d.center,b,4)),c=r.insertCell();const D=document.createElement("select");D.id="preset-"+e+"-select";const B=a.getWindowLevelPresetsNames();for(const e of B){const t=document.createElement("option");t.value=e,t.appendChild(document.createTextNode(e)),D.appendChild(t)}D.onchange=function(e){const t=s();for(let n=0;n<t.length;++n){_app.getLayerGroupByDivId(t[n]).getActiveViewLayer().getViewController().setWindowLevelPreset(e.target.value)}};const T=document.createElement("label");T.htmlFor=D.id,T.appendChild(document.createTextNode("wl: ")),c.appendChild(T),c.appendChild(D);const V=document.createElement("br");c.appendChild(V);const k=document.createElement("select");k.id="colourmap-"+e+"-select";const x=Object.keys(dwv.luts);for(const e of x){const t=document.createElement("option");t.value=e,t.appendChild(document.createTextNode(e)),k.appendChild(t)}k.onchange=function(e){const t=s();for(let n=0;n<t.length;++n){_app.getLayerGroupByDivId(t[n]).getActiveViewLayer().getViewController().setColourMap(e.target.value)}};const G=document.createElement("label");G.htmlFor=k.id,G.appendChild(document.createTextNode("cm: ")),c.appendChild(G),c.appendChild(k),c=r.insertCell();const O="opacity-"+e;c.appendChild(getControlDiv(O,"opacity",0,1,o.getOpacity(),(function(e){const t=s();for(let n=0;n<t.length;++n){const o=_app.getLayerGroupByDivId(t[n]).getActiveViewLayer();o.setOpacity(e),o.draw()}}),4))}function comparePosPat(e,t){return parseFloat(e.split("\\").at(-1))-parseFloat(t.split("\\").at(-1))}function sortByPosPatKey(e){const t=Object.keys(e);t.sort(comparePosPat);const n=new Map;for(let o=0;o<t.length;o++){const a=t[o];n.set(a,e[a])}return n}function getPrecisionRound(e){return function(t){return dwv.precisionRound(t,e)}}function logFramePosPats(e){const t=e[52009230].value,n={};for(let e=0;e<t.length;++e){const o=t[e]["00209113"].value[0]["00200032"].value;void 0===n[o]&&(n[o]=[]);const a=t[e]["00209111"].value[0]["00209157"].value;n[o].push(a)}console.log("DICOM SEG Segments",sortByPosPatKey(n))}function getMetaDataWithNames(e){let t=e;return void 0!==t["00020010"]&&(t=Object.keys(t).reduce(((e,n)=>{const o=dwv.getTagFromKey(n);let a=o.getNameFromDictionary();return void 0===a&&(a="x"+o.getKey()),e[a]=t[n],e}),{})),t}function setupTests(){const e=document.createElement("button");e.onclick=runRenderTest,e.appendChild(document.createTextNode("render test"));document.getElementById("tests").appendChild(e)}function getSimpleStats(e){let t=e[0],n=t,o=0,a=0,d=0;const i=e.length;for(let l=0;l<i;++l)d=e[l],d<t?t=d:d>n&&(n=d),o+=d,a+=d*d;const l=o/i,r=a/i-l*l;return{min:t,max:n,mean:l,stdDev:Math.sqrt(r)}}function runRenderTest(){_app.setActiveLayerGroup(1);const e=_app.getActiveLayerGroup().getActiveViewLayer().getViewController(),t=function(){e.incrementScrollIndex()};let n;const o=[],a=function(){n=performance.now()},d=function(){const e=performance.now();o.push(e-n),n=void 0,o.length<20?setTimeout((()=>{t()}),100):(console.log("Stats:",getSimpleStats(o)),_app.removeEventListener("renderstart",a),_app.removeEventListener("renderend",d))};_app.addEventListener("renderstart",a),_app.addEventListener("renderend",d),t()}function setupAbout(){const e=document.getElementById("about"),t=document.createElement("a");t.href="https://github.com/ivmartel/dwv",t.appendChild(document.createTextNode("dwv"));const n=document.createTextNode(" v"+dwv.getDwvVersion()+" on "+navigator.userAgent);e.appendChild(t),e.appendChild(n)}
|