Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native - MapView - Annotations with custom image

Tags:

react-native

I am writing a react native app that uses the MapView Component. I would like to have annotations with custom images. The React Native Docs for MapView have this to say.

var CustomPinImageMapViewExample = React.createClass({

  getInitialState(): CustomPinImageMapViewExampleState {
    return {
      isFirstLoad: true,
    };
  },

  render() {
    if (this.state.isFirstLoad) {
      var onRegionChangeComplete = (region) => {
        this.setState({
          isFirstLoad: false,
          annotations: [{
            longitude: region.longitude,
            latitude: region.latitude,
            title: 'Thumbs Up!',
            image: require('image!uie_thumb_big'),
          }],
        });
      };
    }

    return (
      <MapView
        style={styles.map}
        onRegionChangeComplete={onRegionChangeComplete}
        region={this.state.mapRegion}
        annotations={this.state.annotations}
      />
    );
  },

});

and tell me that an annotation has an image property which should be set to a Image.propTypes.source.

annotations [{latitude: number, longitude: number, animateDrop: bool,
title: string, subtitle: string, hasLeftCallout: bool, hasRightCallout:
bool, onLeftCalloutPress: function, onRightCalloutPress: function, 
tintColor: string, image: Image.propTypes.source, id: string}] 

I tried adding a url for an image to the image prop on an annotation as you can see here

'use strict';
import React, { Component, Navigator } from 'react-native';

let {
  MapView,
    StyleSheet,
} = React;

class Map extends Component {
    constructor(props) {
        super(props);
        this.state = {
            email : '',
      mapRegion : {latitude: 40.734099, longitude: -73.981016, latitudeDelta: 0.3, longitudeDelta: 0.3},
      annotations : [
      {
        longitude: -73.981831,
        latitude: 40.733481,
        title: 'Pickup',
        subtitle: 'a subtitle',
        hasLeftCallout: true,
        hasRightCallout: true,
        animateDrop: true,
      },
      {
        longitude: -73.982282,
        latitude: 40.735985,
        title: 'Dropoff',
        image: 'http://facebook.github.io/react/img/logo_og.png'
      }],
    };
    }


    render(){
        return (
                <MapView
          style={styles.map}
          annotations={this.state.annotations}
          showsUserLocation={true}
        />
        );
    }
}

const styles = StyleSheet.create({
  map: {
    height: 300,
    margin: 0,
  },
});
export default Map;

