import { TextureLoader } from './TextureLoader';
/**
* @classdesc Google Street View Loader
* @constructor
* @param {object} parameters
*/
function GoogleStreetviewLoader ( parameters = {} ) {
this._parameters = parameters;
this._zoom = null;
this._panoId = null;
this._panoClient = new google.maps.StreetViewService();
this._count = 0;
this._total = 0;
this._canvas = [];
this._ctx = [];
this._wc = 0;
this._hc = 0;
this.result = null;
this.rotation = 0;
this.copyright = '';
this.onSizeChange = null;
this.onPanoramaLoad = null;
this.levelsW = [ 1, 2, 4, 7, 13, 26 ];
this.levelsH = [ 1, 1, 2, 4, 7, 13 ];
this.widths = [ 416, 832, 1664, 3328, 6656, 13312 ];
this.heights = [ 416, 416, 832, 1664, 3328, 6656 ];
this.maxW = 6656;
this.maxH = 6656;
let gl;
try {
const canvas = document.createElement( 'canvas' );
gl = canvas.getContext( 'experimental-webgl' );
if( !gl ) {
gl = canvas.getContext( 'webgl' );
}
}
catch ( error ) {
}
this.maxW = Math.max( gl.getParameter( gl.MAX_TEXTURE_SIZE ), this.maxW );
this.maxH = Math.max( gl.getParameter( gl.MAX_TEXTURE_SIZE ), this.maxH );
}
Object.assign( GoogleStreetviewLoader.prototype, {
constructor: GoogleStreetviewLoader,
/**
* Set progress
* @param {number} loaded
* @param {number} total
* @memberOf GoogleStreetviewLoader
* @instance
*/
setProgress: function ( loaded, total ) {
if ( this.onProgress ) {
this.onProgress( { loaded: loaded, total: total } );
}
},
/**
* Adapt texture to zoom
* @memberOf GoogleStreetviewLoader
* @instance
*/
adaptTextureToZoom: function () {
const w = this.widths [ this._zoom ];
const h = this.heights[ this._zoom ];
const maxW = this.maxW;
const maxH = this.maxH;
this._wc = Math.ceil( w / maxW );
this._hc = Math.ceil( h / maxH );
for( let y = 0; y < this._hc; y++ ) {
for( let x = 0; x < this._wc; x++ ) {
const c = document.createElement( 'canvas' );
if( x < ( this._wc - 1 ) ) c.width = maxW; else c.width = w - ( maxW * x );
if( y < ( this._hc - 1 ) ) c.height = maxH; else c.height = h - ( maxH * y );
this._canvas.push( c );
this._ctx.push( c.getContext( '2d' ) );
}
}
},
/**
* Compose from tile
* @param {number} x
* @param {number} y
* @param {*} texture
* @memberOf GoogleStreetviewLoader
* @instance
*/
composeFromTile: function ( x, y, texture ) {
const maxW = this.maxW;
const maxH = this.maxH;
x *= 512;
y *= 512;
const px = Math.floor( x / maxW );
const py = Math.floor( y / maxH );
x -= px * maxW;
y -= py * maxH;
this._ctx[ py * this._wc + px ].drawImage( texture, 0, 0, texture.width, texture.height, x, y, 512, 512 );
this.progress();
},
/**
* Progress
* @memberOf GoogleStreetviewLoader
* @instance
*/
progress: function() {
this._count++;
this.setProgress( this._count, this._total );
if ( this._count === this._total) {
this.canvas = this._canvas;
this.panoId = this._panoId;
this.zoom = this._zoom;
if ( this.onPanoramaLoad ) {
this.onPanoramaLoad( this._canvas[ 0 ] );
}
}
},
/**
* Compose panorama
* @memberOf GoogleStreetviewLoader
* @instance
*/
composePanorama: function () {
this.setProgress( 0, 1 );
const w = this.levelsW[ this._zoom ];
const h = this.levelsH[ this._zoom ];
const self = this;
this._count = 0;
this._total = w * h;
const { useWebGL } = this._parameters;
for( let y = 0; y < h; y++ ) {
for( let x = 0; x < w; x++ ) {
const url = 'https://geo0.ggpht.com/cbk?cb_client=maps_sv.tactile&authuser=0&hl=en&output=tile&zoom=' + this._zoom + '&x=' + x + '&y=' + y + '&panoid=' + this._panoId + '&nbt&fover=2';
( function( x, y ) {
if( useWebGL ) {
const texture = TextureLoader.load( url, null, function() {
self.composeFromTile( x, y, texture );
} );
} else {
const img = new Image();
img.addEventListener( 'load', function() {
self.composeFromTile( x, y, this );
} );
img.crossOrigin = '';
img.src = url;
}
} )( x, y );
}
}
},
/**
* Load
* @param {string} panoid
* @memberOf GoogleStreetviewLoader
* @instance
*/
load: function ( panoid ) {
this.loadPano( panoid );
},
/**
* Load panorama
* @param {string} id
* @memberOf GoogleStreetviewLoader
* @instance
*/
loadPano: function( id ) {
const self = this;
this._panoClient.getPanoramaById( id, function (result, status) {
if (status === google.maps.StreetViewStatus.OK) {
self.result = result;
self.copyright = result.copyright;
self._panoId = result.location.pano;
self.composePanorama();
}
});
},
/**
* Set zoom level
* @param {number} z
* @memberOf GoogleStreetviewLoader
* @instance
*/
setZoom: function( z ) {
this._zoom = z;
this.adaptTextureToZoom();
}
} );
export { GoogleStreetviewLoader };