class mglStreetViewControl {
/**
*
* @param {NewType} options
*/
constructor(options) {
this._mapillaryAlias =
!options || !options.mapillaryAlias ? "Mapillary" : options.mapillaryAlias;
this._mapillaryLayerOptions =
!options || !options.mapillaryLayerOptions
? {
userKey: "WpzhyQeWLPnZ_TwvxcdU_w",
pano: 1,
}
: options.mapillaryLayerOptions;
}
onAdd(map) {
const _mapillaryAlias = this._mapillaryAlias;
//TODO does this need to exist or can we just use map
const _map = (this._map = map);
//button element
this._btn = document.createElement("button");
this._btn.innerHTML = streetViewIcon();
this._btn.type = "button";
this._btn["aria-label"] = "Open Streetview";
this._btn["title"] = "Open Streetview";
this._btn.id = "mglStreetViewControl";
//spectre css only
//TODO add option to put this on right if control is set to the right
this._btn.classList = "tooltip tooltip-left";
this._btn.dataset.tooltip = "Open Streetview";
//add mapillary points and lines
const _mapillaryLayers = mapillaryLayers(this._mapillaryLayerOptions);
// _mapillaryLayers.map((l) => {
// _map.addLayer(l);
// });
const _mapMinZoom = this._map.getMinZoom();
//add global marker
const _marker = new mapboxgl.Marker({
draggable: true,
});
this._btn.onclick = function () {
//if layers are already showing, reset and return
// if (_map.getLayoutProperty(_mapillaryLayers[0].id, "visibility") === "visible") {
// reset(_marker);
// return;
// }
//set latlng and show marker
_marker.setLngLat(map.getCenter()).addTo(map).on("dragend", onDragEnd);
//map set min zoom to 14 and set zoom to 14 is below 14
_map.setMinZoom(14);
if (_map.getZoom() < 14) _map.setZoom(14);
//show mapillary imagery points and lines
// _mapillaryLayers.forEach((l) => {
// _map.setLayoutProperty(l.id, "visibility", "visible");
// });
//show toast, spectre css only
if (!document.getElementById("streetviewControlToast")) {
const toast = document.createElement("div");
toast.id = "streetviewControlToast";
toast.classList.add("toast");
toast.style.backgroundColor = "firebrick";
toast.style.position = "absolute";
toast.style.bottom = 0;
toast.style.width = "100%";
toast.style.padding = "1rem 0";
toast.style.textAlign = "center";
toast.style.color = "white";
toast.innerText =
"Drag the marker to a location on the street. The selected street view option will open in a new window.";
document.body.appendChild(toast);
} else {
document.getElementById("streetviewControlToast").style.display = "block";
}
setTimeout(function () {
document.getElementById("streetviewControlToast").style.display = "none";
}, 2600);
//listener for 'dragend' event
async function onDragEnd() {
//show loading
showLoading();
//get latlng
const lngLat = this.getLngLat();
const lng = Number(lngLat.lng.toFixed(8));
const lat = Number(lngLat.lat.toFixed(8));
//see if mapillary imags are available
const bboxClickTargetSize = 40;
const point = _map.project(lngLat);
const bbox = [
[point.x - bboxClickTargetSize / 2, point.y - bboxClickTargetSize / 2],
[point.x + bboxClickTargetSize / 2, point.y + bboxClickTargetSize / 2],
];
// const mapillaryLayerIds = _mapillaryLayers.reduce((i, l) => [...i, l.id], []);
// const mapillaryImages = _map.queryRenderedFeatures(bbox, { layers: mapillaryLayerIds });
const mapillaryExists = false; //!mapillaryImages.length ? false : true;
const urls = [
"https://www.google.com/maps/@?api=1&map_action=pano&heading=0&pitch=0&viewpoint="
.concat(lngLat.lat, ",")
.concat(lngLat.lng),
];
console.log(urls[0]);
if (mapillaryExists) {
urls.push(
"https://www.mapillary.com/app/?z=16&lat=" +
lat +
"&lng=" +
lng +
"&focus=photo&panos=true&pKey=" +
mapillaryImages[0].properties.key
);
}
const imgSource =
urls.length < 2
? 0
: confirm(
_mapillaryAlias +
" Street View Imagery is avalable at this location.\n\nClick 'OK' to use " +
_mapillaryAlias +
"Street View Imagery\n--OR--\n'Cancel' to use Google Street View Imagery"
)
? 1
: 0;
window.open(urls[imgSource], "_blank");
reset(this);
}
function reset(marker) {
//TODO fix this hack of getting rid of the event listeners
//remove marker and listener
marker._listeners = [];
marker.off("dragend", onDragEnd);
marker.remove();
//reset map minzoom
_map.setMinZoom(_mapMinZoom);
//hide mapillary points and lines
// _mapillaryLayers.forEach((l) => {
// _map.setLayoutProperty(l.id, "visibility", "none");
// });
//hide toast message
if (document.querySelector("#streetviewControlToast")) {
document.getElementById("streetviewControlToast").style.display = "none";
}
//hide loading
hideLoading();
}
};
this._container = document.createElement("div");
this._container.className = "mapboxgl-ctrl mapboxgl-ctrl-group";
this._container.appendChild(this._btn);
return this._container;
}
onRemove() {
this._container.parentNode.removeChild(this._container);
this._map = undefined;
}
}
export { mglStreetViewControl };
function showLoading() {
if (document.querySelector("#loading")) {
document.querySelector("#loading").classList.add("loading");
}
}
function hideLoading() {
if (document.querySelector("#loading")) {
document.querySelector("#loading").classList.remove("loading");
}
}
/**
* these options are supplied in the global config object of the plugin
* @param {*} options abject with a mapillary userKey and panamoramic boolean option 1 or 0
*/
function mapillaryLayers(options) {
const { userKey, pano } = options;
return JSON.parse(`[{
"id": "svcMapillaryLinesOuter",
"type": "line",
"source": {
"type": "vector",
"tiles": [
"https://tiles3.mapillary.com/v0.1/{z}/{x}/{y}.mvt"
],
"minzoom": 0,
"maxzoom": 14,
"promoteId": "key"
},
"source-layer": "mapillary-sequences",
"paint": {
"line-opacity": 0.9,
"line-color": "white",
"line-gap-width": 3,
"line-width": 2
},
"layout": {
"visibility": "none",
"line-cap": "round",
"line-join": "round"
},
"filter": [
"all",
${
!userKey
? ""
: `[
"==",
[
"get",
"userkey"
],
"${userKey}"
],`
}
[
"==",
[
"get",
"pano"
],
${pano}
]
]
},
{
"id": "svcMapillaryLinesInner",
"type": "line",
"source": {
"type": "vector",
"tiles": [
"https://tiles3.mapillary.com/v0.1/{z}/{x}/{y}.mvt"
],
"minzoom": 0,
"maxzoom": 14,
"promoteId": "key"
},
"source-layer": "mapillary-sequences",
"paint": {
"line-opacity": 0.6,
"line-color": "#05CB63",
"line-width": 3
},
"layout": {
"visibility": "none",
"line-cap": "round",
"line-join": "round"
},
"filter": [
"all",
${
!userKey
? ""
: `[
"==",
[
"get",
"userkey"
],
"${userKey}"
],`
}
[
"==",
[
"get",
"pano"
],
${pano}
]
]
},
{
"id": "svcMapillaryPoints",
"type": "circle",
"source": {
"type": "vector",
"tiles": [
"https://tiles3.mapillary.com/v0.1/{z}/{x}/{y}.mvt"
],
"minzoom": 0,
"maxzoom": 14,
"promoteId": "key"
},
"source-layer": "mapillary-images",
"paint": {
"circle-color": "#05CB63",
"circle-stroke-color": "white",
"circle-stroke-width": 1,
"circle-pitch-scale": "map",
"circle-pitch-alignment": "map"
},
"layout": {
"visibility": "none"
},
"filter": [
"all",
${
!userKey
? ""
: `[
"==",
[
"get",
"userkey"
],
"${userKey}"
],`
}
[
"==",
[
"get",
"pano"
],
${pano}
]
]
}]`);
}
//see https://material.io/resources/icons/?icon=person_pin_circle&style=baseline
/**
* returns a material design street view svg icon
*/
function streetViewIcon() {
return '<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"viewBox="0 0 24 24"><g><rect fill="none" height="24" width="24"/></g><g><g><g><path d="M12,2C8.14,2,5,5.14,5,9c0,5.25,7,13,7,13s7-7.75,7-13C19,5.14,15.86,2,12,2z M12,4c1.1,0,2,0.9,2,2c0,1.11-0.9,2-2,2 s-2-0.89-2-2C10,4.9,10.9,4,12,4z M12,14c-1.67,0-3.14-0.85-4-2.15c0.02-1.32,2.67-2.05,4-2.05s3.98,0.73,4,2.05 C15.14,13.15,13.67,14,12,14z"/></g></g></g></svg>';
}
/**
* Use this to show the bounding box for debug purposes
* @param {*} map instance of Mapbox map object
* @param {*} bbox bounding box
*/
function showBoundingBox(map, bbox) {
var bboxCoords = [map.unproject(bbox[0]), map.unproject(bbox[1])];
var poly = [
[bboxCoords[0].lng, bboxCoords[0].lat],
[bboxCoords[1].lng, bboxCoords[0].lat],
[bboxCoords[1].lng, bboxCoords[1].lat],
[bboxCoords[0].lng, bboxCoords[1].lat],
[bboxCoords[0].lng, bboxCoords[0].lat],
];
var number = Math.random();
map.addLayer({
id: "bbox" + number,
type: "fill",
source: {
type: "geojson",
data: {
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [poly],
},
},
},
layout: {},
paint: {
"fill-color": "firebrick",
"fill-opacity": 0.5,
},
});
}