How to stop cursor flickering over mapbox marker icons? - mapbox

How do I stop cursor flickering over my Mapbox icons? Here is the live site where you can see the problem when hovering over the marker icons: https://rustic-waters-group.thesparksite.com/lakes/
Here is my code:
mapboxgl.accessToken = 'pk.eyJ1IjoiZG1pdHJpbWFydGluIiwiYSI6ImNreHRobHRmcjVqM3cydmt5NWkxdWNibTcifQ.CuN5Dwc963TW-BKRcowxBA';
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/dmitrimartin/ckxtj5aur4fvv15mrhmihala8',
center: [-89.2, 44.33],
zoom: 9.2
});
map.on('load', () => {
const popup = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false
});
map.on('mouseenter', 'lakes', (event) => {
map.getCanvas().style.cursor = 'pointer';
const features = map.queryRenderedFeatures(event.point, {
layers: ['lakes']
});
if (event.features.length === 0) return;
popup.setLngLat(features[0].geometry.coordinates);
popup.setHTML('<h3 class="lake-popup">' + features[0].properties.title + '</h3>');
popup.setMaxWidth("calc(100vw - 40px);");
popup.addTo(map);
});
map.on('mouseleave', 'lakes', () => {
map.getCanvas().style.cursor = '';
popup.remove();
});
map.on('click', 'lakes', (event) => {
const features = map.queryRenderedFeatures(event.point, {
layers: ['lakes']
});
if (event.features.length === 0) return;
window.location.href = ('/lakes/' + features[0].properties.url + '/');
});
document.getElementById("lakes-header").onmouseover = function() {
MyMouseOver();
};
function MyMouseOver() {
document.getElementById("wrapper").style.display = "none";
document.getElementById("lakes-header").style.display = "none";
}
});

The issue stems from the popup box on top of the layer and can be fixed by adding the CSS property 'cursor-events: none' to the popup. That should stop the flickering and shouldn't interfere with the layers.

Related

Custom transform control for geoman

I am trying to add a custom transform control to geoman, to do certain transformations with polylines and polygons. I see that on edit, geoman draws hint lines above vertices etc. I would like my tool to highlight polylines/polygons with the same type of hints. Below is the skeleton of my action:
const ConvertAction = L.Toolbar2.Action.extend({
options: {
toolbarIcon: {
html:
'<div class="icon-maps icon-convert" title="Convert point"></div>',
tooltip: 'Convert point'
}
},
addHooks: () => {
// draw polygon
// map.pm.enableDraw();
changeConvert();
}
});
function changeConvert() {
convert = true;
map.eachLayer(function (layer) {
if (layer.feature && layer.feature.geometry.type === 'Point') {
layer._icon.style['pointer-events'] = 'auto';
}
});
}
Is there an internal function or something that I could use to outline shapes? When I enable Edit layers tool already built into the geoman, shapes are outlined for me. How could I achieve this from my code without having to reimplement the entire thing?
Thus far, after quickly reviewing geoman code, I was able to come up with:
const ConvertAction = L.Toolbar2.Action.extend({
options: {
toolbarIcon: {
html:
'<div class="icon-maps icon-convert" title="Convert point"></div>',
tooltip: 'Convert point'
}
},
addHooks: () => {
// draw polygon
// map.pm.enableDraw();
if (!convert) changeConvert();
else disableConvert();
}
});
function changeConvert() {
convert = true;
map.eachLayer(function (layer) {
if (
layer?.feature?.geometry.type === 'Polygon' ||
layer?.feature?.geometry.type === 'LineString'
) {
const coords = layer.getLatLngs();
const markerGroup = new L.LayerGroup();
markerGroup._pmTempLayer = true;
const createMarker = (latlng) => {
const marker = new L.Marker(latlng, {
draggable: true,
icon: L.divIcon({ className: 'marker-icon' })
});
layer.options.pane =
(map.pm.globalOptions.panes &&
map.pm.globalOptions.panes.vertexPane) ||
'markerPane';
marker._pmTempLayer = true;
markerGroup.addLayer(marker);
return marker;
};
const handleRing = (coordsArr) => {
// if there is another coords ring, go a level deep and do this again
if (Array.isArray(coordsArr[0])) {
return coordsArr.map(handleRing, this);
}
// the marker array, it includes only the markers of vertexes (no middle markers)
const ringArr = coordsArr.map(createMarker);
return ringArr;
};
const markers = handleRing(coords);
map.addLayer(markerGroup);
}
});
}
function disableConvert() {
convert = false;
map.eachLayer(function (layer) {
if (
layer.dragging &&
layer.options?.draggable === true &&
layer._pmTempLayer === true
) {
console.log('temp layer:', layer);
map.removeLayer(layer);
}
});
update();
}
Seems like an excessive amount of code, and reimplementation [and probably not as good the geoman version as I don't fully understand geoman code by far] of existing functionality.
How do I simplify/fix this?

I can make clickable country labels but get error when I click anywhere else

I am trying to create a pop when the user clicks the country label. My code accomplishes this but if the user accidentally clicks anywhere else I get the error "TypeError: Cannot read property 'properties' of undefined". Any help would be appreciated. Thanks.
export default class App extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
lng: -32.87393,
lat: 43.6439,
zoom: 3,
mxZoom: 7,
};
this.mapContainer = React.createRef();
}
componentDidMount() {
const { lng, lat, zoom , mxZoom} = this.state;
const map = new mapboxgl.Map({
container: this.mapContainer.current,
style: 'mapbox://styles/chriswade112358/ckpipp5el0jky18qwzep8ppyl',
center: [lng, lat],
zoom: zoom,
minZoom: zoom,
maxZoom: mxZoom,
});
map.on('style.load', function() {
map.on('click', function(e) {
const features = map.queryRenderedFeatures(e.point, { layers: ['country-label'] });
new mapboxgl.Popup()
.setLngLat(e.lngLat)
.setHTML('you clicked here: <br/>' + features[0].properties.name)
.addTo(map);
});
});
}

