cornerstoneTool.js扩展工具
html
<div id="dicomImage" style="width: 512px;height: 512px;" oncontextmenu="return false" onmousedown="return false"></div>
script
<script src="https://unpkg.com/hammerjs@2.0.8/hammer.js"></script>
<script src="https://unpkg.com/cornerstone-core@2.3.0/dist/cornerstone.js"></script>
<script src="https://unpkg.com/cornerstone-math@0.1.9/dist/cornerstoneMath.min.js"></script>
<script src="https://unpkg.com/cornerstone-wado-image-loader@3.3.1/dist/cornerstoneWADOImageLoader.min.js"></script>
<script src="https://unpkg.com/cornerstone-web-image-loader@2.1.1/dist/cornerstoneWebImageLoader.min.js"></script>
<script src="https://unpkg.com/cornerstone-tools@5.1.5/dist/cornerstoneTools.js"></script>
<script src="https://unpkg.com/dicom-parser@1.8.7/dist/dicomParser.min.js"></script>
<script>
cornerstoneTools.external.cornerstone = cornerstone;
cornerstoneTools.external.Hammer = Hammer;
cornerstoneTools.external.cornerstoneMath = cornerstoneMath;
cornerstoneWADOImageLoader.external.dicomParser = dicomParser;
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
cornerstoneTools.init();
let el = document.querySelector("#dicomImage");
let imageId = "wadouri:http://127.0.0.1/download/dx123.dcm";
cornerstone.enable(el);
cornerstone.loadAndCacheImage(imageId).then(img => {
cornerstone.displayImage(el, img);
});
</script>
效果如下:
若是自己写工具的话,可以利用cornerstoneTools.import这个函数。
第一步
let BaseTool = cornerstoneTools.import("base/BaseAnnotationTool"); //自己写的工具要继承哪个基础工具,有三个可以继承的工具
/**
base/BaseTool 官网General 差不多都是继承这个( 具体我也没有看完全部)
base/BaseAnnotationTool 需要绘制一些图形可以继承这个 官网Annotation
base/BaseBrushTool 官网Segmentation, 需要删除区域可以继承这个
*/
第二步
//自己的工具需要一个新的绘制环境,所以要获取一个函数
let getNewContext = cornerstoneTools.import("drawing/getNewContext");
//绘制板
let draw = cornerstoneTools.import("drawing/draw"); //这个不需要也行,这里函数只会简单的调用ctx.save();回调后调用 ctx.restore(); 建议还是要的,虽然官网没什么例子。
//绘制圆形
let drawCircle = cornerstoneTools.import("drawing/drawCircle");
//绘制线
let drawLine = cornerstoneTools.import("drawing/drawLine");
第三步
let _self = null; //保存this
//十字线
class CrosshairMpr extends BaseTool{
constructor(props){
let defaults = {
name : "CrosshairMpr", //工具名称, 这个是必要的,没有这个,就不能使用自定义工具
supportedInteractionTypes: ["Mouse"], //必要的, 支持那些操作方式, ["Mouse","Touch]
configuration: { //配置,非必要
lineWidth: 1, //自己定义的宽度
}
}
const initialProps = Object.assign({}, defaults, props);
super(initialProps); //继承
//自己定义的属性
this.x = 0; //开始x点
this.y = 0; //开始y点
this.dx = 0; //结束dx点
this.dy = 0; //结束dy点
this.cancleListenIndex = 0; //鼠标按下次数
this.initConfiguration = initialProps; //混合后的配置
}
//可以利用cornerstoneTools.setTool[...]触发下面不同的函数 (PS:非必须)
activeCallback(el, options){ //激活时触发
this.width = el.offsetWidth;
this.height = el.offsetHeight;
this.x = this.width / 2;
this.y = this.height / 2;
this.dx = this.x;
this.dy = this.y;
if(!_self){
_self = this;
}
this._renderCrosshair(getNewContext(el.firstElementChild),el,{},this.x,this.y);
}
disabledCallback(){} //禁用时触发
passiveCallback(){} //被动时触发
enabledCallback(){} //允许时触发
preMouseDownCallback(e){ //鼠标点下触发事件
/**
这里比较狗, 鼠标按下提供了MouseEvent的事件对象,而鼠标移动却没有,只提供了e.detail.currentPoints.client ---> x : e.clientX, y : e.clientY 原本我是想用offset快点实现,后来没有提供又要client进行计算
*/
e.preventDefault();
e.stopPropagation();
this.cancleListenIndex++;
if(this.cancleListenIndex >= 2){
this.cancleMouseMove();
this.cancleListenIndex = 0;
this.x = this.dx;
this.y = this.dy;
return true;
}
let event = e.detail.event;
this.x = event.clientX - this.element.offsetLeft;
this.y = event.clientY - this.element.offsetTop + 1;
this.startMouse();
return true;
}
postMouseDownCallback(e) { //阻止默认事件
e.preventDefault();
e.stopPropagation();
return true;
}
renderToolData(e){ //触发图形改变或改变viewport都会触发这个函数渲染
let event = e.detail;
this._renderCrosshair(getNewContext(event.canvasContext.canvas),event.element,event,this.dx,this.dy);
}
_renderCrosshair(context,el,e,x,y){ //自定义函数
let offset = 10;
let high = (this.height / 2);
let wide = (this.width / 2);
let dx = (wide - x);
let dy = (high - y);
draw(context,ctx=>{//ctx 也是context
//drawLine有五个参数 context, element,start,end,options
/**
context 上下文环境
element enabled元素
start 开始坐标点{x : 0, y : 0}
end 结束坐标点{x : 0,y : 0}
options 对象 ---> color,lineWidth,lineDash,fill
args[5] 这个参数是用来决定是否用 cornerstone.pixelToCanvas获取开始和结束点,如果不传参就是 pixel, 传入start和end将无效, 传有效值将使用start和end
*/
drawLine(ctx,el,{x : x,y : 0},{x : x,y : high - offset - dy},{
color : "orange",
lineWidth : this._configuration.lineWidth || 1
},"canvas");
drawLine(ctx,el,{x : x,y : high + offset - dy},{x : x,y : this.height},{
color : "#38f",
lineWidth : this._configuration.lineWidth || 1
},"canvas");
drawLine(ctx,el,{x : 0,y : y},{x : wide - offset - dx,y : y},{
color : "#f20",
lineWidth : this._configuration.lineWidth || 1
},"canvas");
drawLine(ctx,el,{x : wide + offset - dx,y : y},{x : this.width,y : y},{
color : "green",
lineWidth : this._configuration.lineWidth || 1
},"canvas");
//这个也是同理
drawCircle(ctx,el,{
x : x,
y : y
},offset - 4,{
color : "purple",
lineWidth : this._configuration.lineWidth || 1
},"canvas");
});
}
startMouse(){ //自定义函数
this.element.addEventListener("cornerstonetoolsmousemove",listenMouse);
}
cancleMouseMove(){//自定义函数
this.element.removeEventListener("cornerstonetoolsmousemove",listenMouse);;
}
_resetRender(){//自定义函数, 触发重渲染
let viewport = cornerstone.getViewport(this.element);
cornerstone.setViewport(this.element,viewport);
}
}
//监听鼠标移动
function listenMouse(e){
let event = e.detail;
let client = event.currentPoints.client;
_self.dx = _self.x + (client.x - this.offsetLeft - _self.x);
_self.dy = _self.y + (client.y - this.offsetTop + 1 - _self.y);
_self._resetRender();
}
cornerstoneTools.addTool(CrosshairMpr); //添加工具
cornerstoneTools.setToolActive("CrosshairMpr",{ //激活工具
mouseButtonMask : 1
});
效果如下:
切记不要自己利用canvas清除API清除 ctx.clearRect(0,0,width,height)这会有点危险。
我看官网没有这个API,但是OHIF.org这个demo中的2D MPR实现有,刚好项目也需要这个功能,就自己实现了。至于如果你想像MPR那样联动位置的话,就要用 vtk.js实现了。