Reputation: 167
I am using react-map-gl
and I am rendering markers within the map. I also have some hover animations going on, animations are only css so far, except when you click a marker (Not of importance for this question though).
So far it works as I want and it looks tidy.
But as you can see, in the middle of the map, I have a cluster of markers, they are close to each other. And when I hover one of them in the background it looks like this:
As you can see it does not place it self on top on the other markers, which is desired.
This is the CSS on hover:
.pointer {
transform-origin: bottom center;
width: 40px;
position: absolute;
display: flex;
justify-content: center;
align-items: center;
bottom:0;
transform: translateX(-50%);
&:hover {
animation-name: bounce;
animation-duration: .5s;
animation-fill-mode: forwards;
z-index: 1000;
+ .text {
animation-name: bounce-text;
animation-duration: .4s;
animation-fill-mode: forwards;
animation-delay: .2s;
}
}
}
As you can see I am trying to rise the z-index to 1000 on hover, but it has no effect. Probably since each <Marker/>
is absolute positioned and probably has it's own z-index stack.
Here is the Javascript for the Marker loop:
<ReactMapGl
ref={mapEl}
{...viewPort}
onViewportChange={(_viewport:any) => setViewport(_viewport)}
mapboxApiAccessToken={mapboxToken}
mapStyle="mapbox://styles/mapbox/satellite-v9"
style={{position:'relative', zIndex: '1'}}
>
{mapData.markerCategories.map((markerCategory, i) =>
<React.Fragment key={i}>
{markerCategory.markers.map((marker, i) => <Marker
latitude={marker.position[0]}
longitude={marker.position[1]}
key={i}
>
<Pointer viewPort={viewPort} marker={marker} markerCategory={markerCategory} setViewport={(viewPort:any) => setViewport(viewPort)}/>
</Marker>)}
</React.Fragment>
)}
</ReactMapGl>
The <Pointer/>
component is basically each graphic Icon with svg and CSS for it.
I can not find a solution of this. So my question is, how do I rise a marker to top on each hover by CSS (preferred) or JavaScript?
Upvotes: 1
Views: 3032
Reputation: 56
With maplibre react-map-gl setup, the following simple trick solved the problem.
In App.css: (Naturally the mapbox classname variant can be interchanged with the below.)
.maplibregl-marker:hover {
z-index: 1000;
}
Upvotes: 1
Reputation: 167
Ok, no massive response to this question. :) But I have solved it the "react way". Since I couldn't fix it by CSS I use a hook ([markerCategories, setMarkerCategories]
) and re-structure the array of categories and markers on hover and by doing this the hovered marker gets to the top since the component is re-rendering by the changed array.
const [markerCategories, setMarkerCategories] = useState(mapData.markerCategories);
<React.Fragment key={catIndex}>
{markerCategory.markers.map((marker, markerIndex) => <Marker
latitude={marker.position[0]}
longitude={marker.position[1]}
key={markerIndex}
>
<Pointer
viewPort={viewPort}
marker={marker}
markerCategory={markerCategory}
setViewport={(viewPort:any) => setViewport(viewPort)}
onMouseEnter={() => setMarkerCategories([
...markerCategories.filter(item => item.type !== markerCategory.type),
{
...markerCategory,
markers: [
...markerCategory.markers.filter((item:any) => item.position !== marker.position),
marker
]
}
])}
/>
</Marker>)}
The magic lies within the onMouseEnter
function where I make the category and marker/pointer last in its array. React magically re-render the markers by this new array order and the current marker gets on top. A bit messy and beautiful in the same way. :)
A bit over the top, but for future reference; This is how the mapData is structured from the start (Yes, it is just dummy data):
const mapData = {
zoom: 12,
position: [55.582559800905926, 13.00460428558812],
markerCategories: [
{
type: 'arena',
color: '#755728',
markers: [
{
name: 'Swedbank Arena',
position: [55.58372409722235, 12.987802928589106]
}
]
},
{
type: 'club',
color: '#14366c',
markers: [
{
name: 'Jockes rackabajsarlag',
position: [55.57136374188293, 12.993493330258282]
}
]
},
{
type: 'lodging',
color: '#25841e',
markers: [
{
name: 'Trevligt boende',
position: [55.564897074686044, 12.973576492024604]
}
]
},
{
type: 'atm',
color: '#7f8211',
markers: [
{
name: 'Minuten vid Stadion',
position: [55.584444422651, 12.989066100435894]
}
]
},
{
type: 'restaurant',
color: '#b51818',
markers: [
{
name: 'O\'Leareys',
position: [55.580453319248676, 12.958853177352454]
},
{
name: 'McDonalds',
position: [55.594068887959075, 12.9500562658861]
},
{
name: 'Orvars Korvar',
position: [55.59442766868656, 12.950861573607154]
}
]
},
{
type: 'parking',
color: 'black',
markers: [
{
name: 'Parkering stadion',
position: [55.581107954130964, 12.989043415954846]
}
]
},
{
type: 'airplane',
color: '#3f7d7a',
markers: [
{
name: 'Arlanda',
position: [55.590521772112474, 12.988904530774507]
}
]
},
{
type: 'bus',
color: '#3f7d7a',
markers: [
{
name: 'Södervärn',
position: [55.58882552719527, 13.006218825143767]
}
]
},
{
type: 'boat',
color: '#3f7d7a',
markers: [
{
name: 'Malmö Hamn',
position: [55.61658609761757, 12.997289117070949]
}
]
},
{
type: 'train',
color: '#3f7d7a',
markers: [
{
name: 'Malmö Centralstation',
position: [55.60946379977733, 13.00001154238099]
}
]
},
{
type: 'party',
color: '#993097',
markers: [
{
name: 'Disco',
position: [55.585603832951875, 13.04571167681943]
}
]
},
{
type: 'themePark',
color: '#993097',
markers: [
{
name: 'Arnes Tivoli',
position: [55.57454396334526, 12.910502768373405]
}
]
},
{
type: 'swim',
color: '#993097',
markers: [
{
name: 'Kalkbrott',
position: [55.56765833496694, 12.931152245583036]
}
]
},
{
type: 'misc',
color: '#595959',
markers: [
{
name: 'Kul plats!',
position: [55.597915073658775, 12.92999260814335]
}
]
}
]
}
Upvotes: 1