Openlayer Linestring with two or more lines on the one or more coordinates?

My problem is the following:
Linestring with two or more lines on the one or more coordinates.
With several LineStrings only one string is shown in the map, I know, the LineStrings also use the same coordinates.
Is there a way that the LineStrings can use one and the same coordinates, but a shift of the line (to have for example three lines next to each other) takes place in the structure of the map?
The code is a bit better, which explains a lot:
var logoElement = document.createElement ('a');
logoElement.href = 'http://www.schienenpost.de/';
logoElement.target = '_blank';
var logoImage = document.createElement ('img');
logoImage.src = 'http://www.schienenpost.de/schienenpost.png';
logoElement.appendChild (logoImage);
var iconStyle = new ol.style.Style ({
image: new ol.style.Icon (/** #type {olx.style.IconOptions} */ ({
anchor: [0.5, 1.0],
src: 'http://www.schienenpost.de/marker/marker.png'
}))
});
var scaleLineControl = new ol.control.ScaleLine();
var markerStartEnd = function (layer,feature) {
var i, iconFeature, iconFeatures = [], coordinates, nameLine;
coordinates = feature.getGeometry ().getCoordinates ();
nameLine = feature.getProperties () ['name'];
i = 0;
iconFeature = new ol.Feature ({
geometry: new ol.geom.Point (coordinates[i]),
name: 'Start'+nameLine,
});
iconFeature.setStyle (iconStyle);
iconFeatures.push (iconFeature);
i = coordinates.length - 1;
iconFeature = new ol.Feature ({
geometry: new ol.geom.Point (coordinates[i]),
name: 'End'+nameLine,
});
iconFeature.setStyle (iconStyle);
iconFeatures.push (iconFeature);
layer.getSource ().addFeatures (iconFeatures);
};
var layerLines = new ol.layer.Vector ({
source: new ol.source.Vector ({
format: new ol.format.GeoJSON (),
url: 'schienenpost.geojson',
useSpatialIndex: false
}),
style: new ol.style.Style ({stroke: new ol.style.Stroke ({color : 'red', width: 3})}),
});
var layerMarker = new ol.layer.Vector ({
title: 'Marker',
source: new ol.source.Vector ()
});
var element = document.getElementById ('popup');
var popup = new ol.Overlay ({
element: element,
positioning: 'bottom-center',
stopEvent: false,
offset: [0, -0]
});
var map = new ol.Map ({
controls: ol.control.defaults ()
.extend ([
new ol.control.OverviewMap (),
new ol.control.FullScreen (),
scaleLineControl
]),
//target 'map',
target: document.getElementById ('map'),
layers: [
new ol.layer.Tile ({
source: new ol.source.OSM ()
}),
],
view: new ol.View ({
center: ol.proj.fromLonLat ([10.627, 53.620]),
zoom: 8
}),
logo: logoElement
});
map.addOverlay (popup);
map.addLayer (layerLines);
map.addLayer (layerMarker);
map.once ('moveend', function(e) {
layerLines.getSource ().getFeaturesCollection ().forEach (function (feature) {
markerStartEnd (layerMarker,feature);
});
});
map.on ('click', function (evt) {
var feature = map.forEachFeatureAtPixel (evt.pixel,
function (feature) {
return feature;
});
if (feature) {
var coordinates = feature.getGeometry ().getCoordinates ();
var clickpoint = map.getCoordinateFromPixel (evt.pixel);
if (!isNaN (coordinates [0])) { // Punkt
popup.setPosition (coordinates);
} else if (!isNaN (coordinates [0][0])) { // Linie
popup.setPosition (clickpoint);
} else { // kein brauchbares feature
$ (element).popover ('destroy');
return;
}
$ (element).popover ({
'placement': 'top',
'html': true,
'content': feature.get ('name')
});
$ (element).popover ().data ('bs.popover').options.content = feature.get ('name');
$ (element).popover ('show');
} else {
$ (element).popover ('hide');
}
});
map.on ('pointermove', function(e) {
if (e.dragging) {
$ (element).popover ('destroy');
return;
}
var pixel = map.getEventPixel (e.originalEvent);
var hit = map.hasFeatureAtPixel (pixel);
map.getTarget ().style.cursor = hit ? 'pointer' : '';
});

