FlowBL/public/static/dicom/js/dicomViewPc.js

655 lines
23 KiB
JavaScript
Raw Normal View History

2024-08-04 18:23:33 +08:00
//功能名称
const functionNames = [
"Magnify", "Pan", "Zoom", "ZoomMouseWheel", "Wwwc",
"ScaleOverlay", "OrientationMarkers", "WwwcRegion", "Rotate", "Angle", "ArrowAnnotate", "Bidirectional", "CobbAngle", "EllipticalRoi", "FreehandRoi", "Length", "Probe", "RectangleRoi", "TextMarker",
"StackScroll", "StackScrollMouseWheel"
]
//标尺和方向显示可与其他状态同时启用
const displayFunctions = ["ScaleOverlay", "OrientationMarkers"]
//不能同时启用的功能
const notNeedDisableFunctions = ["WwwcRegion", "Rotate", "Angle", "ArrowAnnotate", "Bidirectional", "CobbAngle", "EllipticalRoi", "FreehandRoi", "Length", "Probe", "RectangleRoi", "TextMarker"]
//状态数据
var stateData = {
rowCount: 1,
columnCount: 1,
imgIndex: 0,
element: {},
dicomInfo: {},
showMapping: new Map()
}
/*切换工具*/
function switchAction(tagName, flag, btn) {
//btn btn-primary
var isSelected = $(btn).hasClass('selected');
if (isSelected) {
$(btn).removeClass("btn-primary")
$(btn).removeClass("selected")
$(btn).addClass("btn-default")
disableFunctions(tagName);
}
else {
disableFunctions(tagName);
$(btn).removeClass("btn-default")
$(btn).addClass("btn-primary")
$(btn).addClass("selected")
}
if (!isSelected) {
cornerstoneTools.setToolActive(tagName, { mouseButtonMask: 1 })
}
}
function reload() {
var data = cornerstoneTools.getToolState(stateData.element, "stack").data[0];
var index = data.currentImageIdIndex;
var imgId = data.imageIds[index];
data.currentImageIdIndex = index;
cornerstone.loadAndCacheImage(imgId).then(function (image) {
cornerstone.enable(stateData.element);
cornerstone.displayImage(stateData.element, image);
});
}
//下一张
function next(imgId) {
if (imgId && stateData.element != imgId) {
return;
}
var data = cornerstoneTools.getToolState(stateData.element, "stack").data[0];
var index = data.currentImageIdIndex;
if (index == data.imageIds.length - 1) {
return;
}
else {
index += 1;
}
var imgId = data.imageIds[index];
data.currentImageIdIndex = index;
cornerstone.loadAndCacheImage(imgId).then(function (image) {
cornerstone.enable(stateData.element);
cornerstone.displayImage(stateData.element, image);
renderTagText(stateData.element,image)
});
for (var i = 0; i < 10; i++) {
if (index + i == data.imageIds.length - 1) {
break;
}
cornerstone.loadImage(data.imageIds[index + i]).then((image) => {
console.log("loaded ok " + data.imageIds[index + i]);
})
}
setSliderValue(stateData.element.id)
}
//读取文件中的标签信息
function getDicomInfo(image) {
var imageInfo = {};
imageInfo.seriesNumber = image.data.string('x00200011');//图像序列号
imageInfo.imageNum = image.data.string('x00200013');//图像位置
imageInfo.imageDate = image.data.string("x00080021");//拍摄日期
imageInfo.sliceThickness = image.data.string('x00180050');//层厚
imageInfo.patientId = image.data.string('x00100020');//病理号
// 判断窗宽窗位是否合法
imageInfo.pixelR = image.data.uint16('x00280103');
imageInfo.heightBit = image.data.uint16('x00280102') || '';
// 病人基本信息
imageInfo.patientName = image.data.string('x00100010');
imageInfo.patientBirthDate = image.data.string('x00100030');
imageInfo.patientGender = image.data.string('x00100040');
imageInfo.sID = image.data.string('x00200011');
// 像素间距
imageInfo.pixelSpacing = image.data.string('x00280030');
imageInfo.height = image.data.uint16('x00280010');
imageInfo.width = image.data.uint16('x00280011');
imageInfo.height = image.data.uint16('x00280010');
imageInfo.windowCenter = image.data.string('x00281050');
imageInfo.windowWidth = image.data.string('x00281051');
imageInfo.imagePixelSpacing = image.data.string('x00181164') || '';
imageInfo.rowPixelSpacing = image.rowPixelSpacing;
// 放射放大系数
imageInfo.magnification = Number(image.data.string('x00181114'));
// 放射源到面板的距离
imageInfo.sourceTOdetector = image.data.string('x00181110');
// 放射源到病人的距离
imageInfo.sourceTOpatient = image.data.string('x00181111');
//this.modalityLUT = cornerstone.metaData.get('modalityLutModule', image.imageId).modalityLUTSequence;
imageInfo.voiContent = cornerstone.metaData.get('voiLutModule', image.imageId);
// 斜率截距
imageInfo.rescaleIntercept = Number(image.data.string('x00281052'));
imageInfo.rescaleSlope = Number(image.data.string('x00281053'));
return imageInfo;
}
//上一张
function last(imgId) {
if (imgId && stateData.element != imgId) {
return;
}
var data = cornerstoneTools.getToolState(stateData.element, "stack").data[0];
var index = data.currentImageIdIndex;
if (index == 0) {
return;
}
else {
index -= 1;
}
var imgId = data.imageIds[index];
data.currentImageIdIndex = index;
cornerstone.loadAndCacheImage(imgId).then(function (image) {
cornerstone.enable(stateData.element);
cornerstone.displayImage(stateData.element, image);
renderTagText(stateData.element, image)
});
setSliderValue(stateData.element.id)
}
//进度条更新
function setAllSliderValue() {
//获取所有已经加载的图片区映射关系
if (stateData.showMapping) {
stateData.showMapping.forEach((value, key) => {
setSliderValue(key);
});
}
}
//标签文本更新
function setAllTagsValue() {
if (stateData.showMapping) {
stateData.showMapping.forEach((value, key) => {
var element = document.getElementById(key)
var image = cornerstone.getImage(element);
//TODO 缺少获取图片对象信息
renderTagText(element, image)
});
}
}
//重置画布
function resetRenderCanvase() {
var element = stateData.element;
const enabledElement = cornerstone.getEnabledElement(element);
enabledElement.renderingTools.colormapId = undefined;
enabledElement.renderingTools.colorLut = undefined;
const renderCanvas = enabledElement.renderingTools.renderCanvas;
const canvasContext = renderCanvas.getContext('2d');
// NOTE - we need to fill the render canvas with white pixels since we
// control the luminance using the alpha channel to improve rendering performance.
canvasContext.fillStyle = 'white';
canvasContext.fillRect(0, 0, renderCanvas.width, renderCanvas.height);
const renderCanvasData = canvasContext.getImageData(0, 0, renderCanvas.width, renderCanvas.height);
enabledElement.renderingTools.renderCanvasContext = canvasContext;
enabledElement.renderingTools.renderCanvasData = renderCanvasData;
cornerstone.updateImage(stateData.element);
}
//重置按钮状态
function resetBtnState(id) {
if ($("#" + id).hasClass("selected")) {
$("#" + id).removeClass("btn-primary")
$("#" + id).removeClass("selected")
$("#" + id).addClass("btn-default")
}
}
function disableFunctions(currentFun) {
functionNames.forEach(function (fname) {
resetBtnState(fname)
if (currentFun != fname && (notNeedDisableFunctions.includes(fname) || displayFunctions.includes(fname))) {
return;
}
cornerstoneTools.setToolDisabled(fname, { mouseButtonMask: 1 })
})
}
//辅助工具
const toolFunction = ["ScaleOverlay", "OrientationMarkers"]
const wheelFunction = ["ZoomMouseWheel"]
//撤销所有改动
function resetTool() {
//反转色
//invert(null, $("#invert"), true)
//changColor(0, $("#changeColor"), true)
functionNames.forEach(function (fname) {
if (notNeedDisableFunctions.includes(fname)) {
cornerstoneTools.clearToolState(stateData.element, fname);
}
})
cornerstone.reset(stateData.element);
cornerstone.updateImage(stateData.element);
}
//反转颜色
function invert(flag, btn, reset) {
//btn btn-primary
var isSelected = $(btn).hasClass('selected');
if (isSelected || reset) {
$(btn).removeClass("btn-primary")
$(btn).removeClass("selected")
$(btn).addClass("btn-default")
}
else {
$(btn).removeClass("btn-default")
$(btn).addClass("btn-primary")
$(btn).addClass("selected")
}
//反转颜色
var viewport = {
invert: !isSelected ? true : false
}
cornerstone.setViewport(stateData.element, viewport);
}
//彩色
function changColor(flag, btn, reset) {
var element = stateData.element;
//btn btn-primary
var isSelected = $(btn).hasClass('selected');
if (isSelected || reset) {
$(btn).removeClass("btn-primary")
$(btn).removeClass("selected")
$(btn).addClass("btn-default")
}
else {
$(btn).removeClass("btn-default")
$(btn).addClass("btn-primary")
$(btn).addClass("selected")
}
resetRenderCanvase();
const b = cornerstone.getEnabledElement(element)
const v = cornerstone.getDefaultViewport(b.canvas, b.image)
var vp = cornerstone.getViewport(element);
vp.colormap = !isSelected ? "hsv" : undefined;
if (!flag) {
cornerstone.setViewport(element, v)
}
else {
cornerstone.setViewport(element, vp)
}
}
//重置cornerstone
function reset() {
cornerstone.reset(stateData.element);
}
function initConerstone(element) {
// 注册并挂载cornerstone及其cornerstoneTools固定操作
cornerstoneTools.external.cornerstone = cornerstone;
cornerstoneTools.external.cornerstoneMath = cornerstoneMath;
cornerstoneTools.external.Hammer = Hammer;
cornerstoneWADOImageLoader.external.dicomParser = dicomParser;
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
// imageId就是cornerstone要求的.dcm图片地址,例如var imageId = "wadouri:http://127.0.0.1:6699/ctdcm1.dcm";
//var imageId = "wadouri:./1.dcm";
// 初始化cornerstoneTools工具
cornerstoneTools.init();
//// 获取要用于加载图片的div区域
//element = document.getElementById('dicomImage');
////激活获取到的用于图片加载的区域
cornerstone.enable(element);
// 从cornerstoneTools库中获取窗宽,窗高工具
const WwwcTool = cornerstoneTools.WwwcTool;
//添加获取到的窗宽,窗高工具
cornerstoneTools.addTool(WwwcTool);
//放大
const MagnifyTool = cornerstoneTools.MagnifyTool;
cornerstoneTools.addTool(MagnifyTool)
//平移
const PanTool = cornerstoneTools.PanTool;
cornerstoneTools.addTool(PanTool)
const ZoomTool = cornerstoneTools.ZoomTool;
cornerstoneTools.addTool(ZoomTool, {
// Optional configuration
configuration: {
invert: false,
preventZoomOutsideImage: false,
minScale: .1,
maxScale: 20.0,
}
});
const ZoomMouseWheelTool = cornerstoneTools.ZoomMouseWheelTool;
cornerstoneTools.addTool(ZoomMouseWheelTool)
const WwwcRegionTool = cornerstoneTools.WwwcRegionTool;
cornerstoneTools.addTool(WwwcRegionTool)
const ScaleOverlayTool = cornerstoneTools.ScaleOverlayTool;
cornerstoneTools.addTool(ScaleOverlayTool)
//旋转
const RotateTool = cornerstoneTools.RotateTool;
cornerstoneTools.addTool(RotateTool)
const OrientationMarkersTool = cornerstoneTools.OrientationMarkersTool;
cornerstoneTools.addTool(OrientationMarkersTool)
const AngleTool = cornerstoneTools.AngleTool;
cornerstoneTools.addTool(AngleTool)
const ArrowAnnotateTool = cornerstoneTools.ArrowAnnotateTool;
cornerstoneTools.addTool(ArrowAnnotateTool)
const BidirectionalTool = cornerstoneTools.BidirectionalTool;
cornerstoneTools.addTool(BidirectionalTool)
const CobbAngleTool = cornerstoneTools.CobbAngleTool;
cornerstoneTools.addTool(CobbAngleTool)
const EllipticalRoiTool = cornerstoneTools.EllipticalRoiTool;
cornerstoneTools.addTool(EllipticalRoiTool)
const FreehandRoiTool = cornerstoneTools.FreehandRoiTool;
cornerstoneTools.addTool(FreehandRoiTool)
const LengthTool = cornerstoneTools.LengthTool;
cornerstoneTools.addTool(LengthTool)
const ProbeTool = cornerstoneTools.ProbeTool;
cornerstoneTools.addTool(ProbeTool)
const RectangleRoiTool = cornerstoneTools.RectangleRoiTool;
cornerstoneTools.addTool(RectangleRoiTool)
const TextMarkerTool = cornerstoneTools.TextMarkerTool
// set up the markers configuration
const configuration = {
markers: ['F5', 'F4', 'F3', 'F2', 'F1'],
current: 'F5',
ascending: true,
loop: true,
}
cornerstoneTools.addTool(TextMarkerTool, { configuration })
const StackScrollTool = cornerstoneTools.StackScrollTool
cornerstoneTools.addTool(StackScrollTool)
const StackScrollMouseWheelTool = cornerstoneTools.StackScrollMouseWheelTool
cornerstoneTools.addTool(StackScrollMouseWheelTool)
cornerstoneTools.setToolActive('StackScrollMouseWheel', {})
}
function initConerstoneAndData() {
var series = stateData.dicomInfo.seriesList[stateData.imgIndex].instanceList
const scheme = 'wadouri'
const baseUrl = ''
const imageIds = series.map(seriesImage => `${scheme}:${baseUrl}${seriesImage.imageid}`)
//define the stack
const stack = {
currentImageIdIndex: 0,
imageIds: imageIds
}
cornerstone.enable(stateData.element);
// load images and set the stack
cornerstone.loadImage(imageIds[0]).then((image) => {
initSlider(stateData.element);
cornerstone.displayImage(stateData.element, image)
cornerstoneTools.addStackStateManager(stateData.element, ['stack'])
cornerstoneTools.addToolState(stateData.element, 'stack', stack)
renderTagText(stateData.element, image)
})
}
//页面加载完成,执行初始化
$(document).ready(function () {
createElements(1, 1,true);
//激活获取到的用于图片加载的区域
stateData.element = document.getElementById('dicomImage_0_0');
stateData.showMapping.set('dicomImage_0_0',0);
//cornerstone.enable(stateData.element);
initConerstone(stateData.element);
//初始化数据
initData();
//鼠标滚轮事件
document.addEventListener('mousewheel', function (event) {
// 处理事件
setAllSliderValue();
setAllTagsValue();
});
//鼠标移动事件
document.addEventListener('mousemove', function (event) {
// 处理事件
setAllSliderValue();
setAllTagsValue();
});
})
//初始化右侧图片列表
function initImgList(data) {
$("#dicom-list").empty();
for (var i = 0; i < data.seriesList.length; i++) {
var className = "series_img";
if (stateData.imgIndex == i) {
className += "_active";
}
$("#dicom-list").append('<img id="img_' + i + '" onclick="changeIndex(' + i + ')" class="' + className + '" src="' + data.seriesList[i].thumbUrl + '"/>');
}
}
//修改序列
function changeIndex(i) {
if (stateData.imgIndex == i && stateData.showMapping.get(stateData.element.id) == i) {
return;
}
$("#img_" + stateData.imgIndex).removeClass("series_img_active");
$("#img_" + stateData.imgIndex).addClass("series_img")
$("#img_" + i).removeClass("series_img")
$("#img_" + i).addClass("series_img_active")
stateData.imgIndex = i
initConerstone(stateData.element)
initConerstoneAndData();
stateData.showMapping.set(stateData.element.id, i);
}
//获取数据 Handler/Service.ashx idx: idx, no: localData.no, orgId: localData.orgId, method: "getSeries"
function initData() {
var idx = GetQueryString("idx");
var localStorage = window.localStorage;
var localData = JSON.parse(localStorage.data);
2024-08-06 13:35:42 +08:00
var data= JSON.parse(localData.do);
console.log("网页接受到数据"+data)
stateData.dicomInfo = data;
initImgList(stateData.dicomInfo);
initConerstoneAndData();
2024-08-04 18:23:33 +08:00
/* alert(localData.regid) */
2024-08-06 13:35:42 +08:00
/* $.getJSON("http://127.0.0.1:5000/get-data", {
2024-08-04 18:23:33 +08:00
},
function (data) {
if ("failed" == data.status) {
alert("获取数据失败")
}
else {
2024-08-06 13:35:42 +08:00
console.log(data)
2024-08-04 18:23:33 +08:00
stateData.dicomInfo = data;
initImgList(stateData.dicomInfo);
initConerstoneAndData();
}
2024-08-06 13:35:42 +08:00
}); */
2024-08-04 18:23:33 +08:00
}
2024-08-06 13:35:42 +08:00
2024-08-04 18:23:33 +08:00
//初始化滚动条
function initSlider(element) {
var idx = stateData.showMapping.get(element.id);
var size = stateData.dicomInfo.seriesList[idx].instanceList.length;
//当前索引
var index = 0;
try {
var data = cornerstoneTools.getToolState(element, "stack").data[0];
index = data.currentImageIdIndex;
}
catch (err) {
console.log('err',err)
}
$("#" + element.id + "-slider").attr("min", 1)
$("#" + element.id + "-slider").attr("max", size)
$("#" + element.id + "-slider").val(index + 1)
}
//选中元素
function changeElement(b) {
//滚动条和上下翻页禁用
$(".operator").attr("disabled", "true");
$("#" + b.id + "-btn-next").removeAttr("disabled");
$("#" + b.id + "-btn-last").removeAttr("disabled");
$("#" + b.id + "-slider").removeAttr("disabled");
if (stateData.element == b) {
$(b).parent().removeClass("dicom-img-box");
$(b).parent().addClass("dicom-img-box-active");
return;
}
$(b).parent().removeClass("dicom-img-box");
$(b).parent().addClass("dicom-img-box-active");
$(stateData.element).parent().removeClass("dicom-img-box-active");
$(stateData.element).parent().addClass("dicom-img-box");
stateData.element = b;
}
//获取URL参数
function GetQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]); return null;
}
//设置滑动条值
function setSliderValue(imgId) {
//获取被选中胶片区域元素
var element = document.getElementById(imgId)
var data = cornerstoneTools.getToolState(element, "stack").data[0];
var index = data.currentImageIdIndex;
$("#" + imgId + "-slider").val(index+1);
}
function changeSlider(imgId, slider) {
var sliderValue = $(slider).val();
var data = cornerstoneTools.getToolState(stateData.element, "stack").data[0];
index = sliderValue - 1;
var imgId = data.imageIds[index];
data.currentImageIdIndex = index;
cornerstone.loadAndCacheImage(imgId).then(function (image) {
cornerstone.enable(stateData.element);
cornerstone.displayImage(stateData.element, image);
renderTagText(stateData.element,image)
});
for (var i = 0; i < 10; i++) {
if (index + i == data.imageIds.length - 1) {
break;
}
cornerstone.loadImage(data.imageIds[index + i]).then((image) => {
console.log("loaded ok " + data.imageIds[index + i]);
})
}
}
//渲染标签文本
function renderTagText(e, i) {
var tagsInfo = getDicomInfo(i);
var element = $(e).parent()[0];
var boxId = element.id;
//判断文本是否已经显示
if (!$("#" + boxId + "_left-top").length) {
var infoElement =
' <div id="' + boxId + '_left-top" class="around-info-left-top"></div>' +
' <div id="' + boxId + '_right-top" class="around-info-right-top"></div>' +
' <div id="' + boxId + '_left-bottom" class="around-info-left-bottom"></div>' +
' <div id="' + boxId + '_right-bottom" class="around-info-right-bottom"></div>';
$(element).children().first().before(infoElement);
}
//左上角
var leftTop = $("#" + boxId + "_left-top");
leftTop.empty();
leftTop.append("<div class='tag-item'>" + tagsInfo.patientId + "</div>");//体检编号
leftTop.append("<div class='tag-item'>姓名:" + stateData.dicomInfo.patientname + "</div>");//患者姓名
leftTop.append("<div class='tag-item'>" + tagsInfo.patientBirthDate + " " + (tagsInfo.patientGender == 'F' ? "男":"女") + "</div>");
leftTop.append("<div class='tag-item'>" + tagsInfo.imageDate + "</div>");
//左下角
var leftBottom = $("#" + boxId + "_left-bottom");
leftBottom.empty();
leftBottom.append("<div class='tag-item'>" + stateData.dicomInfo.hospital +"</div>");
//右上角
var rightTop = $("#" + boxId + "_right-top");
rightTop.empty();
rightTop.append("<div class='tag-item'>序列:" + tagsInfo.seriesNumber + " 图像:" + tagsInfo.imageNum + "</div>");
//右下角
var vp = cornerstone.getViewport(e);
var rightBottom = $("#" + boxId + "_right-bottom");
rightBottom.empty();
rightBottom.append("<div class='tag-item'>缩放:" + vp.scale.toFixed(2) + "</div>");
rightBottom.append("<div class='tag-item'>" + tagsInfo.width + "x" + tagsInfo.height + "</div>");
rightBottom.append("<div class='tag-item'>窗宽:" + tagsInfo.windowWidth + " 窗位:" + tagsInfo.windowCenter + "</div>");
}
//创建视图元素
function createElements(rowCount, columnCount,isInit) {
var container = document.getElementById('dicom-continer');
if (!isInit) {
clearChildren(container);
}
for (var i = 0; i < rowCount; i++) {
//生成行
var rowDom = document.createElement('div')
rowDom.setAttribute("class", "flex-row");
for (var j = 0; j < columnCount; j++) {
var columnDom = document.createElement('div');
columnDom.setAttribute("class", "dicom-img-box");
columnDom.setAttribute("id", 'dicom-img-box_' + i + '_' + j)
var imgId = 'dicomImage_' + i + '_' + j;
$(columnDom).append('<div class="dicom-img" id="' + imgId + '" onclick="changeElement(this)"></div>'
+'<div class="slider-container">'
+ '<i class="iconfont icon-fangxiangjiantou-shang icon-shang operator" id="' + imgId +'-last_btn" onclick="last(' + imgId +')"></i>'
+ '<input type="range" class="lcmf-range lcmf-range-date operator" value="0" id="' + imgId +'-slider" onchange="changeSlider(\'' + imgId + '\',this)" />'
+ '<i class="iconfont icon-fangxiangjiantou-xia icon-xia operator" id="' + imgId +'-next_btn" onclick="next(' + imgId +')"></i>'
+ '</div>');
rowDom.appendChild(columnDom);
}
container.appendChild(rowDom);
}
}
//清理元素
function clearChildren(element) {
if (element && element.children.length > 0) {
for (var i = 0; i < element.children.length; i++) {
element.removeChild(element.children[i]);
i--;
}
}
}
//创建视图入口
function doCreate() {
let rowCount = parseInt(document.getElementById('row-count').value);
let columnCount = parseInt(document.getElementById('column-count').value);
if (stateData.rowCount == rowCount && stateData.columnCount == columnCount) {
return;
}
createElements(rowCount, columnCount, false);
stateData.rowCount = rowCount;
stateData.columnCount = columnCount;
stateData.imgIndex = 0;
stateData.element = null;
stateData.showMapping = new Map()
}