handleScaleUpdate method

void handleScaleUpdate(
  1. ScaleUpdateDetails details
)
inherited

Implementation

void handleScaleUpdate(ScaleUpdateDetails details) {
  if (_tapUpCounter == 1) {
    _handleDoubleTapHold(details);
    return;
  }

  final eventSource =
      _dragMode ? MapEventSource.onDrag : MapEventSource.onMultiFinger;

  final flags = options.interactiveFlags;
  final focalOffset = details.localFocalPoint;

  final currentRotation = radianToDeg(details.rotation);

  if (_dragMode) {
    if (InteractiveFlag.hasFlag(flags, InteractiveFlag.drag)) {
      if (!_dragStarted) {
        // We could emit start event at [handleScaleStart], however it is
        // possible drag will be disabled during ongoing drag then
        // [didUpdateWidget] will emit MapEventMoveEnd and if drag is enabled
        // again then this will emit the start event again.
        _dragStarted = true;
        mapState.emitMapEvent(
          MapEventMoveStart(
            center: mapState.center,
            zoom: mapState.zoom,
            source: eventSource,
          ),
        );
      }

      final oldCenterPt = mapState.project(mapState.center, mapState.zoom);
      final localDistanceOffset =
          _rotateOffset(_lastFocalLocal - focalOffset);

      final newCenterPt = oldCenterPt + _offsetToPoint(localDistanceOffset);
      final newCenter = mapState.unproject(newCenterPt, mapState.zoom);

      mapState.move(
        newCenter,
        mapState.zoom,
        hasGesture: true,
        source: eventSource,
      );
    }
  } else {
    final hasIntPinchMove =
        InteractiveFlag.hasFlag(flags, InteractiveFlag.pinchMove);
    final hasIntPinchZoom =
        InteractiveFlag.hasFlag(flags, InteractiveFlag.pinchZoom);
    final hasIntRotate =
        InteractiveFlag.hasFlag(flags, InteractiveFlag.rotate);

    if (hasIntPinchMove || hasIntPinchZoom || hasIntRotate) {
      final hasGestureRace = options.enableMultiFingerGestureRace;

      if (hasGestureRace && _gestureWinner == MultiFingerGesture.none) {
        if (hasIntPinchZoom &&
            (_getZoomForScale(_mapZoomStart, details.scale) - _mapZoomStart)
                    .abs() >=
                options.pinchZoomThreshold) {
          if (options.debugMultiFingerGestureWinner) {
            debugPrint('Multi Finger Gesture winner: Pinch Zoom');
          }
          _yieldMultiFingerGestureWinner(MultiFingerGesture.pinchZoom, true);
        } else if (hasIntRotate &&
            currentRotation.abs() >= options.rotationThreshold) {
          if (options.debugMultiFingerGestureWinner) {
            debugPrint('Multi Finger Gesture winner: Rotate');
          }
          _yieldMultiFingerGestureWinner(MultiFingerGesture.rotate, true);
        } else if (hasIntPinchMove &&
            (_focalStartLocal - focalOffset).distance >=
                options.pinchMoveThreshold) {
          if (options.debugMultiFingerGestureWinner) {
            debugPrint('Multi Finger Gesture winner: Pinch Move');
          }
          _yieldMultiFingerGestureWinner(MultiFingerGesture.pinchMove, true);
        }
      }

      if (!hasGestureRace || _gestureWinner != MultiFingerGesture.none) {
        final gestures = _getMultiFingerGestureFlags();

        final hasGesturePinchMove = MultiFingerGesture.hasFlag(
            gestures, MultiFingerGesture.pinchMove);
        final hasGesturePinchZoom = MultiFingerGesture.hasFlag(
            gestures, MultiFingerGesture.pinchZoom);
        final hasGestureRotate =
            MultiFingerGesture.hasFlag(gestures, MultiFingerGesture.rotate);

        final hasMove = hasIntPinchMove && hasGesturePinchMove;
        final hasZoom = hasIntPinchZoom && hasGesturePinchZoom;
        final hasRotate = hasIntRotate && hasGestureRotate;

        var mapMoved = false;
        var mapRotated = false;
        if (hasMove || hasZoom) {
          double newZoom;
          // checking details.scale to prevent situation whew details comes
          // with zero scale
          if (hasZoom && details.scale > 0.0) {
            newZoom = _getZoomForScale(
                _mapZoomStart, details.scale + _scaleCorrector);

            if (!_pinchZoomStarted) {
              if (newZoom != _mapZoomStart) {
                _pinchZoomStarted = true;

                if (!_pinchMoveStarted) {
                  // emit MoveStart event only if pinchMove hasn't started
                  mapState.emitMapEvent(
                    MapEventMoveStart(
                      center: mapState.center,
                      zoom: mapState.zoom,
                      source: eventSource,
                    ),
                  );
                }
              }
            }
          } else {
            newZoom = mapState.zoom;
          }

          LatLng newCenter;
          if (hasMove) {
            if (!_pinchMoveStarted && _lastFocalLocal != focalOffset) {
              _pinchMoveStarted = true;

              if (!_pinchZoomStarted) {
                // emit MoveStart event only if pinchZoom hasn't started
                mapState.emitMapEvent(
                  MapEventMoveStart(
                    center: mapState.center,
                    zoom: mapState.zoom,
                    source: eventSource,
                  ),
                );
              }
            }

            if (_pinchMoveStarted) {
              final oldCenterPt = mapState.project(mapState.center, newZoom);
              final newFocalLatLong = _offsetToCrs(_focalStartLocal, newZoom);
              final newFocalPt = mapState.project(newFocalLatLong, newZoom);
              final oldFocalPt = mapState.project(_focalStartLatLng, newZoom);
              final zoomDifference = oldFocalPt - newFocalPt;
              final moveDifference =
                  _rotateOffset(_focalStartLocal - _lastFocalLocal);

              final newCenterPt = oldCenterPt +
                  zoomDifference +
                  _offsetToPoint(moveDifference);
              newCenter = mapState.unproject(newCenterPt, newZoom);
            } else {
              newCenter = mapState.center;
            }
          } else {
            newCenter = mapState.center;
          }

          if (_pinchZoomStarted || _pinchMoveStarted) {
            mapMoved = mapState.move(
              newCenter,
              newZoom,
              hasGesture: true,
              source: eventSource,
            );
          }
        }

        if (hasRotate) {
          if (!_rotationStarted && currentRotation != 0.0) {
            _rotationStarted = true;
            mapState.emitMapEvent(
              MapEventRotateStart(
                center: mapState.center,
                zoom: mapState.zoom,
                source: eventSource,
              ),
            );
          }

          if (_rotationStarted) {
            final rotationDiff = currentRotation - _lastRotation;
            final oldCenterPt = mapState.project(mapState.center);
            final rotationCenter =
                mapState.project(_offsetToCrs(_lastFocalLocal));
            final vector = oldCenterPt - rotationCenter;
            final rotatedVector = vector.rotate(degToRadian(rotationDiff));
            final newCenter = rotationCenter + rotatedVector;
            mapMoved = mapState.move(
                    mapState.unproject(newCenter), mapState.zoom,
                    source: eventSource) ||
                mapMoved;
            mapRotated = mapState.rotate(
              mapState.rotation + rotationDiff,
              hasGesture: true,
              source: eventSource,
            );
          }
        }

        if (mapMoved || mapRotated) mapState.setState(() {});
      }
    }
  }

  _lastRotation = currentRotation;
  _lastScale = details.scale;
  _lastFocalLocal = focalOffset;
}