eDICOMViewer

Element Value 수정 추가

5월 8, 2018 eDICOMViewer No comments

1.vex-dialog input에서 read only인 text 구분을 위해 text color를 변경
div tag의 class vex-dialog-input하위의 input tag중 read-only attribute를 가지는 tag만 변경 시도

div.vex-dialog-input>input:read-only{
    color: #808080;
}

2.추가로 실제 row 값을 변경 후 table에 redraw를 위해 아래와 같이 row의 invalidate 사용

///modify
rowData['value'] = data.value.trim();
nodeDCMTK.SetElementValue(ID2Elements[id], rowData['value']);
row.invalidate().draw();

npm rebuild후 Node Version Error 해결

4월 23, 2018 eDICOMViewer No comments

1. 기존 source를 새로운 directory로 clone후 rebuild를 아래와 같이 수행

//npm install로 재설치
$npm install

//electron-rebuild수행
$./node_modules/.bin/electron-rebuild

//webpack 수행
$webpack

2. electron 수행시 Console에 아래와 같이 오류 발생
was compiled against a different Node.js version using
NODE_MODULE_VERSION 57. This version of Node.js requires
NODE_MODULE_VERSION 54. Please try re-compiling or re-installing

3. electron-rebuild 수행시 -v를 통해 현재 electron version 설정하여 rebuild 수행

//electron-rebuild수행
$./node_modules/.bin/electron-rebuild -v 1.7.10

4.정상 수행

참고)
electron version은 process.versions로 확인 가능

// Debugging
log.debug(process.versions);

Element Value 수정 및 Save File

4월 20, 2018 eDICOMViewer No comments

1.먼저 수정하고자 선택한 DICOM Element를 가져오기 위해
고유 ID에 dcmElementPtr을 Table에 row 추가시 dictionary로 저장

var ID2Elements = {};
function loadDICOMFileHierarchy(fileName){
    ///load시 재 초기화
    ID2Elements = {};
}

function AddTableRow(dcmElementPtr, level, parentRow, id, isLeaf){
    ///insert to dictionary
    ID2Elements[id] = dcmElementPtr;
    ...
}

2.수정 popup에서 ok후 rowData 및 SetElementValue()로 실제 DcmElement에 update

...
callback: function (data) {
            if (!data) 
                return;
                
            ///modify
            rowData['value'] = data.value.trim();
            nodeDCMTK.SetElementValue(ID2Elements[id], rowData['vr']);
}

3.SetElementValue()는 아래 형태로 수정

int SetElementValue(void* elementPtr, char* value)
{
	DcmElement* pElement = (DcmElement*)elementPtr;
	if (pElement == NULL)
		return 0;

	try
	{
		OFCondition status = pElement->putString(value);
		if (!status.good())
			return 0;
	}
	catch (...)
	{
		OutputDebugStringA("SetElementValue Exception!");
		return 0;
	}
	return 1;
}

4.File Save를 위해 menu에 save file…기능 추가

{
    label: 'Save File...',
    click: ()=>{
        var fileName=[];
        fileName = dialog.showSaveDialog({
            properties: ['saveFile'],
            filters: [
                {name: 'DICOM', extensions: ['dcm', 'dic']},
                {name: 'All Files', extensions: ['*']}
                ]
        }); 
        if(fileName == null)
            return;
        
        dcmTK.saveDICOMFile(fileName);
    }
},

5.SaveDICOMFile()함수는 아래 형태로 구현


int SaveDcmFileFormat(void* dcmPtr, char* fileName)
{
	DcmFileFormat* pDcmFileFormat = (DcmFileFormat*)dcmPtr;
	if (pDcmFileFormat == NULL)
		return 0;

	try
	{
		OFFilename *pOFFileName = new OFFilename(fileName);
		OFCondition status = pDcmFileFormat->saveFile(*pOFFileName);
		if (!status.good())
			return 0;
	}
	catch (...)
	{
		OutputDebugStringA("SaveDcmFileFormat::saveFile Exception!");
	}
	return 1;
}

7.수정된 DICOM 파일로 정상 저장 됨

modify form 만들기

4월 5, 2018 eDICOMViewer No comments

table row에 double click event시 modify form 띄우기

1.dataTable에 double click event 연동
event : dblclick
selector : tr

//double click
$('#Elements tbody').on('dblclick', 'tr', function(){
    var tr = $(this);
    var row = elementTable.row( tr );
    var rowId = dcmTK.GetRowId(row);
    if(!dcmTK.ShowEditForm(row))
        return;
});

2.nodeDCMTK module에 ShowEditForm()함수 추가. row.data()를 통해 실제 각 column에 해당하는 data 접근

function ShowEditForm(row){
    var rowData = row.data();
}

