This code fetches and assembles a panoramic image from Google Street View, allowing for dynamic display and manipulation of street-level imagery.
npm run import -- "load google panorama"
// FROM: https://github.com/sidequestlegend/GSVPanoDepth.js/blob/master/examples/js/GSVPano.js
var path = require('path')
var fs = require('fs')
var {GoogleAuth} = require('google-auth-library');
var google = require('googleapis')
var importer = require('../Core')
var getRpcFromSpec = importer.import("get rpc from spec")
var authorize = importer.import("google oauth token client")
var mapsClient = getRpcFromSpec(require('../Resources/APIs/google-maps-platform-openapi3.json'));
var {createCanvas, loadImage} = require('canvas')
var PROFILE_PATH = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
var authKey = fs.readFileSync(path.join(PROFILE_PATH, '.credentials/key.txt')).toString().trim()
//_panoClient = new google.maps.StreetViewService(),
var _location,
_zoom,
_panoId,
_count = 0,
_total = 0,
_canvas = createCanvas(1, 1),
_ctx = _canvas.getContext('2d'),
rotation = 0,
copyright = '',
onSizeChange = null,
onPanoramaLoad = null
function setProgress(p) {
}
function throwError(message) {
if (onError) {
onError(message)
} else {
console.error(message)
}
}
function adaptTextureToZoom() {
var w = 416 * Math.pow(2, _zoom - 0.7),
h = (416 * Math.pow(2, _zoom - 2))
_canvas.width = w
_canvas.height = h
_ctx.translate( _canvas.width, 0)
_ctx.scale(-1, 1)
}
function composeFromTile(x, y, texture) {
_ctx.drawImage(texture, x * 512, y * 512)
_count++
var p = Math.round(_count * 100 / _total)
setProgress(p)
if (_count === _total) {
if (onPanoramaLoad) {
onPanoramaLoad()
}
}
}
async function composePanorama() {
setProgress(0)
console.log('Loading panorama for zoom ' + _zoom + '...')
var w = Math.pow(2, _zoom),
h = Math.pow(2, _zoom - 1),
url, x, y
_count = 0
_total = w * h
var now = (new Date).getTime()
for( y = 0; y < h; y++) {
for( x = 0; x < w; x++) {
/*
var imgResult = await mapsClient.cbk.get({
output: 'tile',
panoid: _panoId,
zoom: 0,
x: x,
y: y
})
fs.writeFileSync('.tmpimg.jpeg', imgResult.body)
*/
//url = 'http://maps.google.com/cbk?output=tile&panoid=' + _panoId + '&zoom=0&x=' + x + '&y=' + y + '&' + Date.now()
//var img = await loadImage('.tmpimg.jpeg')
/*
var img = new Image
img.addEventListener('load', function () {
resolve()
})
var imgPromise = new Promise(resolve => {
})
img.src = imgResult.body
await imgPromise
*/
if (onPanoramaLoad) {
await onPanoramaLoad(_panoId)
}
//composeFromTile(x, y, img)
}
}
}
async function loadPanorama(location, onLoad) {
console.log(mapsClient)
console.log('Load for', location)
var result = await mapsClient.maps.streetview.metadata.get({
location: location[0] + ',' + location[1],
heading: 0,
key: authKey
})
onPanoramaLoad = onLoad
//if( onPanoramaData ) onPanoramaData( result )
//var h = google.maps.geometry.spherical.computeHeading(location, result.location.latLng)
//rotation = (result.tiles.centerHeading - h) * Math.PI / 180.0
//copyright = result.copyright
_panoId = result.body.pano_id
_location = location
await composePanorama()
}
function setZoom( z ) {
_zoom = z
adaptTextureToZoom()
}
module.exports = {
setZoom,
loadPanorama,
}
const path = require('path');
const fs = require('fs');
const { GoogleAuth } = require('google-auth-library');
const google = require('googleapis');
const importer = require('../Core');
const { getRpcFromSpec } = importer.import('get rpc from spec');
const { authorize } = importer.import('google oauth token client');
const { createCanvas, loadImage } = require('canvas');
const PROFILE_PATH = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
const authKey = fs.readFileSync(path.join(PROFILE_PATH, '.credentials/key.txt')).toString().trim();
const _panoClient = new google.maps.StreetViewService();
const _location = null;
const _zoom = 0;
const _panoId = null;
const _count = 0;
const _total = 0;
const _canvas = createCanvas(1, 1);
const _ctx = _canvas.getContext('2d');
let rotation = 0;
let copyright = '';
let onError = null;
let onSizeChange = null;
let onPanoramaLoad = null;
/**
* @description Sets the progress of the panorama composition
* @param {number} p The progress percentage
*/
function setProgress(p) {
if (onError) {
onError(p);
} else {
console.error(`Progress: ${p}%`);
}
}
/**
* @description Throws an error if an error handler is provided
* @param {string} message The error message
*/
function throwError(message) {
if (onError) {
onError(message);
} else {
console.error(message);
}
}
/**
* @description Adapts the texture to the current zoom level
*/
function adaptTextureToZoom() {
const w = 416 * Math.pow(2, _zoom - 0.7);
const h = 416 * Math.pow(2, _zoom - 2);
_canvas.width = w;
_canvas.height = h;
_ctx.translate(_canvas.width, 0);
_ctx.scale(-1, 1);
}
/**
* @description Composes a tile from the given texture
* @param {number} x The x-coordinate of the tile
* @param {number} y The y-coordinate of the tile
* @param {HTMLImageElement} texture The texture to compose
*/
function composeFromTile(x, y, texture) {
_ctx.drawImage(texture, x * 512, y * 512);
_count++;
setProgress(Math.round(_count * 100 / _total));
if (_count === _total) {
if (onPanoramaLoad) {
onPanoramaLoad();
}
}
}
/**
* @description Composes the panorama from the tiles
* @async
*/
async function composePanorama() {
setProgress(0);
console.log(`Loading panorama for zoom ${_zoom}...`);
const w = Math.pow(2, _zoom);
const h = Math.pow(2, _zoom - 1);
const url = `http://maps.google.com/cbk?output=tile&panoid=${_panoId}&zoom=0`;
_count = 0;
_total = w * h;
const now = new Date().getTime();
for (let y = 0; y < h; y++) {
for (let x = 0; x < w; x++) {
const imgPromise = new Promise((resolve) => {
const img = new Image();
img.addEventListener('load', () => {
resolve();
});
img.src = `${url}&x=${x}&y=${y}&${now}`;
});
await imgPromise;
composeFromTile(x, y, new Image());
}
}
}
/**
* @description Loads the panorama from the given location
* @async
* @param {Array} location The location coordinates
* @param {function} onLoad The callback function to call when the panorama is loaded
*/
async function loadPanorama(location, onLoad) {
console.log('Load for', location);
const result = await mapsClient.maps.streetview.metadata.get({
location: location[0] + ',' + location[1],
heading: 0,
key: authKey,
});
onPanoramaLoad = onLoad;
_panoId = result.body.pano_id;
_location = location;
await composePanorama();
}
/**
* @description Sets the zoom level of the panorama
* @param {number} z The new zoom level
*/
function setZoom(z) {
_zoom = z;
adaptTextureToZoom();
}
module.exports = {
setZoom,
loadPanorama,
};
This code snippet is designed to load and compose a panoramic image from Google Street View using the Google Maps Platform API.
Here's a breakdown:
Dependencies:
Initialization:
Progress Handling:
Image Adaptation:
Tile Composition:
Panorama Loading:
Callbacks:
Purpose:
This code snippet demonstrates how to fetch and assemble a panoramic image from Google Street View programmatically, allowing for dynamic display and manipulation of street-level imagery.