matrixTranslate method

  1. @protected
Matrix4 matrixTranslate(
  1. Matrix4 matrix,
  2. Offset translation
)

Return a new matrix representing the given matrix after applying the given translation.

Implementation

@protected
Matrix4 matrixTranslate(Matrix4 matrix, Offset translation) {
  if (translation == Offset.zero) {
    return matrix.clone();
  }

  late final Offset alignedTranslation;

  if (currentAxis != null) {
    switch (widget.panAxis) {
      case PanAxis.horizontal:
        alignedTranslation = alignAxis(translation, Axis.horizontal);
      case PanAxis.vertical:
        alignedTranslation = alignAxis(translation, Axis.vertical);
      case PanAxis.aligned:
        alignedTranslation = alignAxis(translation, currentAxis!);
      case PanAxis.free:
        alignedTranslation = translation;
    }
  } else {
    alignedTranslation = translation;
  }

  final Matrix4 nextMatrix = matrix.clone()
    ..translate(
      alignedTranslation.dx,
      alignedTranslation.dy,
    );

  // Transform the viewport to determine where its four corners will be after
  // the child has been transformed.
  final Quad nextViewport = transformViewport(nextMatrix, widgetViewport);

  // If the boundaries are infinite, then no need to check if the translation
  // fits within them.
  if (childBoundaryRect.isInfinite) {
    return nextMatrix;
  }

  // Expand the boundaries with rotation. This prevents the problem where a
  // mismatch in orientation between the viewport and boundaries effectively
  // limits translation. With this approach, all points that are visible with
  // no rotation are visible after rotation.
  final Quad boundariesAabbQuad = getAxisAlignedBoundingBoxWithRotation(
    childBoundaryRect,
    currentRotation,
  );

  // If the given translation fits completely within the boundaries, allow it.
  final Offset offendingDistance =
      exceedsBy(boundariesAabbQuad, nextViewport);
  if (offendingDistance == Offset.zero) {
    return nextMatrix;
  }

  // Desired translation goes out of bounds, so translate to the nearest
  // in-bounds point instead.
  final Offset nextTotalTranslation = getMatrixTranslation(nextMatrix);
  final double currentScale = matrix.getScaleOnZAxis();
  final Offset correctedTotalTranslation = Offset(
    nextTotalTranslation.dx - offendingDistance.dx * currentScale,
    nextTotalTranslation.dy - offendingDistance.dy * currentScale,
  );
  // TODO(justinmc): This needs some work to handle rotation properly. The
  // idea is that the boundaries are axis aligned (boundariesAabbQuad), but
  // calculating the translation to put the viewport inside that Quad is more
  // complicated than this when rotated.
  // https://github.com/flutter/flutter/issues/57698
  final Matrix4 correctedMatrix = matrix.clone()
    ..setTranslation(Vector3(
      correctedTotalTranslation.dx,
      correctedTotalTranslation.dy,
      0.0,
    ));

  // Double check that the corrected translation fits.
  final Quad correctedViewport =
      transformViewport(correctedMatrix, widgetViewport);
  final Offset offendingCorrectedDistance =
      exceedsBy(boundariesAabbQuad, correctedViewport);
  if (offendingCorrectedDistance == Offset.zero) {
    return correctedMatrix;
  }

  // If the corrected translation doesn't fit in either direction, don't allow
  // any translation at all. This happens when the viewport is larger than the
  // entire boundary.
  if (offendingCorrectedDistance.dx != 0.0 &&
      offendingCorrectedDistance.dy != 0.0) {
    return matrix.clone();
  }

  // Otherwise, allow translation in only the direction that fits. This
  // happens when the viewport is larger than the boundary in one direction.
  final Offset unidirectionalCorrectedTotalTranslation = Offset(
    offendingCorrectedDistance.dx == 0.0 ? correctedTotalTranslation.dx : 0.0,
    offendingCorrectedDistance.dy == 0.0 ? correctedTotalTranslation.dy : 0.0,
  );
  return matrix.clone()
    ..setTranslation(Vector3(
      unidirectionalCorrectedTotalTranslation.dx,
      unidirectionalCorrectedTotalTranslation.dy,
      0.0,
    ));
}