Leafletjs: How to have new marker in first click then update the latlng of marker in second click

I have list of markers that want to render in the map, but I want it one by one. In first click I want to make new marker. Then when I click to another location, I want my marker to just move to the new latLng not to create another marker. Here is my code:
function (licon, coord, data) {
var self = jQuery(this);
var map = self.data("map");
var latlng = new L.LatLng(coord[0], coord[1]);
//Create Marker
if (licon) {
var leafIcon = L.icon(licon);
console.log(typeof (marker));
if (typeof (marker) === 'undefined') {
var marker = L.marker(latlng, {
icon: leafIcon,
"markerData": data,
draggable: true
});
} else {
console.log('not undefined');
map.removeLayer(marker);
marker = L.marker(latlng, {
icon: leafIcon,
"markerData": data,
draggable: true
});
}
} else {
var marker = L.marker(latlng, {
"markerData": data,
draggable: true
});
}
marker.addTo(map);
return marker;
}
A quick example of the result: http://jsfiddle.net/ve2huzxw/43/
var currentMarker;
map.on("click", function (event) {
if (currentMarker) {
currentMarker.setLatLng(event.latlng);
return;
}
currentMarker = L.marker(event.latlng, {
draggable: true
}).addTo(map).on("click", function () {
event.originalEvent.stopPropagation();
});
});
document.getElementById("done").addEventListener("click", function () {
currentMarker = null;
});
You can also add a smooth transition to show the marker moving to the new position:
if (currentMarker) {
currentMarker._icon.style.transition = "transform 0.3s ease-out";
currentMarker._shadow.style.transition = "transform 0.3s ease-out";
currentMarker.setLatLng(event.latlng);
setTimeout(function () {
currentMarker._icon.style.transition = null;
currentMarker._shadow.style.transition = null;
}, 300);
return;
}
a slightly more consolidated solution some years later.
var currentMarker;
map2.on('click', function(e) {
if (currentMarker){
currentMarker.setLatLng(e.latlng)
} else {
currentMarker = new L.marker(e.latlng).addTo(map2);
};
//console.log('lat, lon: ', e.latlng.lat, e.latlng.lng);
});
leaflet now defaults to smoothly dragging the point over to the new coords.

google map info window data display

I have error about for info window data. I can't get the Please help me to check my code.
function initialize() {
map = new google.maps.Map(document.getElementById(map), {
center: new google.maps.LatLng(1.352083, 103.819836),
zoom: 12,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
//var infowindow;
if (markers) {
for (var level in markers) {
for (var i = 0; i < markers[level].length; i++) {
var details = markers[level][i];
//var infowindow;
markers[level][i] = new google.maps.Marker({
title: details.name,
position: new google.maps.LatLng(
details.location[0], details.location[1]),
clickable: true,
draggable: false,
icon: details.icon
});
var infowindow = new google.maps.InfoWindow({
content: details.description,
//content : markers[level][i].description,
position: new google.maps.LatLng(details.location[0], details.location[1])
//position: markers[level][i].position
});
google.maps.event.addListener(markers[level][i], 'click', function() {
infowindow.setPosition(this.position);
alert(this.position);
//infowindow.setContent(markers[level][i].description);
infowindow.open(map,markers[level][i]);
});
}
}
}
I can't get the description data. Please help me to check my code.