-
-
Save tordans/339312be319c977a4485a6f56c9800bc to your computer and use it in GitHub Desktop.
Sync viewer and map markers
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> | |
<head> | |
<meta charset='utf-8' /> | |
<title></title> | |
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' /> | |
<link rel='stylesheet' href='https://unpkg.com/[email protected]/dist/mapillary.min.css' /> | |
<link href='https://unpkg.com/[email protected]/dist/leaflet.css' rel='stylesheet' /> | |
<script src='https://unpkg.com/[email protected]/dist/mapillary.min.js'></script> | |
<script src='https://unpkg.com/[email protected]/dist/leaflet.js'></script> | |
<style> | |
html, body { margin:0; padding:0; height: 100%; } | |
#mly { position: absolute; width: 60%; height: 100%; } | |
#map { position: absolute; width: 40%; height: 100%; right: 0; } | |
</style> | |
</head> | |
<body> | |
<div class="form"> | |
<form> | |
<label> | |
Image key: | |
<input name="image_key" value="" placeholder="image key" type="text"> | |
</label> | |
<input type="submit" value="show this image"> | |
</form> | |
</div> | |
<div class="error" style="color: red; font-size: 200%"></div> | |
<div id='mly'></div> | |
<div id='map'></div> | |
<script> | |
// https://stackoverflow.com/a/5448595 | |
function findGetParameter(parameterName) { | |
var result = null, | |
tmp = []; | |
location.search | |
.substr(1) | |
.split("&") | |
.forEach(function (item) { | |
tmp = item.split("="); | |
if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]); | |
}); | |
return result; | |
} | |
// Get image key from url or warn add tempory key | |
var image_key = findGetParameter('image_key'); | |
if(image_key == null) { | |
document.querySelectorAll('.error')[0].textContent = 'Use the image key form or add ?image_key=jYNjmv7P567FSw92Z1_DEw to the url.'; | |
image_key = 'jYNjmv7P567FSw92Z1_DEw'; | |
} | |
// Setup map | |
var map = L.map('map').setView([56.04351888068181, 12.695600612967427], 18); | |
var osmUrl='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; | |
var osmAttrib='Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors'; | |
var osm = new L.TileLayer(osmUrl, { maxZoom: 19, attribution: osmAttrib}); | |
map.addLayer(osm); | |
map.keyboard.disable(); | |
// Setup viewer | |
var mly = new Mapillary.Viewer( | |
'mly', | |
'QjI1NnU0aG5FZFZISE56U3R5aWN4Zzo5ZDMwMzY2ZjBhMzdmYWVi', | |
null, | |
{ | |
component: { | |
marker: { | |
visibleBBoxSize: 100, | |
}, | |
mouse: { | |
doubleClickZoom: false, | |
}, | |
}, | |
}); | |
mly.moveToKey(image_key).then( | |
() => { /* noop */ }, | |
(e) => { console.error(e); }); | |
// Show original latLon and latLon (if computed exist it will differ) of current | |
// viewer node on map. Show line linking the two points together | |
const mapNodePosition = { | |
line: L.polyline([[0, 0], [0, 0]], {color: '#0ff', weight: 1}), | |
originalPos: L.circleMarker([0, 0], { radius: 7, color: '#0ff' }), | |
pos: L.circleMarker([0, 0], { radius: 7, color: '#00f' }), | |
}; | |
mly.on(Mapillary.Viewer.nodechanged, (node) => { | |
const latLon = [node.latLon.lat, node.latLon.lon]; | |
const originalLatLon = [node.originalLatLon.lat, node.originalLatLon.lon]; | |
mapNodePosition.line.setLatLngs([originalLatLon, latLon]); | |
mapNodePosition.originalPos.setLatLng(originalLatLon); | |
mapNodePosition.pos.setLatLng(latLon); | |
map.setView(latLon); | |
if (!map.hasLayer(mapNodePosition.line)) { | |
mapNodePosition.line.addTo(map); | |
mapNodePosition.originalPos.addTo(map); | |
mapNodePosition.pos.addTo(map); | |
} | |
}); | |
// Get marker component | |
const markerComponent = mly.getComponent('marker'); | |
// Show a flat circle marker in the viewer when hovering the map | |
let mapHoverViewerMarker; | |
const removeMapHoverViewerMarker = () => { | |
if (!!mapHoverViewerMarker && markerComponent.has(mapHoverViewerMarker.id)) { | |
markerComponent.remove([mapHoverViewerMarker.id]); | |
mapHoverViewerMarker = null; | |
} | |
} | |
const onMapMouseEvent = (e) => { | |
mapHoverViewerMarker = new Mapillary.MarkerComponent.CircleMarker( | |
'map-hover-viewer-marker-id', | |
{ lat: e.latlng.lat, lon: e.latlng.lng }, | |
{ color: '#0f0' }); | |
markerComponent.add([mapHoverViewerMarker]); | |
} | |
map.on('mousemove', onMapMouseEvent); | |
map.on('mouseover', onMapMouseEvent); | |
map.on('mouseout', removeMapHoverViewerMarker); | |
// Show a flat circle marker in the viewer and a corresponding map marker when hovering the viewer | |
const indicator = { | |
id: "indicator-id", | |
mapLine: L.polyline([[0, 0], [0, 0]], { color: '#0f0', weight: 1, id: "indicator-id-line" }), | |
mapMarker: L.circleMarker([0, 0], { radius: 5, color: '#0f0', id: "indicator-id-circle" }), | |
viewerMarker: null, | |
state: { | |
dragging: false, | |
lastPos: null, | |
moving: false, | |
}, | |
}; | |
const addMapIndicator = () => { | |
if (!map.hasLayer(indicator.mapLine)) { | |
indicator.mapLine.addTo(map); | |
} | |
if (!map.hasLayer(indicator.mapMarker)) { | |
indicator.mapMarker.addTo(map); | |
} | |
} | |
const removeMapIndicator = () => { | |
if (map.hasLayer(indicator.mapLine)) { | |
map.removeLayer(indicator.mapLine); | |
} | |
if (map.hasLayer(indicator.mapMarker)) { | |
map.removeLayer(indicator.mapMarker); | |
} | |
} | |
const removeViewerIndicator = () => { | |
if (!!indicator.viewerMarker && markerComponent.has(indicator.viewerMarker.id)) { | |
markerComponent.remove([indicator.viewerMarker.id]); | |
indicator.viewerMarker = null; | |
} | |
} | |
const setViewerIndicatorMarker = (latLon) => { | |
const viewerMarker = new Mapillary.MarkerComponent.CircleMarker( | |
indicator.id, | |
latLon, | |
{ color: '#0f0' }); | |
markerComponent.add([viewerMarker]); | |
indicator.viewerMarker = viewerMarker; | |
} | |
const moveIndicatorMarker = (latLon) => { | |
if (indicator.state.dragging) { return; } | |
if (latLon == null) { | |
removeMapIndicator(); | |
removeViewerIndicator(); | |
return; | |
} | |
const posLatLng = mapNodePosition.pos.getLatLng(); | |
const lineString = [ | |
[posLatLng.lat, posLatLng.lng], | |
[latLon.lat, latLon.lon], | |
[ | |
posLatLng.lat + 5 * (latLon.lat - posLatLng.lat), | |
posLatLng.lng + 5 * (latLon.lon - posLatLng.lng), | |
], | |
]; | |
indicator.mapLine.setLatLngs(lineString); | |
indicator.mapMarker.setLatLng([latLon.lat, latLon.lon]); | |
setViewerIndicatorMarker({ lat: latLon.lat, lon: latLon.lon }); | |
addMapIndicator(); | |
} | |
const onViewerMouseEvent = (event) => { | |
indicator.state.lastPos = event.pixelPoint; | |
moveIndicatorMarker(event.latLon); | |
} | |
mly.on(Mapillary.Viewer.mouseup, onViewerMouseEvent); | |
mly.on(Mapillary.Viewer.mouseover, onViewerMouseEvent); | |
mly.on(Mapillary.Viewer.mousedown, onViewerMouseEvent); | |
mly.on(Mapillary.Viewer.mousemove, (event) => { | |
// Store last mouse position for later unprojection | |
indicator.state.lastPos = event.pixelPoint; | |
if (indicator.state.moving || indicator.state.dragging) { return; } | |
moveIndicatorMarker(event.latLon); | |
}); | |
mly.on(Mapillary.Viewer.mouseout, (event) => { | |
indicator.state.lastPos = null; | |
removeViewerIndicator(); | |
removeMapIndicator(); | |
}); | |
mly.on(Mapillary.Viewer.movestart, (event) => { indicator.state.moving = true; }); | |
mly.on(Mapillary.Viewer.moveend, (event) => { | |
indicator.state.moving = false; | |
if (!indicator.state.lastPos) { return; } | |
// Unproject the last position and move indicator marker if latLon exist | |
mly.unproject(indicator.state.lastPos).then(moveIndicatorMarker); | |
}); | |
markerComponent.on(Mapillary.MarkerComponent.MarkerComponent.dragstart, () => { | |
// Remove indicators when dragging marker in the viewer | |
indicator.state.dragging = true; | |
removeViewerIndicator(); | |
removeMapIndicator(); | |
}); | |
markerComponent.on(Mapillary.MarkerComponent.MarkerComponent.dragend, () => { | |
indicator.state.dragging = false; | |
if (!indicator.state.lastPos) { return; } | |
// Unproject the last position and move indicator marker if latLon exist | |
mly.unproject(indicator.state.lastPos).then(moveIndicatorMarker); | |
}); | |
// Create markers on click in map or viewer | |
let addedMarkerId = 0; | |
const mapMarkers = {}; | |
const addOrReplaceViewerMarker = (id, latLon) => { | |
// Create an interactive marker to be able to drag it in viewer | |
// and retrieve it with getMarkerIdAt method | |
const marker = new Mapillary.MarkerComponent.SimpleMarker( | |
id, | |
latLon, | |
{ interactive: true }); | |
markerComponent.add([marker]); | |
} | |
const handleMapMarkerDrag = (mapMarker) => { | |
// Listen to map events and act to move map and viewer markers accordingly | |
mapMarker.on({ | |
mousedown: (event) => { | |
const onMouseMove = (e) => { | |
// Update both viewer marker and map marker on map marker drag | |
addOrReplaceViewerMarker(mapMarker.options.id, { lat: e.latlng.lat, lon: e.latlng.lng }); | |
mapMarker.setLatLng(e.latlng); | |
}; | |
const onMouseUp = (e) => { | |
map.off('mousemove', onMouseMove) | |
map.off('mouseup', onMouseUp); | |
} | |
map.on('mousemove', onMouseMove); | |
map.on('mouseup', onMouseUp); | |
}, | |
mouseover: (event) => { | |
// Remove map hover viewer marker when hovering a map marker | |
removeMapHoverViewerMarker(); | |
// Disable map dragging to ensure that only map marker is dragged | |
map.dragging.disable(); | |
map.off('mousemove', onMapMouseEvent); | |
map.off('click', mapOnClick); | |
}, | |
mouseout: (event) => { | |
map.dragging.enable(); | |
map.on('mousemove', onMapMouseEvent); | |
map.on('click', mapOnClick); | |
}, | |
}); | |
} | |
const createMarker = (latLon) => { | |
const id = (addedMarkerId++).toString(); | |
addOrReplaceViewerMarker(id, latLon); | |
const mapMarker = | |
L.circleMarker( | |
[latLon.lat, latLon.lon], | |
{ radius: 5, color: '#f00', draggable: 'true', id: id }) | |
.addTo(map); | |
mapMarkers[id] = mapMarker; | |
handleMapMarkerDrag(mapMarker); | |
} | |
mly.on(Mapillary.Viewer.click, (e) => { | |
if (!e.latLon) { return; } | |
markerComponent.getMarkerIdAt(e.pixelPoint).then((markerId) => { | |
// Only create a new marker if no interactive markers are hovered | |
if (markerId != null) { return; } | |
createMarker(e.latLon); | |
}); | |
}); | |
const mapOnClick = (e) => { | |
if (!e.latlng) { return; } | |
createMarker({ lat: e.latlng.lat, lon: e.latlng.lng }); | |
}; | |
map.on('click', mapOnClick); | |
// Update map marker when latLon changes for a marker by dragging in the viewer | |
markerComponent.on(Mapillary.MarkerComponent.MarkerComponent.changed, (e) => { | |
const mapMarker = mapMarkers[e.marker.id]; | |
if (!mapMarker) { | |
return; | |
} | |
mapMarker.setLatLng([e.marker.latLon.lat, e.marker.latLon.lon]); | |
}); | |
// Trigger render on browser window resize | |
window.addEventListener("resize", function() { mly.resize(); }); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment