function pointNearHandle (eventData, toolIndex) { const toolData = getToolState(eventData.element, toolType); if (toolData === undefined) { return; } const data = toolData.data[toolIndex]; if (data.handles === undefined) { return; } const mousePoint = eventData.currentPoints.canvas; for (let i = 0; i < data.handles.length; i++) { const handleCanvas = cornerstone.pixelToCanvas(eventData.element, data.handles[i]); if (cornerstoneMath.point.distance(handleCanvas, mousePoint) < 5) { return i; } } return; }
setTimeout(function () { startPoints = { page: cornerstoneMath.point.pageToPoint(e.originalEvent.changedTouches[0]), image: cornerstone.pageToPixel(element, e.originalEvent.changedTouches[0].pageX, e.originalEvent.changedTouches[0].pageY), client: { x: e.originalEvent.changedTouches[0].clientX, y: e.originalEvent.changedTouches[0].clientY } }; startPoints.canvas = cornerstone.pixelToCanvas(element, startPoints.image); eventType = 'CornerstoneToolsTouchEnd'; eventData = { event: e, viewport: cornerstone.getViewport(element), image: cornerstone.getEnabledElement(element).image, element, startPoints, currentPoints: startPoints, type: eventType, isTouchEvent: true }; event = $.Event(eventType, eventData); $(element).trigger(event, eventData); }, 50);
pressTimeout = setTimeout(function () { if (!isPress) { return; } currentPoints = { page: cornerstoneMath.point.pageToPoint(e.originalEvent.touches[0]), image: cornerstone.pageToPixel(element, e.originalEvent.touches[0].pageX, e.originalEvent.touches[0].pageY), client: { x: e.originalEvent.touches[0].clientX, y: e.originalEvent.touches[0].clientY } }; currentPoints.canvas = cornerstone.pixelToCanvas(element, startPoints.image); eventType = 'CornerstoneToolsTouchPress'; eventData = { event: e, viewport: cornerstone.getViewport(element), image: cornerstone.getEnabledElement(element).image, element, currentPoints, type: eventType, isTouchEvent: true }; event = $.Event(eventType, eventData); $(element).trigger(event, eventData); // Console.log(eventType); }, pressDelay);
touchStartDelay = setTimeout(function () { startPoints = { page: cornerstoneMath.point.pageToPoint(e.originalEvent.touches[0]), image: cornerstone.pageToPixel(element, e.originalEvent.touches[0].pageX, e.originalEvent.touches[0].pageY), client: { x: e.originalEvent.touches[0].clientX, y: e.originalEvent.touches[0].clientY } }; startPoints.canvas = cornerstone.pixelToCanvas(element, startPoints.image); eventType = 'CornerstoneToolsTouchStart'; if (e.originalEvent.touches.length > 1) { eventType = 'CornerstoneToolsMultiTouchStart'; } eventData = { event: e, viewport: cornerstone.getViewport(element), image: cornerstone.getEnabledElement(element).image, element, startPoints, currentPoints: startPoints, type: eventType, isTouchEvent: true }; event = $.Event(eventType, eventData); $(element).trigger(event, eventData); if (event.isImmediatePropagationStopped() === false) { // IsPress = false; // ClearTimeout(pressTimeout); // No current tools responded to the drag action. // Create new tool measurement eventType = 'CornerstoneToolsTouchStartActive'; if (e.originalEvent.touches.length > 1) { eventType = 'CornerstoneToolsMultiTouchStartActive'; } eventData.type = eventType; $(element).trigger(eventType, eventData); } // Console.log(eventType); lastPoints = copyPoints(startPoints); }, 50);
function onImageRendered (e, eventData) { // If we have no toolData for this element, return immediately as there is nothing to do const toolData = getToolState(e.currentTarget, toolType); if (!toolData) { return; } const image = eventData.image; const element = eventData.element; const lineWidth = toolStyle.getToolWidth(); const config = ellipticalRoi.getConfiguration(); const context = eventData.canvasContext.canvas.getContext('2d'); const seriesModule = cornerstone.metaData.get('generalSeriesModule', image.imageId); let modality; if (seriesModule) { modality = seriesModule.modality; } context.setTransform(1, 0, 0, 1, 0, 0); // If we have tool data for this element - iterate over each set and draw it for (let i = 0; i < toolData.data.length; i++) { context.save(); const data = toolData.data[i]; // Apply any shadow settings defined in the tool configuration if (config && config.shadow) { context.shadowColor = config.shadowColor || '#000000'; context.shadowOffsetX = config.shadowOffsetX || 1; context.shadowOffsetY = config.shadowOffsetY || 1; } // Check which color the rendered tool should be const color = toolColors.getColorIfActive(data.active); // Convert Image coordinates to Canvas coordinates given the element const handleStartCanvas = cornerstone.pixelToCanvas(element, data.handles.start); const handleEndCanvas = cornerstone.pixelToCanvas(element, data.handles.end); // Retrieve the bounds of the ellipse (left, top, width, and height) // In Canvas coordinates const leftCanvas = Math.min(handleStartCanvas.x, handleEndCanvas.x); const topCanvas = Math.min(handleStartCanvas.y, handleEndCanvas.y); const widthCanvas = Math.abs(handleStartCanvas.x - handleEndCanvas.x); const heightCanvas = Math.abs(handleStartCanvas.y - handleEndCanvas.y); // Draw the ellipse on the canvas context.beginPath(); context.strokeStyle = color; context.lineWidth = lineWidth; drawEllipse(context, leftCanvas, topCanvas, widthCanvas, heightCanvas); context.closePath(); // If the tool configuration specifies to only draw the handles on hover / active, // Follow this logic if (config && config.drawHandlesOnHover) { // Draw the handles if the tool is active if (data.active === true) { drawHandles(context, eventData, data.handles, color); } else { // If the tool is inactive, draw the handles only if each specific handle is being // Hovered over const handleOptions = { drawHandlesIfActive: true }; drawHandles(context, eventData, data.handles, color, handleOptions); } } else { // If the tool has no configuration settings, always draw the handles drawHandles(context, eventData, data.handles, color); } // Define variables for the area and mean/standard deviation let area, meanStdDev, meanStdDevSUV; // Perform a check to see if the tool has been invalidated. This is to prevent // Unnecessary re-calculation of the area, mean, and standard deviation if the // Image is re-rendered but the tool has not moved (e.g. during a zoom) if (data.invalidated === false) { // If the data is not invalidated, retrieve it from the toolData meanStdDev = data.meanStdDev; meanStdDevSUV = data.meanStdDevSUV; area = data.area; } else { // If the data has been invalidated, we need to calculate it again // Retrieve the bounds of the ellipse in image coordinates const ellipse = { left: Math.round(Math.min(data.handles.start.x, data.handles.end.x)), top: Math.round(Math.min(data.handles.start.y, data.handles.end.y)), width: Math.round(Math.abs(data.handles.start.x - data.handles.end.x)), height: Math.round(Math.abs(data.handles.start.y - data.handles.end.y)) }; // First, make sure this is not a color image, since no mean / standard // Deviation will be calculated for color images. if (!image.color) { // Retrieve the array of pixels that the ellipse bounds cover const pixels = cornerstone.getPixels(element, ellipse.left, ellipse.top, ellipse.width, ellipse.height); // Calculate the mean & standard deviation from the pixels and the ellipse details meanStdDev = calculateEllipseStatistics(pixels, ellipse); if (modality === 'PT') { // If the image is from a PET scan, use the DICOM tags to // Calculate the SUV from the mean and standard deviation. // Note that because we are using modality pixel values from getPixels, and // The calculateSUV routine also rescales to modality pixel values, we are first // Returning the values to storedPixel values before calcuating SUV with them. // TODO: Clean this up? Should we add an option to not scale in calculateSUV? meanStdDevSUV = { mean: calculateSUV(image, (meanStdDev.mean - image.intercept) / image.slope), stdDev: calculateSUV(image, (meanStdDev.stdDev - image.intercept) / image.slope) }; } // If the mean and standard deviation values are sane, store them for later retrieval if (meanStdDev && !isNaN(meanStdDev.mean)) { data.meanStdDev = meanStdDev; data.meanStdDevSUV = meanStdDevSUV; } } // Retrieve the pixel spacing values, and if they are not // Real non-zero values, set them to 1 const columnPixelSpacing = image.columnPixelSpacing || 1; const rowPixelSpacing = image.rowPixelSpacing || 1; // Calculate the image area from the ellipse dimensions and pixel spacing area = Math.PI * (ellipse.width * columnPixelSpacing / 2) * (ellipse.height * rowPixelSpacing / 2); // If the area value is sane, store it for later retrieval if (!isNaN(area)) { data.area = area; } // Set the invalidated flag to false so that this data won't automatically be recalculated data.invalidated = false; } // Define an array to store the rows of text for the textbox const textLines = []; // If the mean and standard deviation values are present, display them if (meanStdDev && meanStdDev.mean !== undefined) { // If the modality is CT, add HU to denote Hounsfield Units let moSuffix = ''; if (modality === 'CT') { moSuffix = ' HU'; } // Create a line of text to display the mean and any units that were specified (i.e. HU) let meanText = `Mean: ${numberWithCommas(meanStdDev.mean.toFixed(2))}${moSuffix}`; // Create a line of text to display the standard deviation and any units that were specified (i.e. HU) let stdDevText = `StdDev: ${numberWithCommas(meanStdDev.stdDev.toFixed(2))}${moSuffix}`; // If this image has SUV values to display, concatenate them to the text line if (meanStdDevSUV && meanStdDevSUV.mean !== undefined) { const SUVtext = ' SUV: '; meanText += SUVtext + numberWithCommas(meanStdDevSUV.mean.toFixed(2)); stdDevText += SUVtext + numberWithCommas(meanStdDevSUV.stdDev.toFixed(2)); } // Add these text lines to the array to be displayed in the textbox textLines.push(meanText); textLines.push(stdDevText); } // If the area is a sane value, display it if (area) { // Determine the area suffix based on the pixel spacing in the image. // If pixel spacing is present, use millimeters. Otherwise, use pixels. // This uses Char code 178 for a superscript 2 let suffix = ` mm${String.fromCharCode(178)}`; if (!image.rowPixelSpacing || !image.columnPixelSpacing) { suffix = ` pixels${String.fromCharCode(178)}`; } // Create a line of text to display the area and its units const areaText = `Area: ${numberWithCommas(area.toFixed(2))}${suffix}`; // Add this text line to the array to be displayed in the textbox textLines.push(areaText); } // If the textbox has not been moved by the user, it should be displayed on the right-most // Side of the tool. if (!data.handles.textBox.hasMoved) { // Find the rightmost side of the ellipse at its vertical center, and place the textbox here // Note that this calculates it in image coordinates data.handles.textBox.x = Math.max(data.handles.start.x, data.handles.end.x); data.handles.textBox.y = (data.handles.start.y + data.handles.end.y) / 2; } // Convert the textbox Image coordinates into Canvas coordinates const textCoords = cornerstone.pixelToCanvas(element, data.handles.textBox); // Set options for the textbox drawing function const options = { centering: { x: false, y: true } }; // Draw the textbox and retrieves it's bounding box for mouse-dragging and highlighting const boundingBox = drawTextBox(context, textLines, textCoords.x, textCoords.y, color, options); // Store the bounding box data in the handle for mouse-dragging and highlighting data.handles.textBox.boundingBox = boundingBox; // If the textbox has moved, we would like to draw a line linking it with the tool // This section decides where to draw this line to on the Ellipse based on the location // Of the textbox relative to the ellipse. if (data.handles.textBox.hasMoved) { // Draw dashed link line between tool and text // The initial link position is at the center of the // Textbox. const link = { start: {}, end: { x: textCoords.x, y: textCoords.y } }; // First we calculate the ellipse points (top, left, right, and bottom) const ellipsePoints = [{ // Top middle point of ellipse x: leftCanvas + widthCanvas / 2, y: topCanvas }, { // Left middle point of ellipse x: leftCanvas, y: topCanvas + heightCanvas / 2 }, { // Bottom middle point of ellipse x: leftCanvas + widthCanvas / 2, y: topCanvas + heightCanvas }, { // Right middle point of ellipse x: leftCanvas + widthCanvas, y: topCanvas + heightCanvas / 2 }]; // We obtain the link starting point by finding the closest point on the ellipse to the // Center of the textbox link.start = cornerstoneMath.point.findClosestPoint(ellipsePoints, link.end); // Next we calculate the corners of the textbox bounding box const boundingBoxPoints = [{ // Top middle point of bounding box x: boundingBox.left + boundingBox.width / 2, y: boundingBox.top }, { // Left middle point of bounding box x: boundingBox.left, y: boundingBox.top + boundingBox.height / 2 }, { // Bottom middle point of bounding box x: boundingBox.left + boundingBox.width / 2, y: boundingBox.top + boundingBox.height }, { // Right middle point of bounding box x: boundingBox.left + boundingBox.width, y: boundingBox.top + boundingBox.height / 2 }]; // Now we recalculate the link endpoint by identifying which corner of the bounding box // Is closest to the start point we just calculated. link.end = cornerstoneMath.point.findClosestPoint(boundingBoxPoints, link.start); // Finally we draw the dashed linking line context.beginPath(); context.strokeStyle = color; context.lineWidth = lineWidth; context.setLineDash([2, 3]); context.moveTo(link.start.x, link.start.y); context.lineTo(link.end.x, link.end.y); context.stroke(); } context.restore(); } }
// /////// BEGIN IMAGE RENDERING /////// function onImageRendered (e, eventData) { // If we have no toolData for this element, return immediately as there is nothing to do const toolData = getToolState(e.currentTarget, toolType); if (!toolData) { return; } const enabledElement = eventData.enabledElement; // We have tool data for this element - iterate over each one and draw it const context = eventData.canvasContext.canvas.getContext('2d'); context.setTransform(1, 0, 0, 1, 0, 0); let color; const lineWidth = toolStyle.getToolWidth(); const font = textStyle.getFont(); const config = arrowAnnotate.getConfiguration(); for (let i = 0; i < toolData.data.length; i++) { context.save(); if (config && config.shadow) { context.shadowColor = config.shadowColor || '#000000'; context.shadowOffsetX = config.shadowOffsetX || 1; context.shadowOffsetY = config.shadowOffsetY || 1; } const data = toolData.data[i]; if (data.active) { color = toolColors.getActiveColor(); } else { color = toolColors.getToolColor(); } // Draw the arrow const handleStartCanvas = cornerstone.pixelToCanvas(eventData.element, data.handles.start); const handleEndCanvas = cornerstone.pixelToCanvas(eventData.element, data.handles.end); // Config.arrowFirst = false; if (config.arrowFirst) { drawArrow(context, handleEndCanvas, handleStartCanvas, color, lineWidth); } else { drawArrow(context, handleStartCanvas, handleEndCanvas, color, lineWidth); } const handleOptions = { drawHandlesIfActive: (config && config.drawHandlesOnHover) }; if (config.drawHandles) { drawHandles(context, eventData, data.handles, color, handleOptions); } // Draw the text if (data.text && data.text !== '') { context.font = font; // Calculate the text coordinates. const textWidth = context.measureText(data.text).width + 10; const textHeight = textStyle.getFontSize() + 10; let distance = Math.max(textWidth, textHeight) / 2 + 5; if (handleEndCanvas.x < handleStartCanvas.x) { distance = -distance; } let textCoords; if (!data.handles.textBox.hasMoved) { if (config.arrowFirst) { textCoords = { x: handleEndCanvas.x - textWidth / 2 + distance, y: handleEndCanvas.y - textHeight / 2 }; } else { // If the arrow is at the End position, the text should // Be placed near the Start position textCoords = { x: handleStartCanvas.x - textWidth / 2 - distance, y: handleStartCanvas.y - textHeight / 2 }; } const transform = cornerstone.internal.getTransform(enabledElement); transform.invert(); const coords = transform.transformPoint(textCoords.x, textCoords.y); data.handles.textBox.x = coords.x; data.handles.textBox.y = coords.y; } textCoords = cornerstone.pixelToCanvas(eventData.element, data.handles.textBox); const boundingBox = drawTextBox(context, data.text, textCoords.x, textCoords.y, color); data.handles.textBox.boundingBox = boundingBox; if (data.handles.textBox.hasMoved) { // Draw dashed link line between tool and text const link = { start: {}, end: {} }; const midpointCanvas = { x: (handleStartCanvas.x + handleEndCanvas.x) / 2, y: (handleStartCanvas.y + handleEndCanvas.y) / 2 }; const points = [handleStartCanvas, handleEndCanvas, midpointCanvas]; link.end.x = textCoords.x; link.end.y = textCoords.y; link.start = cornerstoneMath.point.findClosestPoint(points, link.end); const boundingBoxPoints = [{ // Top middle point of bounding box x: boundingBox.left + boundingBox.width / 2, y: boundingBox.top }, { // Left middle point of bounding box x: boundingBox.left, y: boundingBox.top + boundingBox.height / 2 }, { // Bottom middle point of bounding box x: boundingBox.left + boundingBox.width / 2, y: boundingBox.top + boundingBox.height }, { // Right middle point of bounding box x: boundingBox.left + boundingBox.width, y: boundingBox.top + boundingBox.height / 2 } ]; link.end = cornerstoneMath.point.findClosestPoint(boundingBoxPoints, link.start); context.beginPath(); context.strokeStyle = color; context.lineWidth = lineWidth; context.setLineDash([2, 3]); context.moveTo(link.start.x, link.start.y); context.lineTo(link.end.x, link.end.y); context.stroke(); } } context.restore(); } }
// /////// BEGIN IMAGE RENDERING /////// function onImageRendered (e, eventData) { // If we have no toolData for this element, return immediately as there is nothing to do const toolData = getToolState(e.currentTarget, toolType); if (!toolData) { return; } const enabledElement = eventData.enabledElement; // We have tool data for this element - iterate over each one and draw it const context = eventData.canvasContext.canvas.getContext('2d'); context.setTransform(1, 0, 0, 1, 0, 0); // Activation color let color; const lineWidth = toolStyle.getToolWidth(); const font = textStyle.getFont(); const config = simpleAngle.getConfiguration(); for (let i = 0; i < toolData.data.length; i++) { context.save(); if (config && config.shadow) { context.shadowColor = config.shadowColor === undefined ? '#000000' : config.shadowColor; context.shadowOffsetX = config.shadowOffsetX === undefined ? 1 : config.shadowOffsetX; context.shadowOffsetX = config.shadowOffsetY === undefined ? 1 : config.shadowOffsetY; context.shadowBlur = config.shadowBlur === undefined ? 1 : config.shadowBlur; } const data = toolData.data[i]; // Differentiate the color of activation tool if (data.active) { color = toolColors.getActiveColor(); } else { color = toolColors.getToolColor(); } const handleStartCanvas = cornerstone.pixelToCanvas(eventData.element, data.handles.start); const handleMiddleCanvas = cornerstone.pixelToCanvas(eventData.element, data.handles.middle); const handleEndCanvas = cornerstone.pixelToCanvas(eventData.element, data.handles.end); // Draw the line context.beginPath(); context.strokeStyle = color; context.lineWidth = lineWidth; context.moveTo(handleStartCanvas.x, handleStartCanvas.y); context.lineTo(handleMiddleCanvas.x, handleMiddleCanvas.y); context.lineTo(handleEndCanvas.x, handleEndCanvas.y); context.stroke(); // Draw the handles const handleOptions = { drawHandlesIfActive: (config && config.drawHandlesOnHover) }; drawHandles(context, eventData, data.handles, color, handleOptions); // Draw the text context.fillStyle = color; // Default to isotropic pixel size, update suffix to reflect this const columnPixelSpacing = eventData.image.columnPixelSpacing || 1; const rowPixelSpacing = eventData.image.rowPixelSpacing || 1; let suffix = ''; if (!eventData.image.rowPixelSpacing || !eventData.image.columnPixelSpacing) { suffix = ' (isotropic)'; } const sideA = { x: (Math.ceil(data.handles.middle.x) - Math.ceil(data.handles.start.x)) * columnPixelSpacing, y: (Math.ceil(data.handles.middle.y) - Math.ceil(data.handles.start.y)) * rowPixelSpacing }; const sideB = { x: (Math.ceil(data.handles.end.x) - Math.ceil(data.handles.middle.x)) * columnPixelSpacing, y: (Math.ceil(data.handles.end.y) - Math.ceil(data.handles.middle.y)) * rowPixelSpacing }; const sideC = { x: (Math.ceil(data.handles.end.x) - Math.ceil(data.handles.start.x)) * columnPixelSpacing, y: (Math.ceil(data.handles.end.y) - Math.ceil(data.handles.start.y)) * rowPixelSpacing }; const sideALength = length(sideA); const sideBLength = length(sideB); const sideCLength = length(sideC); // Cosine law let angle = Math.acos((Math.pow(sideALength, 2) + Math.pow(sideBLength, 2) - Math.pow(sideCLength, 2)) / (2 * sideALength * sideBLength)); angle *= (180 / Math.PI); const rAngle = roundToDecimal(angle, 2); if (rAngle) { const str = '00B0'; // Degrees symbol const text = rAngle.toString() + String.fromCharCode(parseInt(str, 16)) + suffix; const distance = 15; let textCoords; if (data.handles.textBox.hasMoved) { textCoords = cornerstone.pixelToCanvas(eventData.element, data.handles.textBox); } else { textCoords = { x: handleMiddleCanvas.x, y: handleMiddleCanvas.y }; context.font = font; const textWidth = context.measureText(text).width; if (handleMiddleCanvas.x < handleStartCanvas.x) { textCoords.x -= distance + textWidth + 10; } else { textCoords.x += distance; } const transform = cornerstone.internal.getTransform(enabledElement); transform.invert(); const coords = transform.transformPoint(textCoords.x, textCoords.y); data.handles.textBox.x = coords.x; data.handles.textBox.y = coords.y; } const options = { centering: { x: false, y: true } }; const boundingBox = drawTextBox(context, text, textCoords.x, textCoords.y, color, options); data.handles.textBox.boundingBox = boundingBox; if (data.handles.textBox.hasMoved) { // Draw dashed link line between tool and text const link = { start: {}, end: {} }; const points = [handleStartCanvas, handleEndCanvas, handleMiddleCanvas]; link.end.x = textCoords.x; link.end.y = textCoords.y; link.start = cornerstoneMath.point.findClosestPoint(points, link.end); const boundingBoxPoints = [{ // Top middle point of bounding box x: boundingBox.left + boundingBox.width / 2, y: boundingBox.top }, { // Left middle point of bounding box x: boundingBox.left, y: boundingBox.top + boundingBox.height / 2 }, { // Bottom middle point of bounding box x: boundingBox.left + boundingBox.width / 2, y: boundingBox.top + boundingBox.height }, { // Right middle point of bounding box x: boundingBox.left + boundingBox.width, y: boundingBox.top + boundingBox.height / 2 } ]; link.end = cornerstoneMath.point.findClosestPoint(boundingBoxPoints, link.start); context.beginPath(); context.strokeStyle = color; context.lineWidth = lineWidth; context.setLineDash([2, 3]); context.moveTo(link.start.x, link.start.y); context.lineTo(link.end.x, link.end.y); context.stroke(); } } context.restore(); } }
function onTouch (e) { const element = e.currentTarget || e.srcEvent.currentTarget; let event, eventType, scaleChange, delta, remainingPointers, rotation; // Prevent mouse events from occurring alongside touch events e.preventDefault(); // If more than one finger is placed on the element, stop the press timeout if ((e.pointers && e.pointers.length > 1) || (e.originalEvent && e.originalEvent.touches && e.originalEvent.touches.length > 1)) { isPress = false; clearTimeout(pressTimeout); } switch (e.type) { case 'tap': isPress = false; clearTimeout(pressTimeout); // Calculate our current points in page and image coordinates currentPoints = { page: cornerstoneMath.point.pageToPoint(e.pointers[0]), image: cornerstone.pageToPixel(element, e.pointers[0].pageX, e.pointers[0].pageY), client: { x: e.pointers[0].clientX, y: e.pointers[0].clientY } }; currentPoints.canvas = cornerstone.pixelToCanvas(element, currentPoints.image); eventType = 'CornerstoneToolsTap'; eventData = { event: e, viewport: cornerstone.getViewport(element), image: cornerstone.getEnabledElement(element).image, element, currentPoints, type: eventType, isTouchEvent: true }; event = $.Event(eventType, eventData); $(element).trigger(event, eventData); break; case 'doubletap': isPress = false; clearTimeout(pressTimeout); // Calculate our current points in page and image coordinates currentPoints = { page: cornerstoneMath.point.pageToPoint(e.pointers[0]), image: cornerstone.pageToPixel(element, e.pointers[0].pageX, e.pointers[0].pageY), client: { x: e.pointers[0].clientX, y: e.pointers[0].clientY } }; currentPoints.canvas = cornerstone.pixelToCanvas(element, currentPoints.image); eventType = 'CornerstoneToolsDoubleTap'; eventData = { event: e, viewport: cornerstone.getViewport(element), image: cornerstone.getEnabledElement(element).image, element, currentPoints, type: eventType, isTouchEvent: true }; event = $.Event(eventType, eventData); $(element).trigger(event, eventData); break; case 'pinchstart': isPress = false; clearTimeout(pressTimeout); lastScale = 1.0; break; case 'pinchmove': isPress = false; clearTimeout(pressTimeout); if (preventNextPinch === true) { lastScale = e.scale; preventNextPinch = false; break; } scaleChange = (e.scale - lastScale) / lastScale; startPoints = { page: e.center, image: cornerstone.pageToPixel(element, e.center.x, e.center.y) }; startPoints.canvas = cornerstone.pixelToCanvas(element, startPoints.image); eventType = 'CornerstoneToolsTouchPinch'; eventData = { event: e, startPoints, viewport: cornerstone.getViewport(element), image: cornerstone.getEnabledElement(element).image, element, direction: e.scale < 1 ? 1 : -1, scaleChange, type: eventType, isTouchEvent: true }; event = $.Event(eventType, eventData); $(element).trigger(event, eventData); lastScale = e.scale; break; case 'touchstart': lastScale = 1.0; clearTimeout(pressTimeout); clearTimeout(touchStartDelay); touchStartDelay = setTimeout(function () { startPoints = { page: cornerstoneMath.point.pageToPoint(e.originalEvent.touches[0]), image: cornerstone.pageToPixel(element, e.originalEvent.touches[0].pageX, e.originalEvent.touches[0].pageY), client: { x: e.originalEvent.touches[0].clientX, y: e.originalEvent.touches[0].clientY } }; startPoints.canvas = cornerstone.pixelToCanvas(element, startPoints.image); eventType = 'CornerstoneToolsTouchStart'; if (e.originalEvent.touches.length > 1) { eventType = 'CornerstoneToolsMultiTouchStart'; } eventData = { event: e, viewport: cornerstone.getViewport(element), image: cornerstone.getEnabledElement(element).image, element, startPoints, currentPoints: startPoints, type: eventType, isTouchEvent: true }; event = $.Event(eventType, eventData); $(element).trigger(event, eventData); if (event.isImmediatePropagationStopped() === false) { // IsPress = false; // ClearTimeout(pressTimeout); // No current tools responded to the drag action. // Create new tool measurement eventType = 'CornerstoneToolsTouchStartActive'; if (e.originalEvent.touches.length > 1) { eventType = 'CornerstoneToolsMultiTouchStartActive'; } eventData.type = eventType; $(element).trigger(eventType, eventData); } // Console.log(eventType); lastPoints = copyPoints(startPoints); }, 50); isPress = true; pageDistanceMoved = 0; pressTimeout = setTimeout(function () { if (!isPress) { return; } currentPoints = { page: cornerstoneMath.point.pageToPoint(e.originalEvent.touches[0]), image: cornerstone.pageToPixel(element, e.originalEvent.touches[0].pageX, e.originalEvent.touches[0].pageY), client: { x: e.originalEvent.touches[0].clientX, y: e.originalEvent.touches[0].clientY } }; currentPoints.canvas = cornerstone.pixelToCanvas(element, startPoints.image); eventType = 'CornerstoneToolsTouchPress'; eventData = { event: e, viewport: cornerstone.getViewport(element), image: cornerstone.getEnabledElement(element).image, element, currentPoints, type: eventType, isTouchEvent: true }; event = $.Event(eventType, eventData); $(element).trigger(event, eventData); // Console.log(eventType); }, pressDelay); break; case 'touchend': lastScale = 1.0; isPress = false; clearTimeout(pressTimeout); setTimeout(function () { startPoints = { page: cornerstoneMath.point.pageToPoint(e.originalEvent.changedTouches[0]), image: cornerstone.pageToPixel(element, e.originalEvent.changedTouches[0].pageX, e.originalEvent.changedTouches[0].pageY), client: { x: e.originalEvent.changedTouches[0].clientX, y: e.originalEvent.changedTouches[0].clientY } }; startPoints.canvas = cornerstone.pixelToCanvas(element, startPoints.image); eventType = 'CornerstoneToolsTouchEnd'; eventData = { event: e, viewport: cornerstone.getViewport(element), image: cornerstone.getEnabledElement(element).image, element, startPoints, currentPoints: startPoints, type: eventType, isTouchEvent: true }; event = $.Event(eventType, eventData); $(element).trigger(event, eventData); }, 50); break; case 'panmove': // Using the delta-value of HammerJS, because it takes all pointers into account // This is very important when using panning in combination with pinch-zooming // But HammerJS' delta is relative to the start of the pan event // So it needs to be converted to a per-event-delta for CornerstoneTools delta = { x: e.deltaX - lastDelta.x, y: e.deltaY - lastDelta.y }; lastDelta = { x: e.deltaX, y: e.deltaY }; // Calculate our current points in page and image coordinates currentPoints = { page: { x: lastPoints.page.x + delta.x, y: lastPoints.page.y + delta.y }, image: cornerstone.pageToPixel(element, lastPoints.page.x + delta.x, lastPoints.page.y + delta.y), client: { x: lastPoints.client.x + delta.x, y: lastPoints.client.y + delta.y } }; currentPoints.canvas = cornerstone.pixelToCanvas(element, currentPoints.image); // Calculate delta values in page and image coordinates deltaPoints = { page: cornerstoneMath.point.subtract(currentPoints.page, lastPoints.page), image: cornerstoneMath.point.subtract(currentPoints.image, lastPoints.image), client: cornerstoneMath.point.subtract(currentPoints.client, lastPoints.client), canvas: cornerstoneMath.point.subtract(currentPoints.canvas, lastPoints.canvas) }; pageDistanceMoved += Math.sqrt(deltaPoints.page.x * deltaPoints.page.x + deltaPoints.page.y * deltaPoints.page.y); // Console.log("pageDistanceMoved: " + pageDistanceMoved); if (pageDistanceMoved > pressMaxDistance) { // Console.log('Press event aborted due to movement'); isPress = false; clearTimeout(pressTimeout); } eventType = 'CornerstoneToolsTouchDrag'; if (e.pointers.length > 1) { eventType = 'CornerstoneToolsMultiTouchDrag'; } eventData = { viewport: cornerstone.getViewport(element), image: cornerstone.getEnabledElement(element).image, element, startPoints, lastPoints, currentPoints, deltaPoints, numPointers: e.pointers.length, type: eventType, isTouchEvent: true }; event = $.Event(eventType, eventData); $(element).trigger(event, eventData); lastPoints = copyPoints(currentPoints); break; case 'panstart': lastDelta = { x: e.deltaX, y: e.deltaY }; currentPoints = { page: cornerstoneMath.point.pageToPoint(e.pointers[0]), image: cornerstone.pageToPixel(element, e.pointers[0].pageX, e.pointers[0].pageY), client: { x: e.pointers[0].clientX, y: e.pointers[0].clientY } }; currentPoints.canvas = cornerstone.pixelToCanvas(element, currentPoints.image); lastPoints = copyPoints(currentPoints); break; case 'panend': isPress = false; clearTimeout(pressTimeout); // If lastPoints is not yet set, it means panend fired without panstart or pan, // So we can ignore this event if (!lastPoints) { return false; } currentPoints = { page: cornerstoneMath.point.pageToPoint(e.pointers[0]), image: cornerstone.pageToPixel(element, e.pointers[0].pageX, e.pointers[0].pageY), client: { x: e.pointers[0].clientX, y: e.pointers[0].clientY } }; currentPoints.canvas = cornerstone.pixelToCanvas(element, currentPoints.image); // Calculate delta values in page and image coordinates deltaPoints = { page: cornerstoneMath.point.subtract(currentPoints.page, lastPoints.page), image: cornerstoneMath.point.subtract(currentPoints.image, lastPoints.image), client: cornerstoneMath.point.subtract(currentPoints.client, lastPoints.client), canvas: cornerstoneMath.point.subtract(currentPoints.canvas, lastPoints.canvas) }; eventType = 'CornerstoneToolsDragEnd'; eventData = { event: e.srcEvent, viewport: cornerstone.getViewport(element), image: cornerstone.getEnabledElement(element).image, element, startPoints, lastPoints, currentPoints, deltaPoints, type: eventType, isTouchEvent: true }; event = $.Event(eventType, eventData); $(element).trigger(event, eventData); remainingPointers = e.pointers.length - e.changedPointers.length; if (remainingPointers === 2) { preventNextPinch = true; } return pauseEvent(e); case 'rotatemove': isPress = false; clearTimeout(pressTimeout); rotation = e.rotation - lastRotation; lastRotation = e.rotation; eventType = 'CornerstoneToolsTouchRotate'; eventData = { event: e.srcEvent, viewport: cornerstone.getViewport(element), image: cornerstone.getEnabledElement(element).image, element, rotation, type: eventType }; event = $.Event(eventType, eventData); $(element).trigger(event, eventData); break; } // Console.log(eventType); return false; }