if (element === undefined) {
throw new Error('enable: parameter element cannot be undefined');
}
// If this enabled element has the option set for WebGL, we should
// Check if this device actually supports it
// 如果设定webgl选项,判定浏览器是否支持webgl
if (options && options.renderer && options.renderer.toLowerCase() === 'webgl') {
if (webGL.renderer.isWebGLAvailable()) {
// If WebGL is available on the device, initialize the renderer
// And return the renderCanvas from the WebGL rendering path
webGL.renderer.initRenderer();
options.renderer = 'webgl';
} else {
// If WebGL is not available on this device, we will fall back
// To using the Canvas renderer
console.error('WebGL not available, falling back to Canvas renderer');
delete options.renderer;
}
}
const canvas = document.createElement('canvas');
element.appendChild(canvas);
const enabledElement = {
element,
canvas,
image: undefined, // Will be set once image is loaded
invalid: false, // True if image needs to be drawn, false if not
needsRedraw: true,
options,
layers: [],
data: {},
renderingTools: {}
};
export function addEnabledElement (enabledElement) {
if (enabledElement === undefined) {
throw new Error('getEnabledElement: enabledElement element must not be undefined');
}
enabledElements.push(enabledElement);
}
关于根据对应的element查找对应的enabledElement对象的方法:
/**
* Retrieves a Cornerstone Enabled Element object
*
* @param {HTMLElement} element An HTML Element enabled for Cornerstone
*
* @returns {EnabledElement} A Cornerstone Enabled Element
*/
export function getEnabledElement (element) {
if (element === undefined) {
throw new Error('getEnabledElement: parameter element must not be undefined');
}
for (let i = 0; i < enabledElements.length; i++) {
if (enabledElements[i].element === element) {
return enabledElements[i];
}
}
throw new Error('element not enabled');
}
/**
* Adds a Cornerstone Enabled Element object to the central store of enabledElements
*
* @param {string} imageId A Cornerstone Image ID
* @returns {EnabledElement[]} An Array of Cornerstone enabledElement Objects
*/
export function getEnabledElementsByImageId (imageId) {
const ees = [];
enabledElements.forEach(function (enabledElement) {
if (enabledElement.image && enabledElement.image.imageId === imageId) {
ees.push(enabledElement);
}
});
return ees;
}
/**
* Retrieve all of the currently enabled Cornerstone elements
*
* @return {EnabledElement[]} An Array of Cornerstone enabledElement Objects
*/
export function getEnabledElements () {
return enabledElements;
}
/**
* This module is responsible for enabling an element to display images with cornerstone
*
* @param {HTMLElement} element The DOM element enabled for Cornerstone
* @param {HTMLElement} canvas The Canvas DOM element within the DOM element enabled for Cornerstone
* @returns {void}
*/
function setCanvasSize (element, canvas) {
// The device pixel ratio is 1.0 for normal displays and > 1.0
// For high DPI displays like Retina
/*
This functionality is disabled due to buggy behavior on systems with mixed DPI's. If the canvas
is created on a display with high DPI (e.g. 2.0) and then the browser window is dragged to
a different display with a different DPI (e.g. 1.0), the canvas is not recreated so the pageToPixel
produces incorrect results. I couldn't find any way to determine when the DPI changed other than
by polling which is not very clean. If anyone has any ideas here, please let me know, but for now
we will disable this functionality. We may want
to add a mechanism to optionally enable this functionality if we can determine it is safe to do
so (e.g. iPad or iPhone or perhaps enumerate the displays on the system. I am choosing
to be cautious here since I would rather not have bug reports or safety issues related to this
scenario.
var devicePixelRatio = window.devicePixelRatio;
if(devicePixelRatio === undefined) {
devicePixelRatio = 1.0;
}
*/
// Avoid setting the same value because it flashes the canvas with IE and Edge
if (canvas.width !== element.clientWidth) {
canvas.width = element.clientWidth;
canvas.style.width = `${element.clientWidth}px`;
}
// Avoid setting the same value because it flashes the canvas with IE and Edge
if (canvas.height !== element.clientHeight) {
canvas.height = element.clientHeight;
canvas.style.height = `${element.clientHeight}px`;
}
}
/**
* Resizes an enabled element and optionally fits the image to window
*
* @param {HTMLElement} element The DOM element enabled for Cornerstone
* @param {Boolean} fitViewportToWindow true to refit, false to leave viewport parameters as they are
* @returns {void}
*/
export default function (element, fitViewportToWindow) {
const enabledElement = getEnabledElement(element);
// 每次更改element,重新设定canvas的宽高,不然这时候dicom图片可能显示不完全
setCanvasSize(element, enabledElement.canvas);
const eventData = {
element
};
// 发出cornerstoneelementresized事件
triggerEvent(element, 'cornerstoneelementresized', eventData);
// 必须保证有image对象
if (enabledElement.image === undefined) {
return;
}
// 是否要重设viewport
if (fitViewportToWindow === true) {
fitToWindow(element);
} else {
updateImage(element);
}
}
/**
* Retrieves the current image dimensions given an enabled element
*
* @param {EnabledElement} enabledElement The Cornerstone Enabled Element
* @return {{width, height}} The Image dimensions
*/
function getImageSize (enabledElement) {
// 正立或倒立,宽就是宽,高就是高
if (enabledElement.viewport.rotation === 0 || enabledElement.viewport.rotation === 180) {
return {
width: enabledElement.image.width,
height: enabledElement.image.height
};
}
// 如果旋转过90度,则宽高互换
return {
width: enabledElement.image.height,
height: enabledElement.image.width
};
}
/**
* Adjusts an image's scale and translation so the image is centered and all pixels
* in the image are viewable.
*
* @param {HTMLElement} element The Cornerstone element to update
* @returns {void}
*/
export default function (element) {
// fitToWindow主要就是做对于viewport的重新设定
const enabledElement = getEnabledElement(element);
const imageSize = getImageSize(enabledElement);
const verticalScale = enabledElement.canvas.height / imageSize.height;
const horizontalScale = enabledElement.canvas.width / imageSize.width;
// The new scale is the minimum of the horizontal and vertical scale values
enabledElement.viewport.scale = Math.min(horizontalScale, verticalScale);
enabledElement.viewport.translation.x = 0;
enabledElement.viewport.translation.y = 0;
updateImage(element);
}
updateImage()方法则是核心,这里初看很简单,重点在下面:
/**
* Forces the image to be updated/redrawn for the specified enabled element
* @param {HTMLElement} element An HTML Element enabled for Cornerstone
* @param {Boolean} [invalidated=false] Whether or not the image pixel data has been changed, necessitating a redraw
*
* @returns {void}
*/
export default function (element, invalidated = false) {
const enabledElement = getEnabledElement(element);
if (enabledElement.image === undefined && !enabledElement.layers.length) {
throw new Error('updateImage: image has not been loaded yet');
}
drawImage(enabledElement, invalidated);
}
/**
* Internal API function to draw an image to a given enabled element
*
* @param {EnabledElement} enabledElement The Cornerstone Enabled Element to redraw
* @param {Boolean} [invalidated] - true if pixel data has been invalidated and cached rendering should not be used
* @returns {void}
*/
export default function (enabledElement, invalidated = false) {
enabledElement.needsRedraw = true;
if (invalidated) {
enabledElement.invalid = true;
}
}
cornerstone enable API
在每次
loadImage
之前都需要进行enable
,至于enable
到底做了哪些事情,对外来说确实是不可见的。canvas
节点enabledElement
对象cornerstone
存储enabledElement
列表创建canvas节点
创建canvas节点前,首先判断这个element是否存在,如果存在,继续看是否
option
是否有webgl
的option
。之后创建节点,并置为enabled element
的子节点。初始化
enabledElement
对象enabledElement
的作用是在cornerstone
内部缓存与当前element
相关的信息,包含是否需要刷新,image
对象,viewport
对象,element
和canvas
节点等。全局
cornerstone
存储enabledElement
列表在
enabledElements.js
提供了多个工具函数,用于获取到已经enable
过的enabledElement
对象:首先会把所有
enable
过的enabledElement
放在一个Array
内:在初始化的时候,会调用
addEnabledElement(enabledElement)
方法,把enabledElement
放入数组:addEnabledElement(enabledElement)
方法也很简单:关于根据对应的
element
查找对应的enabledElement
对象的方法:其实在这里发现每次查找都经历过一个循环,是否可以考虑更改为
key-value
。以imageId
作key
。在
enabledElements
初始化之后,会触发一次resize()
,这时会设定canvas
节点的宽高,这就是为何建议把element
宽高定死的原因了:如果
resize()
设定第二个参数fitViewportToWindow
为true
,则会触发重设viewport
的计算,如果没有设定(一般来说是宽高未改变的情况),这时不需要重设viewport
对象。而在fitToWindow()
方法里面则是显式调用过fitToWindow(element)
:updateImage()
方法则是核心,这里初看很简单,重点在下面:重点是
drawImage(enabledElement, invalidated)
方法的needsRedraw
和invalidated
,这里简单的把这两个参数设定为true
,是为了在下面的draw
方法使用。初始化事件,轮询是否需要更新图片
这是一个永远在轮询的操作,或许这就是
cornerstone
为何在运转太久不刷新页面之后会卡死的原因了。一旦我们调用
updateImage()
,提示需要重绘,则会在下一次轮询到draw()
触发的时候调用drawImageSync(enabledElement, enabledElement.invalid)
方法进行画图。思考:两点优化
enabledElement
的查找Vue
取消轮询机制