Maps: Can't press ShapeSource on top of UserLocation

Created on 12 Jul 2019  路  11Comments  路  Source: react-native-mapbox-gl/maps

Hello,

image

I have a SymbolLayer located underneath the UserLocation, and I wish the SymbolLayer to be pressable.
But it seems it can't be done: when I press the icon, it is actually the UserLocation which is pressed, and the UserLocation onPress event doesn't have any argument and doesn't have a pointerEvents prop or equivalent.

Is there a way to get to the SymbolLayer ?

Again, great repo, and greater to become, thanks all for the work done !

Most helpful comment

Alright, with a proper utilisation of belowLayerID and aboveLayerId, I got this working.
SUppose your SymbolLayer within your ShapeSource has an id of markersSymbol, here is the code I used for the UserLocation

import React from 'react';
import MapboxGL from '@react-native-mapbox-gl/maps';
import { withTheme } from 'styled-components';

const layerStyles = (circleColor) => ({
  pluse: {
    circleRadius: 15,
    circleColor,
    circleOpacity: 0.2,
    circlePitchAlignment: 'map',
  },
  background: {
    circleRadius: 9,
    circleColor: '#fff',
    circlePitchAlignment: 'map',
  },
  foreground: {
    circleRadius: 6,
    circleColor,
    circlePitchAlignment: 'map',
  },
});


const MyUserLocation = ({ theme: { color: { primary } } }) =>
  <MapboxGL.UserLocation
    visible
    animated
  >
    <MapboxGL.CircleLayer
      key="mapboxUserLocationPluseCircle"
      id="mapboxUserLocationPluseCircle"
      belowLayerID='markersSymbol'
      style={layerStyles(primary).pluse}
    />
    <MapboxGL.CircleLayer
      key="mapboxUserLocationWhiteCircle"
      id="mapboxUserLocationWhiteCircle"
      belowLayerID='markersSymbol'
      style={layerStyles(primary).background}
    />
    <MapboxGL.CircleLayer
      key="mapboxUserLocationBlueCicle"
      id="mapboxUserLocationBlueCicle"
      belowLayerID='markersSymbol'
      aboveLayerID="mapboxUserLocationWhiteCircle"
      style={layerStyles(primary).foreground}
    />
  </MapboxGL.UserLocation>

export default withTheme(MyUserLocation)

All 11 comments

@mfazekas can you experience the same behaviour ?

I can see on ShapeSource.md that

Source press listener, gets called when a user presses one of the children layers only
if that layer has a higher z-index than another source layers

And I can see that UserLocation is an Annotation, and Annotation is a ShapeSource, so does it mean that we should give a low z-index to UserLocation ? If so, how can we achieve this ?

Having the same issue, was this fixed?

No fix for now

Workaround can be to put a transparent layer on top of the layer in the shape source with a higher index than user location.

We could accept a PR with a prop on UserLocation that disables the on press listener, but I honestly feel like this is a very narrow usecase with a functional workaround.

Hi @kristfal
Thanks for the tip, but I just spent a few hours on it and I don't see how to proceed.
The last step I've done has been to increase the layerIndex of my SymbolLayer while hot reloading, which is working while hot reloading until the layerIndex 196 (don't ask me why !), then at 197 it crashes. At 196, I could see that my SymbolLayer was coming on top of the UserLocation so I was quite happy, but I still couldn't click on it.
But when I reload the app with 196, it crashes directly (even more: it quits unexpectedly and I need to yarn ios again).

So I don't see how to proceed ! If you have one more clue it would be really nice...

@kristfal I don't think this is a narrow usecase... If anyone has custom markers rendered (think of the earthquake example) which are clickable, none can be clicked if they are within a 1inch by 1inch square of UserLocation...

@kristfal I need to move forward on the subject now, this is becoming critical to me... a help would be great if possible !

Workaround can be to put a transparent layer on top of the layer in the shape source with a higher index than user location.
According to this comment on #392 , the layerIndex is still a problem, how could you use it ?

We could accept a PR with a prop on UserLocation that disables the on press listener, but I honestly feel like this is a very narrow usecase with a functional workaround.
How do you disable the onPress listener and not capture the touch press so that it goes to the underlying Symbol ?

Thanks !

Alright, with a proper utilisation of belowLayerID and aboveLayerId, I got this working.
SUppose your SymbolLayer within your ShapeSource has an id of markersSymbol, here is the code I used for the UserLocation

import React from 'react';
import MapboxGL from '@react-native-mapbox-gl/maps';
import { withTheme } from 'styled-components';

const layerStyles = (circleColor) => ({
  pluse: {
    circleRadius: 15,
    circleColor,
    circleOpacity: 0.2,
    circlePitchAlignment: 'map',
  },
  background: {
    circleRadius: 9,
    circleColor: '#fff',
    circlePitchAlignment: 'map',
  },
  foreground: {
    circleRadius: 6,
    circleColor,
    circlePitchAlignment: 'map',
  },
});


const MyUserLocation = ({ theme: { color: { primary } } }) =>
  <MapboxGL.UserLocation
    visible
    animated
  >
    <MapboxGL.CircleLayer
      key="mapboxUserLocationPluseCircle"
      id="mapboxUserLocationPluseCircle"
      belowLayerID='markersSymbol'
      style={layerStyles(primary).pluse}
    />
    <MapboxGL.CircleLayer
      key="mapboxUserLocationWhiteCircle"
      id="mapboxUserLocationWhiteCircle"
      belowLayerID='markersSymbol'
      style={layerStyles(primary).background}
    />
    <MapboxGL.CircleLayer
      key="mapboxUserLocationBlueCicle"
      id="mapboxUserLocationBlueCicle"
      belowLayerID='markersSymbol'
      aboveLayerID="mapboxUserLocationWhiteCircle"
      style={layerStyles(primary).foreground}
    />
  </MapboxGL.UserLocation>

export default withTheme(MyUserLocation)

@arnaudambro I'm not entirely following your solution - how would you apply that to my code below?

      <MapboxGL.ShapeSource
        id="ShapeSource"
        shape={this.state.featureCollection}
        cluster
        clusterRadius={50}
        clusterMaxZoom={16}
      >
        <MapboxGL.SymbolLayer id="pointCount" />
        <MapboxGL.SymbolLayer
          id="clusteredPoints"
          belowLayerID="pointCount"
          filter={['has', 'point_count']}
          style={layerStyles.clusterIcon}
        />
        <MapboxGL.SymbolLayer
          id="singleIcon"
          filter={['!', ['has', 'point_count']]}
          style={layerStyles.icon}
        />
      </MapboxGL.ShapeSource>

Can you provide the whole code, markers + user-location so that I can test myself ?

@arnaudambro Thank you very much for your help! I'm getting a step closer to what i'm looking for.

With your solution, user is hidden below the symbol so it can not be seen. What I'm trying to do is to have user on the top of the symbol but the user layer not capturing onPress event that way the layer of the symbol could catch the onPress event.

For know I did set a pulse circleRadius larger than my symbol that way the user can still guess where he is located on the map by seeing a part of the pulse circle. Bad UX but better than seeing nothing 馃槃

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bartolkaruza picture bartolkaruza  路  3Comments

calypsow777 picture calypsow777  路  5Comments

alexisrougnant picture alexisrougnant  路  3Comments

MariaSyed picture MariaSyed  路  4Comments

RichardLindhout picture RichardLindhout  路  4Comments