How to zoom in/out in react-native-map?
Asked Answered
G

7

44

I am using react-native to build a map application. The api I am using is from this link: https://github.com/lelandrichardson/react-native-maps.

Below is the code I bring the map on my app. I wonder how I can give a zoom value on that map. And how I can change the zoom value when the user clicks a button on the map.

What is the zoom API I should use to achieve this?

import React, { Component, StyleSheet, View, TextInput } from "react-native";
import MapView from "react-native-maps";

class MapPage extends Component {
  constructor(props) {
    super(props);
    this.state = {
      region: {
        latitude: 4.21048,
        longitude: 101.97577,
        latitudeDelta: 10,
        longitudeDelta: 5,
      },
    };
  }

  render() {
    return (
      <View style={styles.container}>
        <TextInput style={styles.inputText}>Map</TextInput>
        <MapView
          style={styles.map}
          mapType={"standard"}
          region={this.state.region}
          zoomEnabled={true}
          scrollEnabled={true}
          showsScale={true}
        />
      </View>
    );
  }
}

module.exports = MapPage;

const styles = StyleSheet.create({
  map: {
    position: "absolute",
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
  },
  container: {
    flexDirection: "row",
    justifyContent: "space-between",
    padding: 30,
    flex: 1,
    alignItems: "center",
  },
  inputText: {
    height: 36,
    padding: 4,
    marginRight: 5,
    flex: 4,
    fontSize: 18,
    borderWidth: 1,
    borderColor: "#48BBEC",
    borderRadius: 8,
    color: "#48BBEC",
  },
});

Gamez answered 18/4, 2016 at 4:13 Comment(0)
S
124

You should use the animateToRegion method (see here)

It takes a region object which has latitudeDelta and longitudeDelta. Use these to set the zoom level.

Updated:

in a Region object the latitude and longitude specify the center location and latitudeDelta and longitudeDelta specify the span of the viewable map area.

This image from this blog post illustrates it well (LatΔ and LngΔ). enter image description here

Silencer answered 18/4, 2016 at 7:48 Comment(4)
what is the different between latitude and latitudeDelta? Is there a document to explain them?Gamez
Thanks for response. Is there any example to illustrate how to use animateToRegion?Gamez
Yes, see this example: github.com/lelandrichardson/react-native-maps/blob/master/…Silencer
So, how to set deltas using custom zoom in and zoom out buttons?Shawndashawnee
J
4

New React Native Maps API gives you option to call animateCamera method with zoom parameter.

    const MapComponent= (props: any) => {
    
    const map: LegacyRef<MapView> = useRef(null);
    
    const onZoomInPress = () => {
        map?.current?.getCamera().then((cam: Camera) => {
            cam.zoom += 1;
            map?.current?.animateCamera(cam);
        });
    };
    
    return (
            <View>
                <MapView
                    ref={map}
                    provider={PROVIDER_GOOGLE}
                    region={region}>
                </MapView>
                <ButtonComponent
                    style={{position: 'absolute', bottom: 400, left: 0}}
                    onPress={onZoomInPress}>
                    Zoom In
                </MainButtonBlue>
            </View>
        );
    }
Jacaranda answered 17/3, 2021 at 10:15 Comment(1)
Doesn't work on IOSGladis
I
3

I was able to make this work using Dimensions.get('window');

    const window = Dimensions.get('window');
    const { width, height }  = window
    LONGITUDE_DELTA = LATITUD_DELTA + (width / height)

and by default set LATITUD_DELTA = 0.0922. Then just update this values with the prop onRegionChangeComplete in the <MapView>

Ineludible answered 18/9, 2017 at 4:49 Comment(5)
How come it gives you different values? It refers to the screen size which is constant irrespective of the map zoom levelTerrilyn
I think it should be LONGITUDE_DELTA = LATITUD_DELTA * (width / height)Terrilyn
@Terrilyn why u say that?Ineludible
This approach is used in this example: github.com/react-native-community/react-native-maps/blob/master/…Roehm
How did we end up with LATITUD_DELTA = 0.0922? what does this mean? How do we calculate this?Spiker
S
2
const handleZoomIn = () => {
  map.current?.getCamera().then((cam: Camera) => {
    if (Platform.OS === 'android') {
      cam.zoom += 1;
    } else {
      cam.altitude /= 2;
    }
    map.current?.animateCamera(cam);
  });
};

const handleZoomOut = () => {
  map.current?.getCamera().then((cam: Camera) => {
    if (Platform.OS === 'android') {
      cam.zoom -= 1;
    } else {
      cam.altitude *= 2;
    }
    map.current?.animateCamera(cam);
  });
};
Sporocarp answered 1/2, 2023 at 15:50 Comment(5)
Welcome to the site. Should take a minute to explain your code instead of a code dump.Fern
Hello, where should be the code placed? Please add some text. How to give good answerBloodsucker
this is for functional component. call both this functions for your custom created zoom in and out buttonBermuda
<TouchableOpacity style={{ position: 'absolute', bottom: 150, left: 10, backgroundColor: '#1f38d4', padding: 10, borderRadius: 8, elevation: 10, }} onPress={() => { handleZoomIn() }}> <FontAwesome5 name="plus" size={20} color="#fff" /> </TouchableOpacity>Bermuda
It should perhaps be explained that cam.altitude only works when you are using the iOS MapKitPaterson
N
1

This is what I did and it worked out for me very well:

