@lunit/insight-viewer
Advanced tools
Comparing version 1.1.4 to 1.2.0
@@ -7,2 +7,14 @@ # Changelog | ||
## [1.2.0] - 2019-04-29 | ||
### Added | ||
- `ContourLayer` 추가 | ||
- example app 추가 | ||
## [1.1.4] - 2019-04-19 | ||
### Fixed | ||
- 크롬 휠 이벤트가 passive로 바뀜에 따라 생긴 에러 메시지 제거 | ||
### Removed | ||
- `emotion` 의존성 제거 | ||
## [1.1.2] - 2018-12-03 | ||
@@ -22,3 +34,3 @@ ### Fixed | ||
### Fixed | ||
- 이미지 로드 전에 HeatmapLayer에 posMap을 전달할 경우 발생하는 에러 수정 | ||
- 이미지 로드 전에 `HeatmapLayer`에 posMap을 전달할 경우 발생하는 에러 수정 | ||
@@ -25,0 +37,0 @@ ## [1.0.7] - 2018-09-17 |
@@ -90,2 +90,44 @@ import * as dicomParser from 'dicom-parser'; | ||
var slicedToArray = function () { | ||
function sliceIterator(arr, i) { | ||
var _arr = []; | ||
var _n = true; | ||
var _d = false; | ||
var _e = undefined; | ||
try { | ||
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { | ||
_arr.push(_s.value); | ||
if (i && _arr.length === i) break; | ||
} | ||
} catch (err) { | ||
_d = true; | ||
_e = err; | ||
} finally { | ||
try { | ||
if (!_n && _i["return"]) _i["return"](); | ||
} finally { | ||
if (_d) throw _e; | ||
} | ||
} | ||
return _arr; | ||
} | ||
return function (arr, i) { | ||
if (Array.isArray(arr)) { | ||
return arr; | ||
} else if (Symbol.iterator in Object(arr)) { | ||
return sliceIterator(arr, i); | ||
} else { | ||
throw new TypeError("Invalid attempt to destructure non-iterable instance"); | ||
} | ||
}; | ||
}(); | ||
// cornerstone will mutate the viewport object | ||
@@ -366,2 +408,177 @@ setAutoFreeze(false); | ||
function drawContour(ctx, points, thickness) { | ||
ctx.beginPath(); | ||
ctx.moveTo(points[0][0], points[0][1]); | ||
points.forEach(function (_ref) { | ||
var _ref2 = slicedToArray(_ref, 2), | ||
x = _ref2[0], | ||
y = _ref2[1]; | ||
ctx.lineTo(x, y); | ||
}); | ||
ctx.lineTo(points[0][0], points[0][1]); | ||
ctx.closePath(); | ||
ctx.lineWidth = thickness; | ||
ctx.strokeStyle = 'black'; | ||
ctx.stroke(); | ||
ctx.lineWidth = thickness - 4; | ||
ctx.strokeStyle = 'white'; | ||
ctx.stroke(); | ||
} | ||
function drawAnnotation(ctx, annotation, scale) { | ||
var anchor = annotation.arrow_start; | ||
var foot = annotation.arrow_end; | ||
var valueText = Math.round(annotation.value * 100) + '%'; | ||
var isArrowToLeft = anchor[0] - foot[0] < 0; | ||
var length = Math.sqrt(Math.pow(anchor[0] - foot[0], 2) + Math.pow(anchor[1] - foot[1], 2)); | ||
var vectorX = (anchor[0] - foot[0]) / length; | ||
var vectorY = (anchor[1] - foot[1]) / length; | ||
var arrowX = vectorX * 16; | ||
var arrowY = vectorY * 16; | ||
ctx.save(); | ||
ctx.lineCap = 'square'; | ||
ctx.lineWidth = 6; | ||
ctx.strokeStyle = 'black'; | ||
ctx.beginPath(); | ||
ctx.moveTo(anchor[0] - arrowX, anchor[1] - arrowY); | ||
ctx.lineTo(foot[0], foot[1]); | ||
ctx.stroke(); | ||
ctx.lineWidth = 2; | ||
ctx.strokeStyle = 'white'; | ||
ctx.stroke(); | ||
// arrow head | ||
ctx.strokeStyle = 'black'; | ||
ctx.lineWidth = 2; | ||
ctx.fillStyle = 'white'; | ||
ctx.beginPath(); | ||
ctx.moveTo(anchor[0], anchor[1]); | ||
ctx.lineTo(anchor[0] - arrowX - arrowY * 0.5, anchor[1] - arrowY + arrowX * 0.5); | ||
ctx.lineTo(anchor[0] - arrowX + arrowY * 0.5, anchor[1] - arrowY - arrowX * 0.5); | ||
ctx.closePath(); | ||
ctx.fill(); | ||
ctx.stroke(); | ||
// text | ||
ctx.font = '24px proximanova_semibold, sans-serif'; | ||
ctx.strokeStyle = 'black'; | ||
ctx.lineWidth = 4; | ||
if (isArrowToLeft) { | ||
ctx.strokeText(valueText, foot[0] + 6, foot[1]); | ||
ctx.fillText(valueText, foot[0] + 6, foot[1]); | ||
} else { | ||
var textMetrics = ctx.measureText(valueText); | ||
ctx.strokeText(valueText, foot[0] - textMetrics.width - 6, foot[1]); | ||
ctx.fillText(valueText, foot[0] - textMetrics.width - 6, foot[1]); | ||
} | ||
ctx.restore(); | ||
} | ||
var Contour = function (_React$Component) { | ||
inherits(Contour, _React$Component); | ||
function Contour(props) { | ||
classCallCheck(this, Contour); | ||
var _this = possibleConstructorReturn(this, (Contour.__proto__ || Object.getPrototypeOf(Contour)).call(this, props)); | ||
_this._redraw = _this._redraw.bind(_this); | ||
_this._clear = _this._clear.bind(_this); | ||
return _this; | ||
} | ||
createClass(Contour, [{ | ||
key: 'componentDidUpdate', | ||
value: function componentDidUpdate(prevProps) { | ||
if (this.props.contours !== prevProps.contours || this.props.viewport !== prevProps.viewport || this.props.enabled !== prevProps.enabled) { | ||
this._clear(); | ||
if (Array.isArray(this.props.contours) && this.props.enabled) { | ||
this._redraw(this.props.enabledElement); | ||
} | ||
} | ||
} | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
var _this2 = this; | ||
return React.createElement('canvas', { ref: function ref(canvas) { | ||
_this2.drawingCanvas = canvas; | ||
}, | ||
style: { | ||
position: 'absolute', | ||
top: 0, | ||
left: 0, | ||
width: '100%', | ||
height: '100%' | ||
} }); | ||
} | ||
}, { | ||
key: '_redraw', | ||
value: function _redraw(enabledElement) { | ||
this.drawingCanvas.width = this.drawingCanvas.offsetWidth; | ||
this.drawingCanvas.height = this.drawingCanvas.offsetHeight; | ||
var scale = this.props.viewport.scale; | ||
var ctx = this.drawingCanvas.getContext('2d'); | ||
ctx.save(); | ||
setToPixelCoordinateSystem(enabledElement, ctx); | ||
ctx.scale(1 / scale, 1 / scale); | ||
this.props.contours.forEach(function (_ref3) { | ||
var contour = _ref3.contour, | ||
thickness = _ref3.thickness; | ||
contour.forEach(function (points) { | ||
var transformedPoints = points.map(function (point) { | ||
return [point[0] * scale, point[1] * scale]; | ||
}); | ||
drawContour(ctx, transformedPoints, thickness); | ||
}); | ||
}); | ||
this.props.annotations.forEach(function (annotation) { | ||
var scaledAnnotation = {}; | ||
scaledAnnotation.arrow_start = [annotation.arrow_start[0] * scale, annotation.arrow_start[1] * scale]; | ||
scaledAnnotation.arrow_end = [annotation.arrow_end[0] * scale, annotation.arrow_end[1] * scale]; | ||
scaledAnnotation.value = annotation.value; | ||
drawAnnotation(ctx, scaledAnnotation, scale); | ||
}); | ||
ctx.restore(); | ||
} | ||
}, { | ||
key: '_clear', | ||
value: function _clear() { | ||
var ctx = this.drawingCanvas.getContext('2d'); | ||
// Store the current transformation matrix | ||
ctx.save(); | ||
// Use the identity matrix while clearing the canvas | ||
ctx.setTransform(1, 0, 0, 1, 0, 0); | ||
ctx.clearRect(0, 0, this.drawingCanvas.width, this.drawingCanvas.height); | ||
// Restore the transform | ||
ctx.restore(); | ||
} | ||
}]); | ||
return Contour; | ||
}(React.Component); | ||
Contour.defaultProps = { | ||
contours: [], | ||
annotations: [] | ||
}; | ||
var Contour$1 = (function (props) { | ||
return React.createElement( | ||
ViewerContext.Consumer, | ||
null, | ||
function (_ref4) { | ||
var enabledElement = _ref4.enabledElement, | ||
viewport = _ref4.viewport; | ||
return React.createElement(Contour, _extends({}, props, { | ||
enabledElement: enabledElement, viewport: viewport })); | ||
} | ||
); | ||
}); | ||
var getRGBArray = function getRGBArray(value) { | ||
@@ -658,3 +875,3 @@ var r = 1.0; | ||
export { cornerstone, cornerstoneWADOImageLoader, Heatmap$1 as HeatmapLayer, Magnify$1 as MagnifyLayer }; | ||
export { cornerstone, cornerstoneWADOImageLoader, Contour$1 as ContourLayer, Heatmap$1 as HeatmapLayer, Magnify$1 as MagnifyLayer }; | ||
export default Viewer; |
@@ -95,2 +95,44 @@ 'use strict'; | ||
var slicedToArray = function () { | ||
function sliceIterator(arr, i) { | ||
var _arr = []; | ||
var _n = true; | ||
var _d = false; | ||
var _e = undefined; | ||
try { | ||
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { | ||
_arr.push(_s.value); | ||
if (i && _arr.length === i) break; | ||
} | ||
} catch (err) { | ||
_d = true; | ||
_e = err; | ||
} finally { | ||
try { | ||
if (!_n && _i["return"]) _i["return"](); | ||
} finally { | ||
if (_d) throw _e; | ||
} | ||
} | ||
return _arr; | ||
} | ||
return function (arr, i) { | ||
if (Array.isArray(arr)) { | ||
return arr; | ||
} else if (Symbol.iterator in Object(arr)) { | ||
return sliceIterator(arr, i); | ||
} else { | ||
throw new TypeError("Invalid attempt to destructure non-iterable instance"); | ||
} | ||
}; | ||
}(); | ||
// cornerstone will mutate the viewport object | ||
@@ -371,2 +413,177 @@ produce.setAutoFreeze(false); | ||
function drawContour(ctx, points, thickness) { | ||
ctx.beginPath(); | ||
ctx.moveTo(points[0][0], points[0][1]); | ||
points.forEach(function (_ref) { | ||
var _ref2 = slicedToArray(_ref, 2), | ||
x = _ref2[0], | ||
y = _ref2[1]; | ||
ctx.lineTo(x, y); | ||
}); | ||
ctx.lineTo(points[0][0], points[0][1]); | ||
ctx.closePath(); | ||
ctx.lineWidth = thickness; | ||
ctx.strokeStyle = 'black'; | ||
ctx.stroke(); | ||
ctx.lineWidth = thickness - 4; | ||
ctx.strokeStyle = 'white'; | ||
ctx.stroke(); | ||
} | ||
function drawAnnotation(ctx, annotation, scale) { | ||
var anchor = annotation.arrow_start; | ||
var foot = annotation.arrow_end; | ||
var valueText = Math.round(annotation.value * 100) + '%'; | ||
var isArrowToLeft = anchor[0] - foot[0] < 0; | ||
var length = Math.sqrt(Math.pow(anchor[0] - foot[0], 2) + Math.pow(anchor[1] - foot[1], 2)); | ||
var vectorX = (anchor[0] - foot[0]) / length; | ||
var vectorY = (anchor[1] - foot[1]) / length; | ||
var arrowX = vectorX * 16; | ||
var arrowY = vectorY * 16; | ||
ctx.save(); | ||
ctx.lineCap = 'square'; | ||
ctx.lineWidth = 6; | ||
ctx.strokeStyle = 'black'; | ||
ctx.beginPath(); | ||
ctx.moveTo(anchor[0] - arrowX, anchor[1] - arrowY); | ||
ctx.lineTo(foot[0], foot[1]); | ||
ctx.stroke(); | ||
ctx.lineWidth = 2; | ||
ctx.strokeStyle = 'white'; | ||
ctx.stroke(); | ||
// arrow head | ||
ctx.strokeStyle = 'black'; | ||
ctx.lineWidth = 2; | ||
ctx.fillStyle = 'white'; | ||
ctx.beginPath(); | ||
ctx.moveTo(anchor[0], anchor[1]); | ||
ctx.lineTo(anchor[0] - arrowX - arrowY * 0.5, anchor[1] - arrowY + arrowX * 0.5); | ||
ctx.lineTo(anchor[0] - arrowX + arrowY * 0.5, anchor[1] - arrowY - arrowX * 0.5); | ||
ctx.closePath(); | ||
ctx.fill(); | ||
ctx.stroke(); | ||
// text | ||
ctx.font = '24px proximanova_semibold, sans-serif'; | ||
ctx.strokeStyle = 'black'; | ||
ctx.lineWidth = 4; | ||
if (isArrowToLeft) { | ||
ctx.strokeText(valueText, foot[0] + 6, foot[1]); | ||
ctx.fillText(valueText, foot[0] + 6, foot[1]); | ||
} else { | ||
var textMetrics = ctx.measureText(valueText); | ||
ctx.strokeText(valueText, foot[0] - textMetrics.width - 6, foot[1]); | ||
ctx.fillText(valueText, foot[0] - textMetrics.width - 6, foot[1]); | ||
} | ||
ctx.restore(); | ||
} | ||
var Contour = function (_React$Component) { | ||
inherits(Contour, _React$Component); | ||
function Contour(props) { | ||
classCallCheck(this, Contour); | ||
var _this = possibleConstructorReturn(this, (Contour.__proto__ || Object.getPrototypeOf(Contour)).call(this, props)); | ||
_this._redraw = _this._redraw.bind(_this); | ||
_this._clear = _this._clear.bind(_this); | ||
return _this; | ||
} | ||
createClass(Contour, [{ | ||
key: 'componentDidUpdate', | ||
value: function componentDidUpdate(prevProps) { | ||
if (this.props.contours !== prevProps.contours || this.props.viewport !== prevProps.viewport || this.props.enabled !== prevProps.enabled) { | ||
this._clear(); | ||
if (Array.isArray(this.props.contours) && this.props.enabled) { | ||
this._redraw(this.props.enabledElement); | ||
} | ||
} | ||
} | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
var _this2 = this; | ||
return React.createElement('canvas', { ref: function ref(canvas) { | ||
_this2.drawingCanvas = canvas; | ||
}, | ||
style: { | ||
position: 'absolute', | ||
top: 0, | ||
left: 0, | ||
width: '100%', | ||
height: '100%' | ||
} }); | ||
} | ||
}, { | ||
key: '_redraw', | ||
value: function _redraw(enabledElement) { | ||
this.drawingCanvas.width = this.drawingCanvas.offsetWidth; | ||
this.drawingCanvas.height = this.drawingCanvas.offsetHeight; | ||
var scale = this.props.viewport.scale; | ||
var ctx = this.drawingCanvas.getContext('2d'); | ||
ctx.save(); | ||
cornerstone.setToPixelCoordinateSystem(enabledElement, ctx); | ||
ctx.scale(1 / scale, 1 / scale); | ||
this.props.contours.forEach(function (_ref3) { | ||
var contour = _ref3.contour, | ||
thickness = _ref3.thickness; | ||
contour.forEach(function (points) { | ||
var transformedPoints = points.map(function (point) { | ||
return [point[0] * scale, point[1] * scale]; | ||
}); | ||
drawContour(ctx, transformedPoints, thickness); | ||
}); | ||
}); | ||
this.props.annotations.forEach(function (annotation) { | ||
var scaledAnnotation = {}; | ||
scaledAnnotation.arrow_start = [annotation.arrow_start[0] * scale, annotation.arrow_start[1] * scale]; | ||
scaledAnnotation.arrow_end = [annotation.arrow_end[0] * scale, annotation.arrow_end[1] * scale]; | ||
scaledAnnotation.value = annotation.value; | ||
drawAnnotation(ctx, scaledAnnotation, scale); | ||
}); | ||
ctx.restore(); | ||
} | ||
}, { | ||
key: '_clear', | ||
value: function _clear() { | ||
var ctx = this.drawingCanvas.getContext('2d'); | ||
// Store the current transformation matrix | ||
ctx.save(); | ||
// Use the identity matrix while clearing the canvas | ||
ctx.setTransform(1, 0, 0, 1, 0, 0); | ||
ctx.clearRect(0, 0, this.drawingCanvas.width, this.drawingCanvas.height); | ||
// Restore the transform | ||
ctx.restore(); | ||
} | ||
}]); | ||
return Contour; | ||
}(React.Component); | ||
Contour.defaultProps = { | ||
contours: [], | ||
annotations: [] | ||
}; | ||
var Contour$1 = (function (props) { | ||
return React.createElement( | ||
ViewerContext.Consumer, | ||
null, | ||
function (_ref4) { | ||
var enabledElement = _ref4.enabledElement, | ||
viewport = _ref4.viewport; | ||
return React.createElement(Contour, _extends({}, props, { | ||
enabledElement: enabledElement, viewport: viewport })); | ||
} | ||
); | ||
}); | ||
var getRGBArray = function getRGBArray(value) { | ||
@@ -666,3 +883,4 @@ var r = 1.0; | ||
exports['default'] = Viewer; | ||
exports.ContourLayer = Contour$1; | ||
exports.HeatmapLayer = Heatmap$1; | ||
exports.MagnifyLayer = Magnify$1; |
{ | ||
"name": "@lunit/insight-viewer", | ||
"version": "1.1.4", | ||
"version": "1.2.0", | ||
"description": "A React component for DICOM images", | ||
@@ -5,0 +5,0 @@ "author": { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
62950
1568