anchor.diff:  
   class _GridPhotoViewerState extends State<GridPhotoViewer> with SingleTickerProviderStateMixin {
     AnimationController _controller;
  -  double _lastScale = 1.0;
  +  Animation<Offset> _flingAnimation;
  +  Offset _offset = Offset.zero;
     double _scale = 1.0;
  -  Point _lastFocalPoint = Point.origin;
  -  Point _focalPoint = Point.origin;
  -  Animation<Point> _flingAnimation;
  +  Offset _normalizedOffset;
  +  double _previousScale;
   
     @override
     void initState() {
  
positive.code:     super.dispose();
    }
  
    // The minimum value for the focal point is 0,0. If the size of this
    // renderer's box is w,h then the maximum value of the focal point is
    // (w * _scale - w)/_scale, (h * _scale - h)/_scale.
    Point _clampFocalPoint(Point point) {
      final Size size = context.size;
      final double inverseScale = (_scale - 1.0) / _scale;
      final Point bottomRight = new Point(
        size.width * inverseScale,
        size.height * inverseScale,
      );
       return new Point(point.x.clamp(0.0, bottomRight.x), point.y.clamp(0.0, bottomRight.y));
    }
  
    void _handleFlingAnimation() {
      setState(() {
        _focalPoint = _flingAnimation.value;
        _lastFocalPoint = _focalPoint;
      });
    }
  
    void _handleOnScaleStart(ScaleStartDetails details) {
      setState(() {
        _lastScale = 1.0;
        _lastFocalPoint = details.focalPoint;
        // The fling animation stops if an input gesture starts.
        _controller.stop();
      });
  
negative.code:           onScaleEnd: _handleOnScaleEnd,
            child: new Transform(
              transform: new Matrix4.identity()
                ..translate(_offset.dx, _offset.dy)
                ..scale(_scale),
              child: new ClipRect(
                child: new Image.asset(config.photo.assetName, fit: ImageFit.cover)
  