Esempio n. 1
0
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;
}
Esempio n. 2
0
    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);
Esempio n. 3
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);
Esempio n. 4
0
    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);
Esempio n. 5
0
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();
  }
}
Esempio n. 6
0
// /////// 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();
  }
}
Esempio n. 7
0
// /////// 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();
  }
}
Esempio n. 8
0
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;
}