tests_pacs_viewer.ui.annot.js
// Do not warn if these variables were not defined before.
/* global dwv */
// namespace
// eslint-disable-next-line no-var
var test = test || {};
test.dataModelUI = test.dataModelUI || {};
/**
* Get the annotation group divId.
*
* @param {string} dataId The data ID.
* @returns {string} The divId.
*/
function getAnnotationGroupDivId(dataId) {
return 'annotationgroup' + dataId;
}
/**
* Get the annotation divId.
*
* @param {Annotation} annotation The annotation.
* @param {string} dataId The data ID.
* @returns {string} The divId.
*/
function getAnnotationDivId(annotation, dataId) {
const prefix = getAnnotationGroupDivId(dataId);
const suffix = 'annotation' + annotation.id;
return prefix + '-' + suffix;
}
/**
* Split a divId to get dataId and annotationId.
*
* @param {string} divId The divId.
* @returns {object} The data and annotation ID.
*/
function splitAnnotationDivId(divId) {
const split = divId.split('-');
const prefixStrSize = 'annotationgroup'.length;
const suffixStrSize = 'annotation'.length;
return {
dataId: split[0].substring(prefixStrSize),
annotationId: split[1].substring(suffixStrSize)
};
}
/**
* Annotation UI.
*
* @param {object} app The associated application.
*/
test.dataModelUI.Annotation = function (app) {
/**
* Bind app to ui.
*/
this.registerListeners = function () {
app.addEventListener('dataadd', onDataAdd);
app.addEventListener('annotationadd', onAnnotationAdd);
app.addEventListener('annotationupdate', onAnnotationUpdate);
app.addEventListener('annotationremove', onAnnotationRemove);
};
/**
* Setup the html for the annotation list.
*/
function setupHtml() {
// add annotation group button
const addItem = document.createElement('li');
addItem.id = 'addannotationgroupitem';
const addAnnotationGroupButton = document.createElement('button');
addAnnotationGroupButton.appendChild(
document.createTextNode('Add annotation group'));
addAnnotationGroupButton.onclick = function () {
const divId = 'layerGroup0';
const layerGroup = app.getLayerGroupByDivId(divId);
// add annotation group
const viewLayer = layerGroup.getActiveViewLayer();
const refDataId = viewLayer.getDataId();
const data = app.createAnnotationData(refDataId);
// render (will create draw layer)
app.addAndRenderAnnotationData(data, divId, refDataId);
// item is added to the UI by the 'dataadd' listener
};
addItem.appendChild(addAnnotationGroupButton);
// annotation list
const annotList = document.createElement('ul');
annotList.id = 'annotationgroup-list';
annotList.appendChild(addItem);
// fieldset
const legend = document.createElement('legend');
legend.appendChild(document.createTextNode('Annotation Groups'));
const fieldset = document.createElement('fieldset');
fieldset.appendChild(legend);
fieldset.appendChild(annotList);
// panel div
const panel = document.getElementById('annotationgroups-panel');
panel.appendChild(fieldset);
}
/**
* Get the annotation html.
*
* @param {Annotation} annotation The annotation.
* @param {string} dataId The annotation group dataId.
* @returns {HTMLSpanElement} The HTMl element.
*/
function getAnnotationHtml(annotation, dataId) {
const annotationDivId = getAnnotationDivId(annotation, dataId);
const viewButton = document.createElement('button');
viewButton.style.borderStyle = 'outset';
const vbIdPrefix = 'vb-';
viewButton.id = vbIdPrefix + annotationDivId;
viewButton.title = 'Show/hide annotation';
viewButton.appendChild(document.createTextNode('\u{1F441}\u{FE0F}'));
viewButton.onclick = function (event) {
const target = event.target;
// get annotatio
const indices =
splitAnnotationDivId(target.id.substring(vbIdPrefix.length));
const dataId = indices.dataId;
const annotationId = indices.annotationId;
const drawLayers = app.getDrawLayersByDataId(dataId);
// toggle hidden
const isPressed = target.style.borderStyle === 'inset';
if (isPressed) {
target.style.borderStyle = 'outset';
for (const layer of drawLayers) {
layer.setAnnotationVisibility(annotationId, true);
}
} else {
target.style.borderStyle = 'inset';
for (const layer of drawLayers) {
layer.setAnnotationVisibility(annotationId, false);
}
}
};
const inputColour = document.createElement('input');
inputColour.type = 'color';
inputColour.title = 'Change annotation colour';
const inputColourPrefix = 'cb-';
inputColour.id = inputColourPrefix + annotationDivId;
inputColour.value = annotation.colour;
inputColour.onchange = function (event) {
const target = event.target;
const newColour = target.value;
// get annotation
const indices =
splitAnnotationDivId(target.id.substring(inputColourPrefix.length));
const dataId = indices.dataId;
const annotationId = indices.annotationId;
const annotationGroup = app.getData(dataId).annotationGroup;
const annotation = annotationGroup.find(annotationId);
// update
if (newColour !== annotation.colour) {
const drawController = new dwv.DrawController(annotationGroup);
drawController.updateAnnotationWithCommand(
annotationId,
{colour: annotation.colour},
{colour: newColour},
app.addToUndoStack
);
}
};
const gotoButton = document.createElement('button');
const gbIdPrefix = 'gotob-';
gotoButton.id = gbIdPrefix + annotationDivId;
gotoButton.title = 'Goto annotation';
gotoButton.appendChild(document.createTextNode('\u{1F3AF}'));
gotoButton.onclick = function (event) {
const target = event.target;
// get annotation
const indices =
splitAnnotationDivId(target.id.substring(gbIdPrefix.length));
const dataId = indices.dataId;
const annotationId = indices.annotationId;
const annotationGroup = app.getData(dataId).annotationGroup;
const annotation = annotationGroup.find(annotationId);
const annotCentroid = annotation.getCentroid();
if (typeof annotCentroid !== 'undefined') {
const drawLayers = app.getDrawLayersByDataId(dataId);
for (const layer of drawLayers) {
layer.setCurrentPosition(annotCentroid);
}
} else {
console.log('No centroid for annotation');
}
};
const deleteButton = document.createElement('button');
const dbIdPrefix = 'db-';
deleteButton.id = dbIdPrefix + annotationDivId;
deleteButton.title = 'Delete annotation';
deleteButton.appendChild(document.createTextNode('\u{274C}'));
deleteButton.onclick = function (event) {
const target = event.target;
// get segment and mask
const indices =
splitAnnotationDivId(target.id.substring(dbIdPrefix.length));
const dataId = indices.dataId;
const annotationId = indices.annotationId;
// delete if possible
const drawController = new dwv.DrawController(
app.getData(dataId).annotationGroup);
drawController.removeAnnotationWithCommand(
annotationId,
app.addToUndoStack
);
};
// disable/enable buttons if group is editable or not
const annotationGroup = app.getData(dataId).annotationGroup;
annotationGroup.addEventListener(
'annotationgroupeditablechange', function (event) {
const disabled = !event.data;
inputColour.disabled = disabled;
deleteButton.disabled = disabled;
}
);
const span = document.createElement('span');
span.id = 'span-' + annotationDivId;
span.appendChild(document.createTextNode(
annotation.id + ' (' + annotation.getFactory().getName() + ')'));
span.appendChild(viewButton);
span.appendChild(inputColour);
span.appendChild(gotoButton);
span.appendChild(deleteButton);
return span;
}
/**
* Get an annotation group html.
*
* @param {AnnotationGroup} annotationGroup The annotation group.
* @param {string} dataId The annotation group dataId.
* @returns {HTMLIement} The annotation list element.
*/
function getAnnotationGroupHtml(annotationGroup, dataId) {
const item = document.createElement('li');
item.id = 'li-' + getAnnotationGroupDivId(dataId);
const lockButton = document.createElement('button');
lockButton.style.borderStyle = 'outset';
lockButton.id = 'lockb-' + getAnnotationGroupDivId(dataId);
lockButton.appendChild(document.createTextNode('\u{1F512}'));
lockButton.onclick = function (event) {
const target = event.target;
// toggle hidden
const isPressed = target.style.borderStyle === 'inset';
if (isPressed) {
target.style.borderStyle = 'outset';
if (typeof annotationGroup !== 'undefined') {
annotationGroup.setEditable(true);
}
} else {
target.style.borderStyle = 'inset';
if (typeof annotationGroup !== 'undefined') {
annotationGroup.setEditable(false);
}
}
};
item.appendChild(lockButton);
// save segment button
const saveButton = document.createElement('button');
saveButton.appendChild(document.createTextNode('\u{1F4BE}'));
saveButton.title = 'Save annnotation group';
saveButton.onclick = function () {
const factory = new dwv.AnnotationGroupFactory();
const dicomElements = factory.toDicom(annotationGroup);
// write
const writer = new dwv.DicomWriter();
let dicomBuffer = null;
try {
dicomBuffer = writer.getBuffer(dicomElements);
} catch (error) {
console.error(error);
alert(error.message);
}
const blob = new Blob([dicomBuffer], {type: 'application/dicom'});
saveButton.href = window.URL.createObjectURL(blob);
// temporary link to download
const element = document.createElement('a');
element.href = window.URL.createObjectURL(blob);
element.download = 'dicom-sr-' + dataId + '.dcm';
// trigger download
element.click();
URL.revokeObjectURL(element.href);
};
item.appendChild(saveButton);
const hideLabelsButton = document.createElement('button');
hideLabelsButton.style.borderStyle = 'outset';
hideLabelsButton.id = 'b-hidelabels';
hideLabelsButton.title = 'Show/hide annotation labels';
hideLabelsButton.appendChild(document.createTextNode('\u{1F3F7}\u{FE0F}'));
hideLabelsButton.onclick = function (event) {
const target = event.target;
const drawLayer = app.getDrawLayersByDataId(dataId)[0];
if (typeof drawLayer === 'undefined') {
console.warn('Cannot find draw layer with id ' + dataId);
}
const isPressed = target.style.borderStyle === 'inset';
if (isPressed) {
target.style.borderStyle = 'outset';
drawLayer.setLabelsVisibility(true);
} else {
target.style.borderStyle = 'inset';
drawLayer.setLabelsVisibility(false);
}
};
item.appendChild(hideLabelsButton);
for (const annotation of annotationGroup.getList()) {
item.appendChild(getAnnotationHtml(annotation, dataId));
}
return item;
};
/**
* Handle 'dataadd' event.
*
* @param {object} event The event.
*/
function onDataAdd(event) {
const data = app.getData(event.dataid);
const ag = data.annotationGroup;
if (typeof ag !== 'undefined') {
// setup html if needed
if (!document.getElementById('annotationgroup-list')) {
setupHtml();
}
// annotation group as html
const item = getAnnotationGroupHtml(ag, event.dataid);
// add annotation group item
const addItem = document.getElementById('addannotationgroupitem');
// remove and add after to make it last item
addItem.remove();
// update list
const annotList = document.getElementById('annotationgroup-list');
annotList.appendChild(item);
annotList.appendChild(addItem);
}
};
/**
* Handle 'annotationadd' event.
*
* @param {object} event The event.
*/
function onAnnotationAdd(event) {
const annotation = event.data;
const dataId = event.dataid;
// add annotation html to list
const annotationGroupDivId = 'li-' + getAnnotationGroupDivId(dataId);
const item = document.getElementById(annotationGroupDivId);
item.appendChild(getAnnotationHtml(annotation, dataId));
};
/**
* Handle 'annotationupdate' event.
*
* @param {object} event The event.
*/
function onAnnotationUpdate(event) {
const annotation = event.data;
const dataId = event.dataid;
const keys = event.keys;
if (typeof keys !== 'undefined') {
const annotationDivId = getAnnotationDivId(annotation, dataId);
// update colour input
if (keys.includes('colour')) {
const inputColour = document.getElementById('cb-' + annotationDivId);
inputColour.value = annotation.colour;
}
}
};
/**
* Handle 'annotationremove' event.
*
* @param {object} event The event.
*/
function onAnnotationRemove(event) {
const annotation = event.data;
const dataId = event.dataid;
// remove annotation from list
const annotationDivId = 'span-' + getAnnotationDivId(annotation, dataId);
const item = document.getElementById(annotationDivId);
item.remove();
};
}; // test.dataModelUI.Annotation