function getRegion(origin, destination, zoom) {
  const oLat = Math.abs(origin.latitude);
  const oLng = Math.abs(origin.longitude);
  const dLat = Math.abs(destination.latitude);
  const dLng = Math.abs(destination.longitude);

  return {
      latitude: (origin.latitude + destination.latitude) / 2,
      longitude: (origin.longitude + destination.longitude) / 2,
      latitudeDelta: Math.abs(oLat - dLat) + zoom,
      longitudeDelta: Math.abs(oLng - dLng) + zoom,
  };
}
Novelist answered 3/2, 2021 at 15:56 Comment(1)
Thanks, this worked for me in conjunction with useRef on the MapView using react-native and expo. I use this function in a setTimeout of about 1000ms just so that the map loads and then animate to correct zoom level using your getRegion implementationDiapause
P
0

I created the following based on the mercator math in https://github.com/tuupola/php_google_maps

The key function is mercatorDegreeDeltas(latitude, longitude, width, height, zoom) which returns { latitudeDelta, longitudeDelta } for the specified latitude/longitude center point, map dimensions, and zoom level (1-20).

import React from 'react';
import { useWindowDimensions } from 'react-native';
import MapView from 'react-native-maps';
import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
import { useHeaderHeight } from '@react-navigation/elements';

const MERCATOR_OFFSET = Math.pow(2, 28);
const MERCATOR_RADIUS = MERCATOR_OFFSET / Math.PI;

function mercatorLatitudeToY(latitude) {
  return Math.round(
    MERCATOR_OFFSET - 
    (
      (
        MERCATOR_RADIUS *
          Math.log(
            (1 + Math.sin(latitude * (Math.PI / 180))) /
            (1 - Math.sin(latitude * (Math.PI / 180)))
          )
      ) / 2
    )
  );
}

function mercatorLongitudeToX(longitude) {
  return Math.round(
    MERCATOR_OFFSET +
      (
        (
          (MERCATOR_RADIUS * longitude) * Math.PI
        ) / 180
      )
  );
}

function mercatorXToLongitude(x) {
  return (
    (
      (x - MERCATOR_OFFSET) / MERCATOR_RADIUS
    ) * 180
  ) / Math.PI;
}

function mercatorYToLatitude(y) {
  return (
    (
      (
        Math.PI / 2
      ) -
        (2 * Math.atan(
              Math.exp(
                (
                  y - MERCATOR_OFFSET
                ) / MERCATOR_RADIUS
              )
            )
        )
    ) * 180
  ) / Math.PI;
}

function mercatorAdjustLatitudeByOffsetAndZoom(latitude, offset, zoom) {
  return mercatorYToLatitude(mercatorLatitudeToY(latitude) + (offset << (21 - zoom)));
}

function mercatorAdjustLongitudeByOffsetAndZoom(longitude, offset, zoom) {
  return mercatorXToLongitude(mercatorLongitudeToX(longitude) + (offset << (21 - zoom)));
}

function mercatorDegreeDeltas(latitude, longitude, width, height, zoom) {

  if (!zoom) {
    zoom = 20;
  }

  const deltaX = width / 2;
  const deltaY = height / 2;

  const northLatitude = mercatorAdjustLatitudeByOffsetAndZoom(latitude, deltaY * -1, zoom);
  const westLongitude = mercatorAdjustLongitudeByOffsetAndZoom(longitude, deltaX * -1, zoom);
  const southLatitude = mercatorAdjustLatitudeByOffsetAndZoom(latitude, deltaY, zoom);
  const eastLongitude = mercatorAdjustLongitudeByOffsetAndZoom(longitude, deltaY, zoom);

  const latitudeDelta = Math.abs(northLatitude - southLatitude);
  const longitudeDelta = Math.abs(eastLongitude - westLongitude);

  return { latitudeDelta, longitudeDelta };
}

// Somewhat arbitrarily, Riverside Park, Independence, KS 67301
const CENTER_UNITED_STATES = {
  latitude: 37.24435373025407,
  longitude: -95.70234410503208,
};

export default function MapViewWrapper() {
  const { width, height } = useWindowDimensions();
  const tabBarHeight = useBottomTabBarHeight();
  const headerHeight = useHeaderHeight();
  const initialRegion = React.useRef(null);
  const availableHeight = height - tabBarHeight - headerHeight;

  // Only calculate initial region once
  if (!initialRegion.current) {
    const { latitudeDelta, longitudeDelta } = mercatorDegreeDeltas(
      CENTER_UNITED_STATES.latitude,
      CENTER_UNITED_STATES.longitude,
      width,
      availableHeight,
      4,
    );
    
    initialRegion.current = {
      latitude: CENTER_UNITED_STATES.latitude,
      longitude: CENTER_UNITED_STATES.longitude,
      latitudeDelta: latitudeDelta,
      longitudeDelta: longitudeDelta,
    };
  }

  return (
    <MapView
      initialRegion={initialRegion.current}
      style={{ width: width, height: availableHeight }}
    />
  );
}

There is at least one issue: if you change the zoom from 4 to 3, it isn't centered properly, but larger zoom values work. I don't need the lower zoom values right now, so I haven't investigated the math any further (maybe some sort of overflow?).

Peraea answered 25/12, 2022 at 19:12 Comment(0)
L
-1

Example of Pinch to Zoom Image in React Native

// Import React in our code
import React from 'react';

// Import all the components we are going to use
import { SafeAreaView, StyleSheet, View } from 'react-native';

// Import ImageViewer which will help us to zoom Image
import ImageViewer from 'react-native-image-zoom-viewer';

const App = () => {
  const images = [
    {
      url:
        'https://raw.githubusercontent.com/AboutReact/sampleresource/master/sample_img.png',
    },
    {
      url:
        'https://raw.githubusercontent.com/AboutReact/sampleresource/master/old_logo.png',
    },
  ];

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <View style={styles.container}>
        <ImageViewer imageUrls={images} renderIndicator={() => null} />
      </View>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#F5FCFF',
    flex: 1,
  },
});

export default App;
Landre answered 15/8, 2021 at 17:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.