Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: LocationPuck bearing not visible on Android #3391

Open
philiplindberg opened this issue Feb 23, 2024 · 11 comments · May be fixed by #3742
Open

[Bug]: LocationPuck bearing not visible on Android #3391

philiplindberg opened this issue Feb 23, 2024 · 11 comments · May be fixed by #3742
Labels
bug 🪲 Something isn't working

Comments

@philiplindberg
Copy link
Contributor

philiplindberg commented Feb 23, 2024

Mapbox Implementation

Mapbox

Mapbox Version

default

React Native Version

0.73.4

Platform

Android

@rnmapbox/maps version

10.1.15

Standalone component to reproduce

import React from 'react'
import { Camera, LocationPuck, MapView } from '@rnmapbox/maps'

export default function App() {
  return (
    <MapView style={{ flex: 1 }}>
      <Camera
        zoomLevel={14}
        followUserLocation={true}
      />
      <LocationPuck
        puckBearingEnabled={true}
      />
    </MapView>
  )
}

Observed behavior and steps to reproduce

When rendering the LocationPuck with its bearing enabled on Android, the bearing does not appear. The bearing does appear on iOS.

Android iOS
unnamed (1) IMG_69F787A3B577-1

Expected behavior

The LocationPuck's bearing should be visible on both Android and iOS if enabled.

Notes / preliminary analysis

No response

Additional links and references

No response

@smartmedev
Copy link

You should use a custom image to show LocationPuck bearing on Android.

<MapboxGL.Images images={{ 
      "userLocationTopImage": markerUserIcon, 
      "headingArrow": headingIcon,
      "headingArrowXS": headingIconXS
      }} />

  <MapboxGL.LocationPuck
      topImage="userLocationTopImage"
      puckBearingEnabled={true} 
      puckBrearing="heading"
      bearingImage="headingArrow"
      visible={true}
      pulsing={{
          isEnabled: true,
          color: customColors.markerUserLocation,
          radius: 50.0,
      }} />

@fahadShah23
Copy link

Hi there! for some reason this custom image is not working for my project in android. Is there any way i could add an SVG icon here instead of the PNG?
I am trying to add the SVG Image but it is giving me some errors.
Here are my project details:

React Native Version
0.70.15

Platform
Android

@rnmapbox/maps version
10.1.15

Code:

import React from 'react';
import { View } from 'react-native';
import MapboxGL from '@rnmapbox/maps';
import markerUserIcon from './markerUserIcon.svg';
import headingIcon from './headingIcon.svg';

const ShowMap = () => {
return (
<View style={{ flex: 1 }}>
<MapboxGL.MapView style={{ flex: 1 }}>
<MapboxGL.Images
images={{
userLocationTopImage: markerUserIcon,
headingArrow: headingIcon,
}}
/>
{/* Other MapboxGL components and configurations */}
</MapboxGL.MapView>

);
};
export default ShowMap;

<MapboxGL.LocationPuck
topImage="userLocationTopImage"
puckBearingEnabled={true}
puckBearing="heading"
bearingImage="headingArrow"
visible={true}
pulsing={{
isEnabled: true,
color: customColors.markerUserLocation,
radius: 50.0,
}}
/>

Error that i am encountering:

Error while updating property 'images' of a view managed by: RNMBXImages
null
next. value must not be null

@mfazekas
Copy link
Contributor

@philiplindberg nope svg is not supported, sorry

@fahadShah23
Copy link

Just a quick question @smartmedev or may be you can answer @mfazekas. How can i import the png images (markerUserIcon, headingIcon, headingIconXS) in my file?
i am trying to import them like below in my working file but they does not seems to be working at my end.

import markerUserIcon from './markerUserIcon.png';
import headingIcon from './headingIcon.png';
import headingIconXS from './headingIconXS.png';

i have placed the icons at the same path as my project file on which i want to use the image. am i doing it correct or anything i need to change here?

@smartmedev
Copy link

Hi @fahadShah23 , in react native you cannot import images with "import". You need require.
In my project I have an "icons.js" files where I require all required images then export them.
(Note that all images are on /app/assets/images/ folder)
On the other side, in components and screens I can import images from icons.js file.

Here's an example:

on my /app/utils/icons.js file:

const headingIcon = require('../assets/images/heading.png');
const markerUserIcon = require('../assets/images/marker-user.png');
const headingIconXS = require('../assets/images/heading-icon-xs.png');

export {
    headingIcon,
    markerUserIcon,
    headingIconXS
}

then on my /app/screens/HomeScreen.js import icons like this:

import { headingIcon, markerUserIcon, headingIconXS } from '../../utils/icons';

<MapboxGL.Images images={{ 
      "userLocationTopImage": markerUserIcon, 
      "headingArrow": headingIcon,
      "headingArrowXS": headingIconXS
      }} />

  <MapboxGL.LocationPuck
      topImage="userLocationTopImage"
      puckBearingEnabled={true} 
      puckBrearing="heading"
      bearingImage="headingArrow"
      visible={true}
      pulsing={{
          isEnabled: true,
          color: customColors.markerUserLocation,
          radius: 50.0,
      }} />

@fahadShah23
Copy link

Hi @smartmedev thank you for your response. I have tried your solution but unfortunately image is still not appearing at my end. No sure what wrong i am doing here, can you please help identify.
Here is my code, for instance i have placed my images on the same path/folder where my code file is.
Below are the path to my implementation file ( where i need to get and show the image) and also the images path:

