Reputation: 3
How come my pushpin location is constantly appearing down and right to where I'm actually clicking?
I have my context menu appearing at the correct location but the tryPixelToLocation is giving me a point down and right to where I'm actually clickin. Not sure why.
Please advise. Thanks.
For project requirements I can't use the window.Microsoft.Maps.addHandler. I have to do my actions through the context menu
import React, { useState, useEffect, useRef } from 'react';
const BingMap = ({ bingMapsKey }) => {
const mapRef = useRef(null);
const [menuPosition, setMenuPosition] = useState({ x: '0px', y: '0px' });
const [showMenu, setShowMenu] = useState(false);
const [map, setMap] = useState(null); // State to hold the map object
useEffect(() => {
const script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.defer = true;
script.src = `https://www.bing.com/api/maps/mapcontrol?callback=loadMapScenario&key=${bingMapsKey}`;
document.body.appendChild(script);
window.loadMapScenario = () => {
const newMap = new window.Microsoft.Maps.Map(mapRef.current, {
center: new window.Microsoft.Maps.Location(47.6062, -122.3321),
zoom: 10
});
mapRef.current.addEventListener('contextmenu', handleContextMenu);
setMap(newMap); // Set the map object in state
return () => {
mapRef.current.removeEventListener('contextmenu', handleContextMenu);
};
};
return () => {
if (script.parentNode) {
script.parentNode.removeChild(script);
}
};
}, [bingMapsKey]);
const handleContextMenu = (event) => {
event.preventDefault();
const mapContainer = mapRef.current.getBoundingClientRect();
setShowMenu(true);
setMenuPosition({
x: (event.clientX - mapContainer.left) + 'px',
y: (event.clientY - mapContainer.top) + 'px'
});
};
const handleMenuClick = (action, x, y) => {
if (!map) return;
switch (action) {
case 'add':
//Convert pixel coordinates to map location
const clickLocation = map.tryPixelToLocation(new window.Microsoft.Maps.Point(
parseInt(x ),
parseInt(y)
));
let pinTitle = prompt("Enter a title for the pin:", "New Location");
let pinDescription = prompt("Enter a description for the pin:", "");
if (pinTitle !== null) {
const pin = new window.Microsoft.Maps.Pushpin(clickLocation, {
title: pinTitle,
subTitle: pinDescription
});
pin.metadata = {
title: pinTitle,
description: pinDescription
};
map.entities.push(pin);
}
break;
case 'edit':
console.log('EDIT');
// Handle edit pin action
break;
case 'remove':
console.log('REMOVE');
// Handle remove pin action
break;
default:
break;
}
setShowMenu(false);
};
return (
<div style={{ position: 'relative' }}>
<div ref={mapRef} style={{ width: '100vw', height: '100vh' }}></div>
{showMenu && (
<div
style={{
position: 'absolute',
left: menuPosition.x,
top: menuPosition.y,
background: 'white',
border: '1px solid black',
padding: '5px',
zIndex: 1000
}}
>
<button onClick={() => handleMenuClick('add', menuPosition.x, menuPosition.y)}>Add Pin</button>
<button onClick={() => handleMenuClick('edit', menuPosition.x, menuPosition.y)}>Edit Pin</button>
<button onClick={() => handleMenuClick('remove', menuPosition.x, menuPosition.y)}>Remove Pin</button>
</div>
)}
</div>
);
};
export default BingMap;
Upvotes: 0
Views: 61
Reputation: 17954
Looking at your code I suspect the issue is that when you are using map.tryPixelToLocation
you are not specifying the PixelReference
type, so it is defaulting to viewport
which positions pixels relative to the center of the map. Looking at your code, it appears you are calculating the pixel position relative to the top left corner of the map div element, so you would want the pixel reference to be control
. For example:
const clickLocation = map.tryPixelToLocation(new window.Microsoft.Maps.Point(
parseInt(x),
parseInt(y)
), Microsoft.Maps.PixelReference.control);
That said, since your initial input is mouse coordinates relative to the top left corner of the page, you could skip the calculation that calculates the relative position of the map control and set the pixel reference to page
. For example:
const clickLocation = map.tryPixelToLocation(new window.Microsoft.Maps.Point(
menuPosition.x,
menuPosition.y
), Microsoft.Maps.PixelReference.page);
Here are some related docs:
As for why the default pixel reference is based on the center of the map, I once was curious about this as well as having it relative to the top left corner of the map made more sense initially to me. The reality is that it is possible to get pixels that are no on the map when using the top left corner as a reference point. The map control allows you to go far north/south such that the center of the map goes to the max/south values, it this situation, half of the displayed map is blank and not actually part of the map surface. Similarly, if you disable the repeating globe effect (ability to pan infinitely left/right), you can see a similar scenario with min/max longitude. As such, a relative position based on the center of the map is a better solution for these edge cases, and the map control itself heavily uses the pixel/location conversion methods, so it made sense to default to this reference type.
Upvotes: 1