3. vex.defaultOptions.className = 'vex-theme-top';를 통해 top theme적용 하고 dialog 출력

    vex.defaultOptions.className = 'vex-theme-top';
    vex.dialog.open({
        message: 'Modify Element Value',
        input: [
            '<label for="tag">TAG</label><input name="tag" type="text" value="{0}" readonly/>'.format(tag),
            '<label for="name">Name</label><input name="name" type="text" value="{0}" readonly/>'.format(name),
            '<label for="vr">VR</label><input name="vr" type="text" value="{0}" readonly />'.format(vr),
            '<label for="value">Value</label><input name="value" type="text" value="{0}"  />'.format(value)
        ].join(''),
        buttons: [
            $.extend({}, vex.dialog.buttons.YES, { text: 'OK' }),
            $.extend({}, vex.dialog.buttons.NO, { text: 'Cancel' })
        ],
        callback: function (data) {
            if (!data) 
                return;
                
            console.log('value=', data.value);
        }
    });

4.여기서 기존 row.data()의 data형태가 byte array이고 toString()시 끝에 빈 문자열이 붙는 문제
제거를 위해 아래 두 함수 이용

function strlen(str){
  var stringByteLength = (function(s,b,i,c){
    for(b=i=0;c=s.charCodeAt(i++);b+=c>>11?3:c>>7?2:1);
    return b
  })(str);
  return stringByteLength;
}

function trim(str){
  var len = this.strlen(str);
  return str.substring(0, len);
}

5.최종 dialog open 함수

function ShowEditForm(row){
    var rowData = row.data();
    var tag = util.trim(rowData['tag'].toString('utf8'));
    var name = util.trim(rowData['name'].toString('utf8'));
    var vr = util.trim(rowData['vr'].toString('utf8'));
    var value = util.trim(rowData['value'].toString('utf8'));

    vex.defaultOptions.className = 'vex-theme-top';
    vex.dialog.open({
        message: 'Modify Element Value',
        input: [
            '<label for="tag">TAG</label><input name="tag" type="text" value="{0}" readonly/>'.format(tag),
            '<label for="name">Name</label><input name="name" type="text" value="{0}" readonly/>'.format(name),
            '<label for="vr">VR</label><input name="vr" type="text" value="{0}" readonly />'.format(vr),
            '<label for="value">Value</label><input name="value" type="text" value="{0}"  />'.format(value)
        ].join(''),
        buttons: [
            $.extend({}, vex.dialog.buttons.YES, { text: 'OK' }),
            $.extend({}, vex.dialog.buttons.NO, { text: 'Cancel' })
        ],
        callback: function (data) {
            if (!data) 
                return;
                
            console.log('value=', data.value);
        }
    });
    return true;
}

6.최종 결과 화면

vex를 이용한 confirm dialog 띄우기

4월 4, 2018 eDICOMViewer No comments

vex를 활용하여 confirm dialog 띄우기

1.npm으로 vex-js 설치

$ npm install -save vex-js

2.테스트용으로 기존 File메뉴 하위로 Exit 메뉴 추가