This did not do anything :(. In addition, I cant even find any mention of an image property in the source for the MapView Component. Which you can look at here.

/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule MapView
 * @flow
 */
'use strict';

var EdgeInsetsPropType = require('EdgeInsetsPropType');
var NativeMethodsMixin = require('NativeMethodsMixin');
var Platform = require('Platform');
var React = require('React');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var View = require('View');

var createReactNativeComponentClass = require('createReactNativeComponentClass');
var deepDiffer = require('deepDiffer');
var insetsDiffer = require('insetsDiffer');
var merge = require('merge');
var requireNativeComponent = require('requireNativeComponent');

type Event = Object;
type MapRegion = {
  latitude: number;
  longitude: number;
  latitudeDelta: number;
  longitudeDelta: number;
};

var MapView = React.createClass({
  mixins: [NativeMethodsMixin],

  checkAnnotationIds: function (annotations: Array<Object>) {

    var newAnnotations = annotations.map(function (annotation) {
      if (!annotation.id) {
        // TODO: add a base64 (or similar) encoder here
        annotation.id = encodeURIComponent(JSON.stringify(annotation));
      }

      return annotation;
    });

    this.setState({
      annotations: newAnnotations
    });
  },

  componentWillMount: function() {
    if (this.props.annotations) {
      this.checkAnnotationIds(this.props.annotations);
    }
  },

  componentWillReceiveProps: function(nextProps: Object) {
    if (nextProps.annotations) {
      this.checkAnnotationIds(nextProps.annotations);
    }
  },

  propTypes: {
    /**
     * Used to style and layout the `MapView`.  See `StyleSheet.js` and
     * `ViewStylePropTypes.js` for more info.
     */
    style: View.propTypes.style,

    /**
     * If `true` the app will ask for the user's location and focus on it.
     * Default value is `false`.
     *
     * **NOTE**: You need to add NSLocationWhenInUseUsageDescription key in
     * Info.plist to enable geolocation, otherwise it is going
     * to *fail silently*!
     */
    showsUserLocation: React.PropTypes.bool,

    /**
     * If `false` the user won't be able to pinch/zoom the map.
     * Default value is `true`.
     */
    zoomEnabled: React.PropTypes.bool,

    /**
     * When this property is set to `true` and a valid camera is associated with
     * the map, the camera’s heading angle is used to rotate the plane of the
     * map around its center point. When this property is set to `false`, the
     * camera’s heading angle is ignored and the map is always oriented so
     * that true north is situated at the top of the map view
     */
    rotateEnabled: React.PropTypes.bool,

    /**
     * When this property is set to `true` and a valid camera is associated
     * with the map, the camera’s pitch angle is used to tilt the plane
     * of the map. When this property is set to `false`, the camera’s pitch
     * angle is ignored and the map is always displayed as if the user
     * is looking straight down onto it.
     */
    pitchEnabled: React.PropTypes.bool,

    /**
     * If `false` the user won't be able to change the map region being displayed.
     * Default value is `true`.
     */
    scrollEnabled: React.PropTypes.bool,

    /**
     * The map type to be displayed.
     *
     * - standard: standard road map (default)
     * - satellite: satellite view
     * - hybrid: satellite view with roads and points of interest overlayed
     */
    mapType: React.PropTypes.oneOf([
      'standard',
      'satellite',
      'hybrid',
    ]),

    /**
     * The region to be displayed by the map.
     *
     * The region is defined by the center coordinates and the span of
     * coordinates to display.
     */
    region: React.PropTypes.shape({
      /**
       * Coordinates for the center of the map.
       */
      latitude: React.PropTypes.number.isRequired,
      longitude: React.PropTypes.number.isRequired,

      /**
       * Distance between the minimun and the maximum latitude/longitude
       * to be displayed.
       */
      latitudeDelta: React.PropTypes.number.isRequired,
      longitudeDelta: React.PropTypes.number.isRequired,
    }),

    /**
     * Map annotations with title/subtitle.
     */
    annotations: React.PropTypes.arrayOf(React.PropTypes.shape({
      /**
       * The location of the annotation.
       */
      latitude: React.PropTypes.number.isRequired,
      longitude: React.PropTypes.number.isRequired,

      /**
       * Whether the pin drop should be animated or not
       */
      animateDrop: React.PropTypes.bool,

      /**
       * Annotation title/subtile.
       */
      title: React.PropTypes.string,
      subtitle: React.PropTypes.string,

      /**
       * Whether the Annotation has callout buttons.
       */
      hasLeftCallout: React.PropTypes.bool,
      hasRightCallout: React.PropTypes.bool,

      /**
       * Event handlers for callout buttons.
       */
      onLeftCalloutPress: React.PropTypes.func,
      onRightCalloutPress: React.PropTypes.func,

      /**
       * annotation id
       */
      id: React.PropTypes.string

    })),

    /**
     * Maximum size of area that can be displayed.
     */
    maxDelta: React.PropTypes.number,

    /**
     * Minimum size of area that can be displayed.
     */
    minDelta: React.PropTypes.number,

    /**
     * Insets for the map's legal label, originally at bottom left of the map.
     * See `EdgeInsetsPropType.js` for more information.
     */
    legalLabelInsets: EdgeInsetsPropType,

    /**
     * Callback that is called continuously when the user is dragging the map.
     */
    onRegionChange: React.PropTypes.func,

    /**
     * Callback that is called once, when the user is done moving the map.
     */
    onRegionChangeComplete: React.PropTypes.func,

    /**
     * Callback that is called once, when the user taps an annotation.
     */
    onAnnotationPress: React.PropTypes.func,
  },

  _onChange: function(event: Event) {
    if (event.nativeEvent.continuous) {
      this.props.onRegionChange &&
        this.props.onRegionChange(event.nativeEvent.region);
    } else {
      this.props.onRegionChangeComplete &&
        this.props.onRegionChangeComplete(event.nativeEvent.region);
    }
  },

  _onPress: function(event: Event) {
    if (event.nativeEvent.action === 'annotation-click') {
      this.props.onAnnotationPress && this.props.onAnnotationPress(event.nativeEvent.annotation);
    }

    if (event.nativeEvent.action === 'callout-click') {
      if (!this.props.annotations) {
        return;
      }

      // Find the annotation with the id of what has been pressed
      for (var i = 0; i < this.props.annotations.length; i++) {
        var annotation = this.props.annotations[i];
        if (annotation.id === event.nativeEvent.annotationId) {
          // Pass the right function
          if (event.nativeEvent.side === 'left') {
            annotation.onLeftCalloutPress && annotation.onLeftCalloutPress(event.nativeEvent);
          } else if (event.nativeEvent.side === 'right') {
            annotation.onRightCalloutPress && annotation.onRightCalloutPress(event.nativeEvent);
          }
        }
      }

    }
  },

  render: function() {
    return <RCTMap {...this.props} onPress={this._onPress} onChange={this._onChange} />;
  },
});

if (Platform.OS === 'android') {
  var RCTMap = createReactNativeComponentClass({
    validAttributes: merge(
      ReactNativeViewAttributes.UIView, {
        active: true,
        showsUserLocation: true,
        zoomEnabled: true,
        rotateEnabled: true,
        pitchEnabled: true,
        scrollEnabled: true,
        region: {diff: deepDiffer},
        annotations: {diff: deepDiffer},
        maxDelta: true,
        minDelta: true,
        legalLabelInsets: {diff: insetsDiffer},
      }
    ),
    uiViewClassName: 'RCTMap',
  });
} else {
  var RCTMap = requireNativeComponent('RCTMap', MapView, {
    nativeOnly: {onChange: true, onPress: true}
  });
}

module.exports = MapView;

Here is my packadge.json for dependency info. Hope somebody can help me give my MapView annotations custom images!

"dependencies": {
    "react-native": "0.13 - 0.14",
    "react-native-button": "^1.3.1",
    "react-native-side-menu": "^0.15.5"
  },
  "devDependencies": {
    "babel-core": "^6.1.2",
    "babel-eslint": "^4.1.3",
    "babel-loader": "^6.0.0",
    "babel-preset-es2015": "^6.0.14",
    "babel-preset-react": "^6.0.14",
    "babel-preset-stage-1": "^6.1.2",
    "eslint": "^1.8.0",
    "eslint-loader": "^1.1.1",
    "eslint-plugin-react": "^3.6.3",
    "react": "^0.14.3",
    "react-native-side-menu": "^0.15.5",
    "react-native-webpack-server": "^0.8.1",
    "react-redux": "3.1",
    "redux": "^3.0.4",
    "redux-multi": "^0.1.10",
    "redux-thunk": "^1.0.0",
    "webpack": "^1.12.2",
    "webpack-dev-server": "^1.12.1"
  }, 
like image 516
Benjamin Conant Avatar asked Mar 14 '23 22:03

Benjamin Conant


1 Answers

try...

image: require('./relative/page/to/image.png'),
like image 144
Troy Avatar answered Apr 03 '23 01:04

Troy