gsvviewer/index.js
2022-09-23 22:11:44 -04:00

254 lines
7.6 KiB
JavaScript

'use strict';
//
// VARIABLES
//
var canvas, canvas2, ctx, ctx2, zoom;
const maxCanvasHeight = 7000; //px
var downloadCount = 0;
//
// UTILITY FUNCTIONS
//
function ID(id) {
return document.getElementById(id);
}
function extractTextBetween(input, before, after) {
const step1 = input.substring(input.indexOf(before) + before.length, input.length);
const step2 = step1.substring(0, step1.indexOf(after));
return step2;
}
//
// INITIALIZATION
//
window.addEventListener("load", () => {
const urlBox = ID("downloadURL");
canvas = ID("canvas");
canvas2 = ID("canvas2");
ctx = canvas.getContext("2d");
ctx2 = canvas2.getContext("2d");
ID("loadButton").addEventListener("click", () => {
zoom = ID("zoom").value;
console.log("URL : ", urlBox.value);
parseURL(urlBox.value);
});
ID("downloadButton").addEventListener("click", () => {
downloadCanvas();
});
});
//
//
//
function downloadCanvas() {
ID("infoStatus").textContent = "saving image..";
if (canvas2.height > 0) {
const link1 = document.createElement('a');
link1.download = `top${downloadCount}.png`;
link1.href = canvas.toDataURL();
link1.click();
const link2 = document.createElement('a');
link2.download = `bottom${downloadCount}.png`;
link2.href = canvas2.toDataURL();
link2.click();
downloadCount++;
} else {
const link = document.createElement('a');
link.download = `image${downloadCount}.png`;
link.href = canvas.toDataURL();
link.click();
downloadCount++;
}
}
function resetInfoDisplay() {
const normal = "N/A";
ID("infoStatus").textContent = normal;
ID("infoType").textContent = normal;
ID("infoCopyright").textContent = normal;
ID("infoZooms").textContent = normal;
ID("infoID").textContent = normal;
}
function parseURL(url) {
resetInfoDisplay();
if (url.includes("panoid")) {
const id = extractTextBetween(url, "panoid%3D", "%");
console.log("Extracted PanoID using method 1: ", id);
getPath(id);
} else if (url.includes("m4!1s") && url.includes("data=")) {
const id = extractTextBetween(url, "m4!1s", "!2e");
if (id.length > 22) {
console.log("Extracted Photosphere ID using method 2: ", id);
getSphere(id);
} else {
console.log("Extracted PanoID using method 2: ", id);
getPath(id);
}
} else if (url.includes("googleusercontent.com")) {
const id = extractTextBetween(url, "googleusercontent.com%2Fp%2F", "%3");
console.log("Photosphere ID extracted: ", id);
getSphere(id);
} else {
ID("infoStatus").textContent = "Error: Could not understand link.";
}
}
//
// PATH OBTAINING LOGIC
//
function getPath(panoid) {
ID("infoStatus").textContent = "Getting data from server...";
ID("infoID").textContent = panoid;
ID("infoType").textContent = `Street View`;
var request = new XMLHttpRequest();
request.onload = function () {
ID("infoStatus").textContent = "Parsing data...";
// Metadata parsing witchcraft
const data = JSON.parse(this.responseText.substring(4))[1][0];
const tileSize = data[2][3][1][0];
const bestZoom = (data[2][3][0].length - 1);
if (bestZoom < zoom || zoom < 0) {
zoom = bestZoom;
document.getElementById("zoom").value = bestZoom;
}
const copyright = data[4][0][0][0][0];
ID("infoZooms").textContent = ` 0 to ${bestZoom}`;
ID("infoCopyright").textContent = copyright;
const widthPX = data[2][3][0][zoom][0][1];
const heightPX = data[2][3][0][zoom][0][0];
const width = Math.ceil(widthPX / tileSize);
const height = Math.ceil(heightPX / tileSize);
prepCanvas(widthPX, heightPX);
ID("infoStatus").textContent = "Downloading tiles";
const totalTiles = width * height;
var processedTiles = 0;
for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
requestImage(`https://streetviewpixels-pa.googleapis.com/v1/tile?cb_client=maps_sv.tactile&panoid=${panoid}&x=${x}&y=${y}&zoom=${zoom}&nbt=1&fover=0`, (image) => {
paintImage(image, x, y, heightPX, widthPX, tileSize, height);
processedTiles++;
if (processedTiles === totalTiles) {
ID("infoStatus").textContent = "finished";
}
});
}
}
};
request.open("get", `https://www.google.com/maps/photometa/v1?authuser=0&pb=!1m4!1smaps_sv.tactile!11m2!2m1!1b1!2m2!1sen!2sus!3m3!1m2!1e2!2s${panoid}!4m57!1e1!1e2!1e3!1e4!1e5!1e6!1e8!1e12!2m1!1e1!4m1!1i48!5m1!1e1!5m1!1e2!6m1!1e1!6m1!1e2!9m36!1m3!1e2!2b1!3e2!1m3!1e2!2b0!3e3!1m3!1e3!2b1!3e2!1m3!1e3!2b0!3e3!1m3!1e8!2b0!3e3!1m3!1e1!2b0!3e3!1m3!1e4!2b0!3e3!1m3!1e10!2b1!3e2!1m3!1e10!2b0!3e3`, true);
request.send();
}
//
// PHOTOSHPERE OBTAINING LOGIC
//
function getSphere(sphereID) {
ID("infoStatus").textContent = "Getting data from server...";
ID("infoID").textContent = sphereID;
ID("infoType").textContent = `Photo Sphere`;
var request = new XMLHttpRequest();
request.onload = function () {
ID("infoStatus").textContent = "Parsing data...";
// Metadata parsing witchcraft
const data = JSON.parse(this.responseText.substring(4))[1][0];
const tileSize = data[2][3][1][0];
const bestZoom = (data[2][3][0].length - 1);
if (bestZoom < zoom || zoom < 0) {
zoom = bestZoom;
document.getElementById("zoom").value = bestZoom;
}
const widthPX = data[2][3][0][zoom][0][1];
const heightPX = data[2][3][0][zoom][0][0];
const width = Math.ceil(widthPX / tileSize);
const height = Math.ceil(heightPX / tileSize);
prepCanvas(widthPX, heightPX);
const copyright = data[4][1][0][0];
ID("infoZooms").textContent = bestZoom;
ID("infoCopyright").textContent = copyright;
prepCanvas(widthPX, heightPX);
ID("infoStatus").textContent = "Downloading tiles";
const totalTiles = width * height;
var processedTiles = 0;
for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
requestImage(`https://lh3.ggpht.com/p/${sphereID}=x${x}-y${y}-z${zoom}`, (image) => {
paintImage(image, x, y, heightPX, widthPX, tileSize, height);
processedTiles++;
if (processedTiles === totalTiles) {
ID("infoStatus").textContent = "finished";
}
});
}
}
};
request.open("get", `https://www.google.com/maps/photometa/v1?authuser=0&hl=en&gl=us&pb=!1m4!1smaps_sv.tactile!11m2!2m1!1b1!2m2!1sen!2sus!3m3!1m2!1e10!2s${sphereID}!4m57!1e1!1e2!1e3!1e4!1e5!1e6!1e8!1e12!2m1!1e1!4m1!1i48!5m1!1e1!5m1!1e2!6m1!1e1!6m1!1e2!9m36!1m3!1e2!2b1!3e2!1m3!1e2!2b0!3e3!1m3!1e3!2b1!3e2!1m3!1e3!2b0!3e3!1m3!1e8!2b0!3e3!1m3!1e1!2b0!3e3!1m3!1e4!2b0!3e3!1m3!1e10!2b1!3e2!1m3!1e10!2b0!3e3`, true);
request.send();
}
function requestImage(url, callback) {
var req = new XMLHttpRequest();
req.responseType = "arraybuffer";
req.onload = function () {
const blob = new Blob([this.response], { type: 'application/octet-binary' });
var url = window.URL.createObjectURL(blob);
const image = new Image();
image.src = url;
image.onload = () => {
callback(image);
};
};
req.open("get", url, true);
req.send();
}
function prepCanvas(widthPX, heightPX) {
canvas.width = widthPX;
canvas2.width = widthPX;
if (heightPX > maxCanvasHeight) {
canvas2.height = heightPX / 2;
canvas.height = heightPX / 2;
} else {
canvas2.height = 0;
canvas2.width = 0;
canvas.height = heightPX;
}
}
function paintImage(img, x, y, heightPX, widthPX, tileSize, height) {
if (heightPX > maxCanvasHeight) {
if ((y > ((height / 2) - 1)) && height !== 1) {
ctx2.drawImage(img, x * tileSize, y * tileSize - (heightPX / 2));
} else {
ctx.drawImage(img, x * tileSize, y * tileSize);
}
} else {
ctx.drawImage(img, x * tileSize, y * tileSize);
}
}