menu.append(new MenuItem({
    label:'File', 
    submenu: [
        ...
    {
        label: "Exit",
        click: ()=>{
        
            });
        }
    }
...

3.vex import 추가
먼저 vex-js 부터 require() 이후 css를 import 수행 해야 정상 인식

var vex = require('vex-js')
import 'vex-js/dist/css/vex.css';
import 'vex-js/dist/css/vex-theme-os.css';
vex.registerPlugin(require('vex-dialog'));
vex.defaultOptions.className = 'vex-theme-os';

4. Exit Menu에 confirm dialog 추가

{
    label: "Exit",
    click: ()=>{
        vex.dialog.confirm({
            message: 'Are you want to exit eDICOM Viewer?',
            callback: function (value) {
                if (value != true) 
                    return;
                        
                remote.getCurrentWindow().close();
            }
        });
}

5.결과 화면

참고) 테스용으로 exit에 confirm 추가. 추 후 changed file save로 변경 예정

electron main process debug log 출력

3월 7, 2018 eDICOMViewer No comments

electron main process의 debugging을 위해서 log를 출력 하기

1.npm으로 electron-log 설치 (github)

$ npm install -s electron-log

2.main.js에 electron-log를 require()로 추가. 단 현재 eDICOMViewer의 path상 직접 node_modules로 path 설정

var log = require('./JS/node_modules/electron-log');

3.log 출력시

log.debug('createWindow');

4.출력은 electron을 실행한 console(or power shell) 화면에 출력 됨

DataTable style 설정

3월 2, 2018 eDICOMViewer No comments

1. Data Table의 Style을 bootloader의 black table theme 형태 적용
index.html에서 table에 class 추가
table-dark : dark theme
table-striped : 짝수, 홀수 line bgcolor 변경
table-hover : Mouse hover시 색 변경

<table id="Elements" class="table table-dark table-striped table-hover" cellspacing="0" width="100%">
</table>

2.Data Table에 table-striped설정시 even에만 color 설정이 적용되지 않음.
문제 화면

3.even row에 css에 color설정 추가. 기존 bootstrap에서 설정 한 background-coloroverwrite하기 위해 !important추가 함

tr.even {
    background-color: #202020!important;
}

4.기타 child item은 odd, even에 따라 color 구분하고, mouse hover시 color로 변경
tr tag안에 class에 even + childitem class를 접근하기 위해 tr.even.childitem 으로 접근

tr.even.childitem{
    background-color: #303030!important;
}

tr.odd.childitem{
    background-color: #707070!important;
}

tr.even:hover {
    background-color: #505050!important;
}

tr.odd:hover {
    background-color: #505050!important;
}

5.child item open, close용 icon을 대신 codepen sample을 적용(https://codepen.io/murphyrandle/pen/wvCgI?q=open&limit=all&type=type-pens)

6.codepen에서 제공하는 scss는 css로 compile후에 source로 삽입

* {
  box-sizing: border-box;
}

html {
  background-color: #C9353B;
}

.open-close-button {
  display: inline-block;
 ...
}
.open-close-button:before {
...
  top: 47%;
}
.open-close-button:after {
}

7.open close는 class open만 추가하기에, index.js에 추가

$('#Elements tbody').on('click', 'td.details-control', function () {
        ...
        $(this).children('.open-close-button').toggleClass('open');
        ...
}

9.child item을 다시 show시 color 변경되는 css animation 추가

@keyframes example {
    from {background-color: initial;}
    to {background-color: #606060;}
}

tr.childitem{
    background-color: #606060!important;
    animation-name: example;
    animation-duration: 0.5s;
    animation-play-state: running;
}

10.최종 적용된 table

child item show&hide 기능 추가

2월 26, 2018 eDICOMViewer No comments

child item을 show & hide를 수행하기 위해

1. 먼저 child item tag를 row로 추가시 아래와 같이 parentid attribute를 추가
RowId는 DataTable의 row.id()를 사용

function SetRowId(row, id){
    return row.nodes().to$().attr("parentid", id);
}

var row = parentRow.table().row.add({
           ...
}).draw(false);

///Add explicitly
SetRowId(row, GetRowId(parentRow));

2.추가된 row는 hide 상태로 표시

row.nodes().to$().hide();

3.open, closed icon인 details-control class의 click event에서 tr과 row 구하기

// Add event listener for opening and closing details
$('#Elements tbody').on('click', 'td.details-control', function () {
    var tr = $(this).closest('tr');
    var row = elementTable.row( tr );
    ...
} );

4.row의 class상태가 opend인지 closed인지 확인 하여 해당 parentid로 개별 row의 값을 show(), hide()수행

var parentid = dcmTK.GetRowId(row);
if(dcmTK.IsRowOpend(row))
{
    dcmTK.SetOpenClosed(row, 'closed');
    $('[parentid={0}]'.format(parentid)).each(function(){
        $(this).show();
    });
}
else if(dcmTK.IsRowClosed(row))
{
    dcmTK.SetOpenClosed(row, 'opend');
    $('[parentid={0}]'.format(parentid)).each(function(){
        $(this).hide();
    });
}

5.결과화면

DataTable row에 id 추가

2월 22, 2018 eDICOMViewer No comments

추후 id를 통해 수정 및 다양한 control 수행하기 위해 row의 각 element tag에 고유 id값을 삽입

1. DataTable propertie에 rowId를 추가, rowId를 사용할 data를 선택
column에 id를 추가 후 visible false로 설정하여 화면으로는 표시되지 않도록 설정

elementTable = $('#Elements').DataTable({
    paging: false,
    searching: false,
    ordering: false,
    rowId: 'id',
    columns: [
        { data: "id", visible: false },
        { title: "Elment Tag", data: "tag" },
        { title: "Tag Name", data: "name" },
        { title: "VR", data: "vr" },
        { title: "Value", data: "value" }
    ]
});

2.아래 화면과 같이 id는 td에도 없고, tr(row)에만 id가 추가 됨

DataTable에 name 통해 add row 수행

2월 22, 2018 eDICOMViewer No comments

1.기존 array형태로 add row 하는 방식이 아닌 id와 같은 name을 통해서 add 하도록 구현

2.DataTable()생성시 properties에 column안에
title은 화면에 표시되는 Text를
data는 id에 해당하는 값을 설정

elementTable = $('#Elements').DataTable({
    paging: false,
    searching: false,
    ordering: false,
    columns: [
        { title: "Elment Tag", data: "tag" },
        { title: "Tag Name", data: "name" },
        { title: "VR", data: "vr" },
        { title: "Value", data: "value" }
    ]
});

3.add row시 각 data에 해당하는 항목을 dictionary 형태로 전달

table().row.add({
    "tag": elementText,
    "name": elementName.toString('utf8'),
    "vr": vr.toString('utf8'),
    "value": value.toString('utf8'),
}).draw(false);