File Path: /home/{user}/{projectName}/libs/pattern/src/ui/features/Field/DrawField/DrawFieldFeature.native.tsx
Images Path: /home/{user}/{projectName}/libs/pattern/src/ui/features/Field/heading.png
/home/{user}/{projectName}/libs/pattern/src/ui/features/Field/DrawField/marker-user.png
/home/{user}/{projectName}/libs/pattern/src/ui/features/Field/DrawField/heading-icon-xs.png

here is how i am getting them in my file i.e. 'DrawFieldFeature.native.tsx':

const headingIcon = require('./heading.png');
const markerUserIcon = require('./marker-user.png');
const headingIconXS = require('./heading-icon-xs.png');

Here is how i am using the above icons in Images & LocationPuck:

<Images
          images={{
            userLocationTopImage: markerUserIcon,
            headingArrow: headingIcon,
            headingArrowXS: headingIconXS,
          }}
        />
        <LocationPuck
          visible
          topImage="userLocationTopImage"
          bearingImage="headingArrow"
          puckBearingEnabled
          puckBearing="heading"
          pulsing={{ isEnabled: true, radius: 'accuracy', color: 'lightblue' }}
        />

Also just to check if the images are correctly imported in the file, i console the headingIcon, markerUserIcon and headingIconXS values and it gives my an numeric value i.e. 6. is it correct or it should give some kind or uri?

@smartmedev
Copy link

hi @fahadShah23 if images are in the same folder, have you tried to import like this ?
Maybe absolute path could not work.

const headingIcon = require('heading.png');
const markerUserIcon = require('marker-user.png');
const headingIconXS = require('heading-icon-xs.png');

Also, use double quotes "" for the name of image in "images" attribute of element, you didn't put it in your example.

<MapboxGL.Images images={{ 
      "userLocationTopImage": markerUserIcon, 
      "headingArrow": headingIcon,
      "headingArrowXS": headingIconXS
      }} />

Let me know if it works, i think that require should give the path not numbers, but I'm not sure at all.

@brien-crean
Copy link
Contributor

I have tried this but I can only get the bearingImage to show if I hide the topImage. They do not seem to play nice together.

import React from 'react';
import { Images, LocationPuck } from '@rnmapbox/maps';

export default function UserLocationMarker() {
  const headingIcon = require('./heading.png');
  const userIcon = require('./user-location.png');
  return (
    <>
      <Images
        images={{
          headingArrow: headingIcon,
          userLocation: userIcon,
        }}
      />
      <LocationPuck
        // bug? topImage and bearingImage do not work well together
        // topImage={'userLocation'}
        puckBearingEnabled={true}
        puckBearing={'heading'}
        bearingImage={'headingArrow'}
        visible={true}
        pulsing={{ isEnabled: true, radius: 50.0, color: 'lightblue' }}
      />
    </>
  );
}

I'm running Mapbox version 10.1.28 as I am on react native 0.73.8 currently.

@fredro84
Copy link

@brien-crean

I had the same issue as you and came up with an alternative, hope this helps for you. I have a prop called puckBearingEnabled, if that is true and the platform is android, it shows a custom image that already has a bearing arrow in it (which i created myself). I have added the image to the comment in PNG (so you can use it yourself) or SVG (so you can edit it in figma or other tool)

  if (Platform.OS === 'android' && puckBearingEnabled) {
    const bearing = require('../../assets/icons/map/user-location-with-bearing.png');

    const images = {
      headingArrow: bearing,
    };

    locationPuck = (
      <>
        <Images images={images} />

        <Mapbox.LocationPuck
          puckBearingEnabled={puckBearingEnabled}
          puckBearing="heading"
          bearingImage={puckBearingEnabled ? "headingArrow" : null}
          visible={true}
        />
      </>
    );
  } else {
    locationPuck = (
      <Mapbox.LocationPuck
        puckBearingEnabled={puckBearingEnabled}
        puckBearing="heading"
        visible={true}
      />
    );
  }

user-location-with-bearing

user-location-with-bearing

@yuriydrobniy
Copy link

if anyone is looking for a way to use the View component or SVG (react-native-svg), here is an example:

...
import {LocationPuck, Images, Image} from '@rnmapbox/maps';

const ImagesWrapper = ({children}) => {
  // fix ios issue with overlapping the map layer
  if (Platform.OS === 'ios') {
    return <View style={styles.hiddenLayer}>{children}</View>;
  }
  return <>{children}</>;
};

const CustomLocation = () => {
  return (
    <>
      <ImagesWrapper>
        <Images>
          <Image name="topImageID">
            <SomeSvgComponent />
          </Image>
          <Image name="shadowImageID">
            <SomeViewComponent />
          </Image>
        </Images>
      </ImagesWrapper>

      <LocationPuck
        shadowImage="shadowImageID"
        topImage="topImageID"
        puckBearingEnabled={true}
        puckBearing="heading"
        pulsing={{
          isEnabled: false,
        }}
      />
    </>
  );
};

const styles = StyleSheet.create({
  hiddenLayer: {
    position: 'absolute',
    top: -1000,
    left: -1000,
  },
});

@RmStorm
Copy link

RmStorm commented Jan 17, 2025

It seems to me like the puckBearingEnabled property just gets ignored inside Android? Like right here it's supposed to set the bearing image and it only pays attention to the deprecated androidRenderMode. It looks to me like that function in particular is just a poor imitation of the Android SDK's createDefault2DPuck. Which is what should be used instead I think..

Anyhow, I'll see if I have time make a PR so everybody can stop messing around with loading custom images for a bearing indicator hahaha.

@RmStorm RmStorm linked a pull request Jan 17, 2025 that will close this issue
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🪲 Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants