Created
December 21, 2019 06:29
-
-
Save RikdeBoer/d588500bf7b5a8f02eba5f5db61f525c to your computer and use it in GitHub Desktop.
Leaflet marker rotated, with indicator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<title>Leaflet - Rotated marker with inidicator</title> | |
<meta charset="utf-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<link href="https://unpkg.com/[email protected]/dist/leaflet.css" rel="stylesheet" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/> | |
<script src="https://unpkg.com/[email protected]/dist/leaflet.js" integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" crossorigin=""></script> | |
<style> | |
.mymarker svg path { fill: dodgerblue; } | |
.mymarker { | |
transition: transform 0.5s linear; | |
} | |
.indicator { | |
background-color: white; | |
border: 1px solid dodgerblue; | |
border-radius: 6px; | |
color: dodgerblue; | |
font-size: 14px; | |
font-weight: 600; | |
padding: 2px 4px; | |
position: relative; | |
bottom: 35px; | |
left: 20px; | |
white-space: nowrap; | |
transition: transform 0.5s linear; | |
} | |
.leaflet-popup { | |
margin-bottom: 47px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="map-placeholder" style="height:400px"></div> | |
<script> | |
(function() { | |
// Save original method before overwriting it below. | |
const _setPosOriginal = L.Marker.prototype._setPos | |
L.Marker.addInitHook(function() { | |
const anchor = this.options.icon.options.iconAnchor | |
this.options.rotationOrigin = anchor ? `${anchor[0]}px ${anchor[1]}px` : 'center center' | |
// Ensure marker remains rotated during dragging. | |
this.on('drag', data => { this._rotate() }) | |
}) | |
L.Marker.include({ | |
// _setPos is alled when update() is called, e.g. on setLatLng() | |
_setPos: function(pos) { | |
_setPosOriginal.call(this, pos) | |
if (this.options.rotation) this._rotate() | |
}, | |
_rotate: function() { | |
this._icon.style[`${L.DomUtil.TRANSFORM}Origin`] = this.options.rotationOrigin | |
this._icon.style[L.DomUtil.TRANSFORM] += ` rotate(${this.options.rotation}deg)` | |
} | |
}) | |
})() | |
Math.radians = (degrees) => degrees * Math.PI / 180 | |
function calcHeading(point1, point2) { | |
const pnt1lat = Math.radians(point1.lat) | |
const pnt2lat = Math.radians(point2.lat) | |
const lngDiff = Math.radians(point2.lng - point1.lng) | |
const y = Math.sin(lngDiff) * Math.cos(pnt2lat) | |
const x = Math.cos(pnt1lat) * Math.sin(pnt2lat) - Math.sin(pnt1lat) * Math.cos(pnt2lat) * Math.cos(lngDiff) | |
let heading = Math.atan2(y, x) * 180.0 / Math.PI | |
// Convert to compass heading, 0..360, rather than -180..+180 | |
if (heading < 0) heading += 360 | |
return heading; | |
} | |
function markerOptions(size, heading) { | |
const iconOptions = { | |
iconSize : [size, size], | |
iconAnchor: [size/2, size/2], | |
className : 'mymarker', | |
html : '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M 16 3 C 8.832031 3 3 8.832031 3 16 C 3 23.167969 8.832031 29 16 29 C 23.167969 29 29 23.167969 29 16 C 29 8.832031 23.167969 3 16 3 Z M 16 5 C 22.085938 5 27 9.914063 27 16 C 27 22.085938 22.085938 27 16 27 C 9.914063 27 5 22.085938 5 16 C 5 9.914063 9.914063 5 16 5 Z M 16 8.875 L 9.59375 15.28125 L 11 16.71875 L 15 12.71875 L 15 23 L 17 23 L 17 12.71875 L 21 16.71875 L 22.40625 15.28125 Z"/></svg>' | |
} | |
return { | |
draggable: true, | |
icon: L.divIcon(iconOptions), | |
rotation: heading | |
} | |
} | |
const center = [-37.8179, 144.936] | |
const heading = 253; | |
const myMap = L.map('map-placeholder').setView(center, 16) | |
const myMarker = L.marker(center, markerOptions(50, heading)).addTo(myMap) | |
myMarker | |
.bindPopup('Click on the map<br/>to point me there.<br/><br/>You can drag me too.') | |
.openPopup() | |
myMap.addLayer(L.tileLayer( | |
'https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}@2x.png', | |
{ attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contr.' } | |
)) | |
function updateIndicatorPos(marker, heading) { | |
const pos = marker._icon._leaflet_pos | |
const indicator = marker._icon.nextElementSibling | |
if (heading) indicator.innerHTML = `🧭 ${heading}°` | |
indicator.style.transform = `translate3d(${pos.x}px, ${pos.y}px, 0)` | |
} | |
myMap.whenReady( _ => { | |
L.DomUtil.create('div', 'indicator', myMarker._icon.parentNode) | |
updateIndicatorPos(myMarker, heading) | |
}) | |
myMarker.on('move', data => { updateIndicatorPos(myMarker) }) | |
myMap.on('zoom', data => { updateIndicatorPos(myMarker) }) | |
myMap.on('click', data => { | |
myMarker.options.rotation = Math.round(calcHeading(myMarker.getLatLng(), data.latlng)) | |
myMarker.update() | |
updateIndicatorPos(myMarker, myMarker.options.rotation) | |
}) | |
</script> | |
</body> | |
</html> |
Author
RikdeBoer
commented
Mar 24, 2022
via email
Hallo Hans Erik,
Misschien in _setPos, regel 50:
_setPos: function(pos) {
// Inform external code here
}
Deze function wordt aangeroepen iedere keer dat de marker van plaats of rotatie verandert.
Groeten,
Rik
… On 25 Mar 2022, at 6:57 am, Hans Erik Hazelhorst ***@***.***> wrote:
@hehazelhorst commented on this gist.
Hi,
Very nice code that precisely solves my problem. I have question. I need to add a callback function that passes the heading (rotation) and LatLng to an external program. Where would I insert the code for this?
—
Reply to this email directly, view it on GitHub <https://gist.github.com/d588500bf7b5a8f02eba5f5db61f525c#gistcomment-4109470>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AA6YF6NDPLJ6ZDNBRUJ7E6LVBTCK5ANCNFSM5RSFC57A>.
You are receiving this because you authored the thread.
Dank!
Ja, ik had al zoiets bedacht.
Ga het proberen.
vrgr
Hans Erik
… On 24 Mar 2022, at 22:12, Rik de Boer ***@***.***> wrote:
@RikdeBoer commented on this gist.
Hallo Hans Erik,
Misschien in _setPos, regel 50:
_setPos: function(pos) {
// Inform external code here
}
Deze function wordt aangeroepen iedere keer dat de marker van plaats of rotatie verandert.
Groeten,
Rik
> On 25 Mar 2022, at 6:57 am, Hans Erik Hazelhorst ***@***.***> wrote:
>
> @hehazelhorst commented on this gist.
> Hi,
> Very nice code that precisely solves my problem. I have question. I need to add a callback function that passes the heading (rotation) and LatLng to an external program. Where would I insert the code for this?
>
> —
> Reply to this email directly, view it on GitHub <https://gist.github.com/d588500bf7b5a8f02eba5f5db61f525c#gistcomment-4109470>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AA6YF6NDPLJ6ZDNBRUJ7E6LVBTCK5ANCNFSM5RSFC57A>.
> You are receiving this because you authored the thread.
>
—
Reply to this email directly, view it on GitHub <https://gist.github.com/d588500bf7b5a8f02eba5f5db61f525c#gistcomment-4109529>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AQFXZZUVFYLXPFIOSCS6OFLVBTLFVANCNFSM5RSFC57A>.
You are receiving this because you were mentioned.
Hallo Rik,
Ik had in maart een vraag via github over een functie in een stukje Javascript dat jij in elkaar gezet had, het ging over het weergeven van SVG markers met Leaflet op een Open Street Map.
Probeer een beetje wegwijs te worden in het gebruik van SVG markers (ik weet wel veel van SVG maar niet de integratie in Leaflet). Maar nu loop ik tegen het volgende aan:
- ik wil meerdere SVG markers displayen op 1 kaart
- dat gaat prima met de code in bijgevoegde file (‘almere.html’), er staan 2 markers in.
Ik lees dus de verschillende markers in uit een array. Het 4e element van de array geeft dan de rotatie in graden aan, en het is de bedoeling dat elke marker de rotatie krijgt uit de array. Maar ik doe ergens iets fout. Misschien moet ik een SVG transformatie toevoegen, maar waar en hoe? Via GoogleMaps had ik het wel werkend, maar dit werkt net wat anders.
Enig idee?
met vriendelijke groet,
Hans Erik Hazelhorst
fit-in solutions
Karel Doormanlaan 24 | 3572 NC Utrecht
Claris Partner
FileMaker Pro 15, 14 en 13 Certified Developer
onderdeel van fmReconnect
m: +31628157200 | e: ***@***.*** | w: filemakerontwikkeling.nl
kvk 30141828 | IBAN NL18ASNB8821099067
Hoi Hans
Ik ben op dit moment op vakantie in Tasmania (en zonder laptop).
Ik heb misschien later in de week tijd.
Groeten
Rik
…On Fri, 20 May 2022, 12:48 am Hans Erik Hazelhorst, < ***@***.***> wrote:
***@***.**** commented on this gist.
------------------------------
Hallo Rik,
Ik had in maart een vraag via github over een functie in een stukje
Javascript dat jij in elkaar gezet had, het ging over het weergeven van SVG
markers met Leaflet op een Open Street Map.
Probeer een beetje wegwijs te worden in het gebruik van SVG markers (ik
weet wel veel van SVG maar niet de integratie in Leaflet). Maar nu loop ik
tegen het volgende aan:
- ik wil meerdere SVG markers displayen op 1 kaart
- dat gaat prima met de code in bijgevoegde file (‘almere.html’), er staan
2 markers in.
Ik lees dus de verschillende markers in uit een array. Het 4e element van
de array geeft dan de rotatie in graden aan, en het is de bedoeling dat
elke marker de rotatie krijgt uit de array. Maar ik doe ergens iets fout.
Misschien moet ik een SVG transformatie toevoegen, maar waar en hoe? Via
GoogleMaps had ik het wel werkend, maar dit werkt net wat anders.
Enig idee?
met vriendelijke groet,
Hans Erik Hazelhorst
fit-in solutions
Karel Doormanlaan 24 | 3572 NC Utrecht
Claris Partner
FileMaker Pro 15, 14 en 13 Certified Developer
onderdeel van fmReconnect
m: +31628157200 | e: ***@***.*** | w: filemakerontwikkeling.nl
kvk 30141828 | IBAN NL18ASNB8821099067
—
Reply to this email directly, view it on GitHub
<https://gist.github.com/d588500bf7b5a8f02eba5f5db61f525c#gistcomment-4172308>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AA6YF6NQSNI6DBTH3GNDZQ3VKZICRANCNFSM5RSFC57A>
.
You are receiving this because you were mentioned.Message ID:
<RikdeBoer/4b-Leaflet-marker-rotated-with-indicator.html/comments/4172308@
github.com>
Hi Rik,
The code you have for rotation and SVG markers is great and really helped me.
I did however find problems with the indicator when there is more than 1 marker. It seems the first marker will have the indicator set correctly but then the others seem to be out of position. What is odd is that the results of the transform on the indicators match the markers but they are not in the right position.
Attached are some screenshots to illustrate.
Hi Nathan,
Glad to hear my code got you started at least. Thanks for sharing!
I'm not much involved with this project any more, so I can't tell you off the top of my head what might be going wrong when there's multiple markers.
I'm sure you'll work it out. You're so close!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment