- /**
- * Get srtInverse.
- * @returns {THREE.Matrix4} The scaled extrinsic camera matrix.
- */
- get srtInverse() {
- return this._scaledWorldToCameraInverse;
- }
- /**
- * Get scale.
- * @returns {number} The image atomic reconstruction scale.
- */
- get scale() {
- return this._scale;
- }
- /**
- * Get has valid scale.
- * @returns {boolean} Value indicating if the scale of the transform is valid.
- */
- get hasValidScale() {
- return this._scale > 1e-2 && this._scale < 50;
- }
- /**
- * Get radial peak.
- * @returns {number} Value indicating the radius where the radial
- * undistortion function peaks.
- */
- get radialPeak() {
- return this._radialPeak;
- }
- /**
- * Get width.
- *
- * @description Falls back to the image image width if
- * the API data is faulty.
- *
- * @returns {number} The orientation adjusted image width.
- */
- get width() {
- return this._width;
- }
- /**
- * Calculate the up vector for the image transform.
- *
- * @returns {THREE.Vector3} Normalized and orientation adjusted up vector.
- */
- upVector() {
- let rte = this._worldToCamera.elements;
- switch (this._orientation) {
- case 1:
- return new Vector3(-rte[1], -rte[5], -rte[9]);
- case 3:
- return new Vector3(rte[1], rte[5], rte[9]);
- case 6:
- return new Vector3(-rte[0], -rte[4], -rte[8]);
- case 8:
- return new Vector3(rte[0], rte[4], rte[8]);
- default:
- return new Vector3(-rte[1], -rte[5], -rte[9]);
- }
- }
- /**
- * Calculate projector matrix for projecting 3D points to texture map
- * coordinates (u and v).
- *
- * @returns {THREE.Matrix4} Projection matrix for 3D point to texture
- * map coordinate calculations.
- */
- projectorMatrix() {
- let projector = this._normalizedToTextureMatrix();
- let f = this._focal;
- let projection = new Matrix4().set(f, 0, 0, 0, 0, f, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);
- projector.multiply(projection);
- projector.multiply(this._worldToCamera);
- return projector;
- }
- /**
- * Project 3D world coordinates to basic coordinates.
- *
- * @param {Array<number>} point3d - 3D world coordinates.
- * @return {Array<number>} 2D basic coordinates.
- */
- projectBasic(point3d) {
- let sfm = this.projectSfM(point3d);
- return this._sfmToBasic(sfm);
- }
- /**
- * Unproject basic coordinates to 3D world coordinates.
- *
- * @param {Array<number>} basic - 2D basic coordinates.
- * @param {Array<number>} distance - Distance to unproject from camera center.
- * @param {boolean} [depth] - Treat the distance value as depth from camera center.
- * Only applicable for perspective images. Will be
- * ignored for spherical.
- * @returns {Array<number>} Unprojected 3D world coordinates.
- */
- unprojectBasic(basic, distance, depth) {
- let sfm = this._basicToSfm(basic);
- return this.unprojectSfM(sfm, distance, depth);
- }
- /**
- * Project 3D world coordinates to SfM coordinates.
- *
- * @param {Array<number>} point3d - 3D world coordinates.
- * @return {Array<number>} 2D SfM coordinates.
- */
- projectSfM(point3d) {
- let v = new Vector4(point3d[0], point3d[1], point3d[2], 1);
- v.applyMatrix4(this._worldToCamera);
- return this._bearingToSfm([v.x, v.y, v.z]);
- }
- /**
- * Unproject SfM coordinates to a 3D world coordinates.
- *
- * @param {Array<number>} sfm - 2D SfM coordinates.
- * @param {Array<number>} distance - Distance to unproject
- * from camera center.
- * @param {boolean} [depth] - Treat the distance value as
- * depth from camera center. Only applicable for perspective
- * images. Will be ignored for spherical.
- * @returns {Array<number>} Unprojected 3D world coordinates.
- */
- unprojectSfM(sfm, distance, depth) {
- const bearing = this._sfmToBearing(sfm);
- const unprojectedCamera = depth && !isSpherical(this._cameraType) ?
- new Vector4(distance * bearing[0] / bearing[2], distance * bearing[1] / bearing[2], distance, 1) :
- new Vector4(distance * bearing[0], distance * bearing[1], distance * bearing[2], 1);
- const unprojectedWorld = unprojectedCamera
- .applyMatrix4(this._worldToCameraInverse);
- return [
- unprojectedWorld.x / unprojectedWorld.w,
- unprojectedWorld.y / unprojectedWorld.w,
- unprojectedWorld.z / unprojectedWorld.w,
- ];
- }
- /**
- * Transform SfM coordinates to bearing vector (3D cartesian
- * coordinates on the unit sphere).
- *
- * @param {Array<number>} sfm - 2D SfM coordinates.
- * @returns {Array<number>} Bearing vector (3D cartesian coordinates
- * on the unit sphere).
- */
- _sfmToBearing(sfm) {
- if (isSpherical(this._cameraType)) {
- let lng = sfm[0] * 2 * Math.PI;
- let lat = -sfm[1] * 2 * Math.PI;
- let x = Math.cos(lat) * Math.sin(lng);
- let y = -Math.sin(lat);
- let z = Math.cos(lat) * Math.cos(lng);
- return [x, y, z];
- }
- else if (isFisheye(this._cameraType)) {
- let [dxn, dyn] = [sfm[0] / this._focal, sfm[1] / this._focal];
- const dTheta = Math.sqrt(dxn * dxn + dyn * dyn);
- let d = this._distortionFromDistortedRadius(dTheta, this._ck1, this._ck2, this._radialPeak);
- let theta = dTheta / d;
- let z = Math.cos(theta);
- let r = Math.sin(theta);
- const denomTheta = dTheta > EPSILON ? 1 / dTheta : 1;
- let x = r * dxn * denomTheta;
- let y = r * dyn * denomTheta;
- return [x, y, z];
- }
- else {
- let [dxn, dyn] = [sfm[0] / this._focal, sfm[1] / this._focal];
- const dr = Math.sqrt(dxn * dxn + dyn * dyn);
- let d = this._distortionFromDistortedRadius(dr, this._ck1, this._ck2, this._radialPeak);
- const xn = dxn / d;
- const yn = dyn / d;
- let v = new Vector3(xn, yn, 1);
- v.normalize();
- return [v.x, v.y, v.z];
- }
- }
- /** Compute distortion given the distorted radius.
- *
- * Solves for d in the equation
- * y = d(x, k1, k2) * x
- * given the distorted radius, y.
- */
- _distortionFromDistortedRadius(distortedRadius, k1, k2, radialPeak) {
- let d = 1.0;
- for (let i = 0; i < 10; i++) {
- let radius = distortedRadius / d;
- if (radius > radialPeak) {
- radius = radialPeak;
- }
- d = 1 + k1 * Math.pow(radius, 2) + k2 * Math.pow(radius, 4);
- }
- return d;
- }
- /**
- * Transform bearing vector (3D cartesian coordiantes on the unit sphere) to
- * SfM coordinates.
- *
- * @param {Array<number>} bearing - Bearing vector (3D cartesian coordinates on the
- * unit sphere).
- * @returns {Array<number>} 2D SfM coordinates.
- */
- _bearingToSfm(bearing) {
- if (isSpherical(this._cameraType)) {
- let x = bearing[0];
- let y = bearing[1];
- let z = bearing[2];
- let lng = Math.atan2(x, z);
- let lat = Math.atan2(-y, Math.sqrt(x * x + z * z));
- return [lng / (2 * Math.PI), -lat / (2 * Math.PI)];
- }
- else if (isFisheye(this._cameraType)) {
- if (bearing[2] > 0) {
- const [x, y, z] = bearing;
- const r = Math.sqrt(x * x + y * y);
- let theta = Math.atan2(r, z);
- if (theta > this._radialPeak) {
- theta = this._radialPeak;
- }
- const distortion = 1.0 + Math.pow(theta, 2) * (this._ck1 + Math.pow(theta, 2) * this._ck2);
- const s = this._focal * distortion * theta / r;
- return [s * x, s * y];
- }
- else {
- return [
- bearing[0] < 0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
- bearing[1] < 0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
- ];
- }
- }
- else {
- if (bearing[2] > 0) {
- let [xn, yn] = [bearing[0] / bearing[2], bearing[1] / bearing[2]];
- let r2 = xn * xn + yn * yn;
- const rp2 = Math.pow(this._radialPeak, 2);
- if (r2 > rp2) {
- r2 = rp2;
- }
- const d = 1 + this._ck1 * r2 + this._ck2 * Math.pow(r2, 2);
- return [
- this._focal * d * xn,
- this._focal * d * yn,
- ];
- }
- else {
- return [
- bearing[0] < 0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
- bearing[1] < 0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
- ];
- }
- }
- }
- /**
- * Convert basic coordinates to SfM coordinates.
- *
- * @param {Array<number>} basic - 2D basic coordinates.
- * @returns {Array<number>} 2D SfM coordinates.
- */
- _basicToSfm(basic) {
- let rotatedX;
- let rotatedY;
- switch (this._orientation) {
- case 1:
- rotatedX = basic[0];
- rotatedY = basic[1];
- break;
- case 3:
- rotatedX = 1 - basic[0];
- rotatedY = 1 - basic[1];
- break;
- case 6:
- rotatedX = basic[1];
- rotatedY = 1 - basic[0];
- break;
- case 8:
- rotatedX = 1 - basic[1];
- rotatedY = basic[0];
- break;
- default:
- rotatedX = basic[0];
- rotatedY = basic[1];
- break;
- }
- let w = this._width;
- let h = this._height;
- let s = Math.max(w, h);
- let sfmX = rotatedX * w / s - w / s / 2;
- let sfmY = rotatedY * h / s - h / s / 2;
- return [sfmX, sfmY];
- }
- /**
- * Convert SfM coordinates to basic coordinates.
- *
- * @param {Array<number>} sfm - 2D SfM coordinates.
- * @returns {Array<number>} 2D basic coordinates.
- */
- _sfmToBasic(sfm) {
- let w = this._width;
- let h = this._height;
- let s = Math.max(w, h);
- let rotatedX = (sfm[0] + w / s / 2) / w * s;
- let rotatedY = (sfm[1] + h / s / 2) / h * s;
- let basicX;
- let basicY;
- switch (this._orientation) {
- case 1:
- basicX = rotatedX;
- basicY = rotatedY;
- break;
- case 3:
- basicX = 1 - rotatedX;
- basicY = 1 - rotatedY;
- break;
- case 6:
- basicX = 1 - rotatedY;
- basicY = rotatedX;
- break;
- case 8:
- basicX = rotatedY;
- basicY = 1 - rotatedX;
- break;
- default:
- basicX = rotatedX;
- basicY = rotatedY;
- break;
- }
- return [basicX, basicY];
- }
- /**
- * Checks a value and returns it if it exists and is larger than 0.
- * Fallbacks if it is null.
- *
- * @param {number} value - Value to check.
- * @param {number} fallback - Value to fall back to.
- * @returns {number} The value or its fallback value if it is not defined or negative.
- */
- _getValue(value, fallback) {
- return value != null && value > 0 ? value : fallback;
- }
- _getCameraParameters(value, cameraType) {
- if (isSpherical(cameraType)) {
- return [];
- }
- if (!value || value.length === 0) {
- return [1, 0, 0];
- }
- const padding = 3 - value.length;
- if (padding <= 0) {
- return value;
- }
- return value
- .concat(new Array(padding)
- .fill(0));
- }
- /**
- * Creates the extrinsic camera matrix [ R | t ].
- *
- * @param {Array<number>} rotation - Rotation vector in angle axis representation.
- * @param {Array<number>} translation - Translation vector.
- * @returns {THREE.Matrix4} Extrisic camera matrix.
- */
- createWorldToCamera(rotation, translation) {
- const axis = new Vector3(rotation[0], rotation[1], rotation[2]);
- const angle = axis.length();
- if (angle > 0) {
- axis.normalize();
- }
- const worldToCamera = new Matrix4();
- worldToCamera.makeRotationAxis(axis, angle);
- worldToCamera.setPosition(new Vector3(translation[0], translation[1], translation[2]));
- return worldToCamera;
- }
- /**
- * Calculates the scaled extrinsic camera matrix scale * [ R | t ].
- *
- * @param {THREE.Matrix4} worldToCamera - Extrisic camera matrix.
- * @param {number} scale - Scale factor.
- * @returns {THREE.Matrix4} Scaled extrisic camera matrix.
- */
- _createScaledWorldToCamera(worldToCamera, scale) {
- const scaledWorldToCamera = worldToCamera.clone();
- const elements = scaledWorldToCamera.elements;
- elements[12] = scale * elements[12];
- elements[13] = scale * elements[13];
- elements[14] = scale * elements[14];
- scaledWorldToCamera.scale(new Vector3(scale, scale, scale));
- return scaledWorldToCamera;
- }
- _createBasicWorldToCamera(rt, orientation) {
- const axis = new Vector3(0, 0, 1);
- let angle = 0;
- switch (orientation) {
- case 3:
- angle = Math.PI;
- break;
- case 6:
- angle = Math.PI / 2;
- break;
- case 8:
- angle = 3 * Math.PI / 2;
- break;
- }
- return new Matrix4()
- .makeRotationAxis(axis, angle)
- .multiply(rt);
- }
- _getRadialPeak(k1, k2) {
- const a = 5 * k2;
- const b = 3 * k1;
- const c = 1;
- const d = Math.pow(b, 2) - 4 * a * c;
- if (d < 0) {
- return undefined;
- }
- const root1 = (-b - Math.sqrt(d)) / 2 / a;
- const root2 = (-b + Math.sqrt(d)) / 2 / a;
- const minRoot = Math.min(root1, root2);
- const maxRoot = Math.max(root1, root2);
- return minRoot > 0 ?
- Math.sqrt(minRoot) :
- maxRoot > 0 ?
- Math.sqrt(maxRoot) :
- undefined;
- }
- /**
- * Calculate a transformation matrix from normalized coordinates for
- * texture map coordinates.
- *
- * @returns {THREE.Matrix4} Normalized coordinates to texture map
- * coordinates transformation matrix.
- */
- _normalizedToTextureMatrix() {
- const size = Math.max(this._width, this._height);
- const scaleX = this._orientation < 5 ? this._textureScale[0] : this._textureScale[1];
- const scaleY = this._orientation < 5 ? this._textureScale[1] : this._textureScale[0];
- const w = size / this._width * scaleX;
- const h = size / this._height * scaleY;
- switch (this._orientation) {
- case 1:
- return new Matrix4().set(w, 0, 0, 0.5, 0, -h, 0, 0.5, 0, 0, 1, 0, 0, 0, 0, 1);
- case 3:
- return new Matrix4().set(-w, 0, 0, 0.5, 0, h, 0, 0.5, 0, 0, 1, 0, 0, 0, 0, 1);
- case 6:
- return new Matrix4().set(0, -h, 0, 0.5, -w, 0, 0, 0.5, 0, 0, 1, 0, 0, 0, 0, 1);
- case 8:
- return new Matrix4().set(0, h, 0, 0.5, w, 0, 0, 0.5, 0, 0, 1, 0, 0, 0, 0, 1);
- default:
- return new Matrix4().set(w, 0, 0, 0.5, 0, -h, 0, 0.5, 0, 0, 1, 0, 0, 0, 0, 1);
- }
- }
- }
-
- class StateBase {
- constructor(state) {
- this._spatial = new Spatial();
- this._referenceThreshold = 0.01;
- this._transitionMode = state.transitionMode;
- this._reference = state.reference;
- this._alpha = state.alpha;
- this._camera = state.camera.clone();
- this._zoom = state.zoom;
- this._currentIndex = state.currentIndex;
- this._trajectory = state.trajectory.slice();
- this._trajectoryTransforms = [];
- this._trajectoryCameras = [];
- for (let image of this._trajectory) {
- let translation = this._imageToTranslation(image, this._reference);
- let transform = new Transform(image.exifOrientation, image.width, image.height, image.scale, image.rotation, translation, image.image, undefined, image.cameraParameters, image.cameraType);
- this._trajectoryTransforms.push(transform);
- this._trajectoryCameras.push(new Camera(transform));
- }
- this._currentImage = this._trajectory.length > 0 ?
- this._trajectory[this._currentIndex] :
- null;
- this._previousImage = this._trajectory.length > 1 && this.currentIndex > 0 ?
- this._trajectory[this._currentIndex - 1] :
- null;
- this._currentCamera = this._trajectoryCameras.length > 0 ?
- this._trajectoryCameras[this._currentIndex].clone() :
- new Camera();
- this._previousCamera = this._trajectoryCameras.length > 1 && this.currentIndex > 0 ?
- this._trajectoryCameras[this._currentIndex - 1].clone() :
- this._currentCamera.clone();
- }
- get reference() {
- return this._reference;
- }
- get alpha() {
- return this._getAlpha();
- }
- get camera() {
- return this._camera;
- }
- get zoom() {
- return this._zoom;
- }
- get trajectory() {
- return this._trajectory;
- }
- get currentIndex() {
- return this._currentIndex;
- }
- get currentImage() {
- return this._currentImage;
- }
- get previousImage() {
- return this._previousImage;
- }
- get currentCamera() {
- return this._currentCamera;
- }
- get currentTransform() {
- return this._trajectoryTransforms.length > 0 ?
- this._trajectoryTransforms[this.currentIndex] : null;
- }
- get previousTransform() {
- return this._trajectoryTransforms.length > 1 && this.currentIndex > 0 ?
- this._trajectoryTransforms[this.currentIndex - 1] : null;
- }
- get motionless() {
- return this._motionless;
- }
- get transitionMode() {
- return this._transitionMode;
- }
- move(delta) { }
- moveTo(position) { }
- rotate(delta) { }
- rotateUnbounded(delta) { }
- rotateWithoutInertia(delta) { }
- rotateBasic(basicRotation) { }
- rotateBasicUnbounded(basicRotation) { }
- rotateBasicWithoutInertia(basicRotation) { }
- rotateToBasic(basic) { }
- setSpeed(speed) { }
- zoomIn(delta, reference) { }
- update(fps) { }
- setCenter(center) { }
- setZoom(zoom) { }
- dolly(delta) { }
- orbit(rotation) { }
- setViewMatrix(matrix) { }
- truck(direction) { }
- append(images) {
- if (images.length < 1) {
- throw Error("Trajectory can not be empty");
- }
- if (this._currentIndex < 0) {
- this.set(images);
- }
- else {
- this._trajectory = this._trajectory.concat(images);
- this._appendToTrajectories(images);
- }
- }
- prepend(images) {
- if (images.length < 1) {
- throw Error("Trajectory can not be empty");
- }
- this._trajectory = images.slice().concat(this._trajectory);
- this._currentIndex += images.length;
- this._setCurrentImage();
- let referenceReset = this._setReference(this._currentImage);
- if (referenceReset) {
- this._setTrajectories();
- }
- else {
- this._prependToTrajectories(images);
- }
- this._setCurrentCamera();
- }
- remove(n) {
- if (n < 0) {
- throw Error("n must be a positive integer");
- }
- if (this._currentIndex - 1 < n) {
- throw Error("Current and previous images can not be removed");
- }
- for (let i = 0; i < n; i++) {
- this._trajectory.shift();
- this._trajectoryTransforms.shift();
- this._trajectoryCameras.shift();
- this._currentIndex--;
- }
- this._setCurrentImage();
- }
- clearPrior() {
- if (this._currentIndex > 0) {
- this.remove(this._currentIndex - 1);
- }
- }
- clear() {
- this.cut();
- if (this._currentIndex > 0) {
- this.remove(this._currentIndex - 1);
- }
- }
- cut() {
- while (this._trajectory.length - 1 > this._currentIndex) {
- this._trajectory.pop();
- this._trajectoryTransforms.pop();
- this._trajectoryCameras.pop();
- }
- }
- set(images) {
- this._setTrajectory(images);
- this._setCurrentImage();
- this._setReference(this._currentImage);
- this._setTrajectories();
- this._setCurrentCamera();
- }
- getCenter() {
- return this._currentImage != null ?
- this.currentTransform.projectBasic(this._camera.lookat.toArray()) :
- [0.5, 0.5];
- }
- setTransitionMode(mode) {
- this._transitionMode = mode;
- }
- _getAlpha() { return 1; }
- _setCurrent() {
- this._setCurrentImage();
- let referenceReset = this._setReference(this._currentImage);
- if (referenceReset) {
- this._setTrajectories();
- }
- this._setCurrentCamera();
- }
- _setCurrentCamera() {
- this._currentCamera = this._trajectoryCameras[this._currentIndex].clone();
- this._previousCamera = this._currentIndex > 0 ?
- this._trajectoryCameras[this._currentIndex - 1].clone() :
- this._currentCamera.clone();
- }
- _motionlessTransition() {
- let imagesSet = this._currentImage != null && this._previousImage != null;
- return imagesSet && (this._transitionMode === exports.TransitionMode.Instantaneous || !(this._currentImage.merged &&
- this._previousImage.merged &&
- this._withinOriginalDistance() &&
- this._sameConnectedComponent()));
- }
- _setReference(image) {
- // do not reset reference if image is within threshold distance
- if (Math.abs(image.lngLat.lat - this.reference.lat) < this._referenceThreshold &&
- Math.abs(image.lngLat.lng - this.reference.lng) < this._referenceThreshold) {
- return false;
- }
- // do not reset reference if previous image exist and transition is with motion
- if (this._previousImage != null && !this._motionlessTransition()) {
- return false;
- }
- this._reference.lat = image.lngLat.lat;
- this._reference.lng = image.lngLat.lng;
- this._reference.alt = image.computedAltitude;
- return true;
- }
- _setCurrentImage() {
- this._currentImage = this._trajectory.length > 0 ?
- this._trajectory[this._currentIndex] :
- null;
- this._previousImage = this._currentIndex > 0 ?
- this._trajectory[this._currentIndex - 1] :
- null;
- }
- _setTrajectory(images) {
- if (images.length < 1) {
- throw new ArgumentMapillaryError("Trajectory can not be empty");
- }
- if (this._currentImage != null) {
- this._trajectory = [this._currentImage].concat(images);
- this._currentIndex = 1;
- }
- else {
- this._trajectory = images.slice();
- this._currentIndex = 0;
- }
- }
- _setTrajectories() {
- this._trajectoryTransforms.length = 0;
- this._trajectoryCameras.length = 0;
- this._appendToTrajectories(this._trajectory);
- }
- _appendToTrajectories(images) {
- for (let image of images) {
- if (!image.assetsCached) {
- throw new ArgumentMapillaryError("Assets must be cached when image is added to trajectory");
- }
- let translation = this._imageToTranslation(image, this.reference);
- let transform = new Transform(image.exifOrientation, image.width, image.height, image.scale, image.rotation, translation, image.image, undefined, image.cameraParameters, image.cameraType);
- this._trajectoryTransforms.push(transform);
- this._trajectoryCameras.push(new Camera(transform));
- }
- }
- _prependToTrajectories(images) {
- for (let image of images.reverse()) {
- if (!image.assetsCached) {
- throw new ArgumentMapillaryError("Assets must be cached when added to trajectory");
- }
- let translation = this._imageToTranslation(image, this.reference);
- let transform = new Transform(image.exifOrientation, image.width, image.height, image.scale, image.rotation, translation, image.image, undefined, image.cameraParameters, image.cameraType);
- this._trajectoryTransforms.unshift(transform);
- this._trajectoryCameras.unshift(new Camera(transform));
- }
- }
- _imageToTranslation(image, reference) {
- return computeTranslation({ alt: image.computedAltitude, lat: image.lngLat.lat, lng: image.lngLat.lng }, image.rotation, reference);
- }
- _sameConnectedComponent() {
- let current = this._currentImage;
- let previous = this._previousImage;
- return !!current && !!previous &&
- current.mergeId === previous.mergeId;
- }
- _withinOriginalDistance() {
- let current = this._currentImage;
- let previous = this._previousImage;
- if (!current || !previous) {
- return true;
- }
- // 50 km/h moves 28m in 2s
- let distance = this._spatial.distanceFromLngLat(current.originalLngLat.lng, current.originalLngLat.lat, previous.originalLngLat.lng, previous.originalLngLat.lat);
- return distance < 25;
- }
- }
-
- class EulerRotationDelta {
- constructor(phi, theta) {
- this._phi = phi;
- this._theta = theta;
- }
- get phi() {
- return this._phi;
- }
- set phi(value) {
- this._phi = value;
- }
- get theta() {
- return this._theta;
- }
- set theta(value) {
- this._theta = value;
- }
- get isZero() {
- return this._phi === 0 && this._theta === 0;
- }
- copy(delta) {
- this._phi = delta.phi;
- this._theta = delta.theta;
- }
- lerp(other, alpha) {
- this._phi = (1 - alpha) * this._phi + alpha * other.phi;
- this._theta = (1 - alpha) * this._theta + alpha * other.theta;
- }
- multiply(value) {
- this._phi *= value;
- this._theta *= value;
- }
- threshold(value) {
- this._phi = Math.abs(this._phi) > value ? this._phi : 0;
- this._theta = Math.abs(this._theta) > value ? this._theta : 0;
- }
- lengthSquared() {
- return this._phi * this._phi + this._theta * this._theta;
- }
- reset() {
- this._phi = 0;
- this._theta = 0;
- }
- }
-
- class InteractiveStateBase extends StateBase {
- constructor(state) {
- super(state);
- this._animationSpeed = 1 / 40;
- this._rotationDelta = new EulerRotationDelta(0, 0);
- this._requestedRotationDelta = null;
- this._basicRotation = [0, 0];
- this._requestedBasicRotation = null;
- this._requestedBasicRotationUnbounded = null;
- this._rotationAcceleration = 0.86;
- this._rotationIncreaseAlpha = 0.97;
- this._rotationDecreaseAlpha = 0.9;
- this._rotationThreshold = 1e-3;
- this._unboundedRotationAlpha = 0.8;
- this._desiredZoom = state.zoom;
- this._minZoom = 0;
- this._maxZoom = 3;
- this._lookatDepth = 10;
- this._desiredLookat = null;
- this._desiredCenter = null;
- }
- rotate(rotationDelta) {
- if (this._currentImage == null) {
- return;
- }
- if (rotationDelta.phi === 0 && rotationDelta.theta === 0) {
- return;
- }
- this._desiredZoom = this._zoom;
- this._desiredLookat = null;
- this._requestedBasicRotation = null;
- if (this._requestedRotationDelta != null) {
- this._requestedRotationDelta.phi = this._requestedRotationDelta.phi + rotationDelta.phi;
- this._requestedRotationDelta.theta = this._requestedRotationDelta.theta + rotationDelta.theta;
- }
- else {
- this._requestedRotationDelta = new EulerRotationDelta(rotationDelta.phi, rotationDelta.theta);
- }
- }
- rotateUnbounded(delta) {
- if (this._currentImage == null) {
- return;
- }
- this._requestedBasicRotation = null;
- this._requestedRotationDelta = null;
- this._applyRotation(delta, this._currentCamera);
- this._applyRotation(delta, this._previousCamera);
- if (!this._desiredLookat) {
- return;
- }
- const q = new Quaternion().setFromUnitVectors(this._currentCamera.up, new Vector3(0, 0, 1));
- const qInverse = q.clone().invert();
- const offset = new Vector3()
- .copy(this._desiredLookat)
- .sub(this._camera.position)
- .applyQuaternion(q);
- const length = offset.length();
- let phi = Math.atan2(offset.y, offset.x);
- phi += delta.phi;
- let theta = Math.atan2(Math.sqrt(offset.x * offset.x + offset.y * offset.y), offset.z);
- theta += delta.theta;
- theta = Math.max(0.1, Math.min(Math.PI - 0.1, theta));
- offset.x = Math.sin(theta) * Math.cos(phi);
- offset.y = Math.sin(theta) * Math.sin(phi);
- offset.z = Math.cos(theta);
- offset.applyQuaternion(qInverse);
- this._desiredLookat
- .copy(this._camera.position)
- .add(offset.multiplyScalar(length));
- }
- rotateWithoutInertia(rotationDelta) {
- if (this._currentImage == null) {
- return;
- }
- this._desiredZoom = this._zoom;
- this._desiredLookat = null;
- this._requestedBasicRotation = null;
- this._requestedRotationDelta = null;
- const threshold = Math.PI / (10 * Math.pow(2, this._zoom));
- const delta = {
- phi: this._spatial.clamp(rotationDelta.phi, -threshold, threshold),
- theta: this._spatial.clamp(rotationDelta.theta, -threshold, threshold),
- };
- this._applyRotation(delta, this._currentCamera);
- this._applyRotation(delta, this._previousCamera);
- }
- rotateBasic(basicRotation) {
- if (this._currentImage == null) {
- return;
- }
- this._desiredZoom = this._zoom;
- this._desiredLookat = null;
- this._requestedRotationDelta = null;
- if (this._requestedBasicRotation != null) {
- this._requestedBasicRotation[0] += basicRotation[0];
- this._requestedBasicRotation[1] += basicRotation[1];
- let threshold = 0.05 / Math.pow(2, this._zoom);
- this._requestedBasicRotation[0] =
- this._spatial.clamp(this._requestedBasicRotation[0], -threshold, threshold);
- this._requestedBasicRotation[1] =
- this._spatial.clamp(this._requestedBasicRotation[1], -threshold, threshold);
- }
- else {
- this._requestedBasicRotation = basicRotation.slice();
- }
- }
- rotateBasicUnbounded(basicRotation) {
- if (this._currentImage == null) {
- return;
- }
- if (this._requestedBasicRotationUnbounded != null) {
- this._requestedBasicRotationUnbounded[0] += basicRotation[0];
- this._requestedBasicRotationUnbounded[1] += basicRotation[1];
- }
- else {
- this._requestedBasicRotationUnbounded = basicRotation.slice();
- }
- }
- rotateBasicWithoutInertia(basic) {
- if (this._currentImage == null) {
- return;
- }
- this._desiredZoom = this._zoom;
- this._desiredLookat = null;
- this._requestedRotationDelta = null;
- this._requestedBasicRotation = null;
- const threshold = 0.05 / Math.pow(2, this._zoom);
- const basicRotation = basic.slice();
- basicRotation[0] = this._spatial.clamp(basicRotation[0], -threshold, threshold);
- basicRotation[1] = this._spatial.clamp(basicRotation[1], -threshold, threshold);
- this._applyRotationBasic(basicRotation);
- }
- rotateToBasic(basic) {
- if (this._currentImage == null) {
- return;
- }
- this._desiredZoom = this._zoom;
- this._desiredLookat = null;
- basic[0] = this._spatial.clamp(basic[0], 0, 1);
- basic[1] = this._spatial.clamp(basic[1], 0, 1);
- let lookat = this.currentTransform.unprojectBasic(basic, this._lookatDepth);
- this._currentCamera.lookat.fromArray(lookat);
- }
- zoomIn(delta, reference) {
- if (this._currentImage == null) {
- return;
- }
- this._desiredZoom = Math.max(this._minZoom, Math.min(this._maxZoom, this._desiredZoom + delta));
- let currentCenter = this.currentTransform.projectBasic(this._currentCamera.lookat.toArray());
- let currentCenterX = currentCenter[0];
- let currentCenterY = currentCenter[1];
- let zoom0 = Math.pow(2, this._zoom);
- let zoom1 = Math.pow(2, this._desiredZoom);
- let refX = reference[0];
- let refY = reference[1];
- if (isSpherical(this.currentTransform.cameraType)) {
- if (refX - currentCenterX > 0.5) {
- refX = refX - 1;
- }
- else if (currentCenterX - refX > 0.5) {
- refX = 1 + refX;
- }
- }
- let newCenterX = refX - zoom0 / zoom1 * (refX - currentCenterX);
- let newCenterY = refY - zoom0 / zoom1 * (refY - currentCenterY);
- if (isSpherical(this._currentImage.cameraType)) {
- newCenterX = this._spatial
- .wrap(newCenterX + this._basicRotation[0], 0, 1);
- newCenterY = this._spatial
- .clamp(newCenterY + this._basicRotation[1], 0.05, 0.95);
- }
- else {
- newCenterX = this._spatial.clamp(newCenterX, 0, 1);
- newCenterY = this._spatial.clamp(newCenterY, 0, 1);
- }
- this._desiredLookat = new Vector3()
- .fromArray(this.currentTransform.unprojectBasic([newCenterX, newCenterY], this._lookatDepth));
- }
- setCenter(center) {
- this._desiredLookat = null;
- this._requestedRotationDelta = null;
- this._requestedBasicRotation = null;
- this._desiredZoom = this._zoom;
- let clamped = [
- this._spatial.clamp(center[0], 0, 1),
- this._spatial.clamp(center[1], 0, 1),
- ];
- if (this._currentImage == null) {
- this._desiredCenter = clamped;
- return;
- }
- this._desiredCenter = null;
- let currentLookat = new Vector3()
- .fromArray(this.currentTransform.unprojectBasic(clamped, this._lookatDepth));
- let previousTransform = this.previousTransform != null ?
- this.previousTransform :
- this.currentTransform;
- let previousLookat = new Vector3()
- .fromArray(previousTransform.unprojectBasic(clamped, this._lookatDepth));
- this._currentCamera.lookat.copy(currentLookat);
- this._previousCamera.lookat.copy(previousLookat);
- }
- setZoom(zoom) {
- this._desiredLookat = null;
- this._requestedRotationDelta = null;
- this._requestedBasicRotation = null;
- this._zoom = this._spatial.clamp(zoom, this._minZoom, this._maxZoom);
- this._desiredZoom = this._zoom;
- }
- _applyRotation(delta, camera) {
- if (camera == null) {
- return;
- }
- let q = new Quaternion().setFromUnitVectors(camera.up, new Vector3(0, 0, 1));
- let qInverse = q.clone().invert();
- let offset = new Vector3();
- offset.copy(camera.lookat).sub(camera.position);
- offset.applyQuaternion(q);
- let length = offset.length();
- let phi = Math.atan2(offset.y, offset.x);
- phi += delta.phi;
- let theta = Math.atan2(Math.sqrt(offset.x * offset.x + offset.y * offset.y), offset.z);
- theta += delta.theta;
- theta = Math.max(0.1, Math.min(Math.PI - 0.1, theta));
- offset.x = Math.sin(theta) * Math.cos(phi);
- offset.y = Math.sin(theta) * Math.sin(phi);
- offset.z = Math.cos(theta);
- offset.applyQuaternion(qInverse);
- camera.lookat.copy(camera.position).add(offset.multiplyScalar(length));
- }
- _applyRotationBasic(basicRotation) {
- let currentImage = this._currentImage;
- let previousImage = this._previousImage != null ?
- this.previousImage :
- this.currentImage;
- let currentCamera = this._currentCamera;
- let previousCamera = this._previousCamera;
- let currentTransform = this.currentTransform;
- let previousTransform = this.previousTransform != null ?
- this.previousTransform :
- this.currentTransform;
- let currentBasic = currentTransform.projectBasic(currentCamera.lookat.toArray());
- let previousBasic = previousTransform.projectBasic(previousCamera.lookat.toArray());
- if (isSpherical(currentImage.cameraType)) {
- currentBasic[0] = this._spatial.wrap(currentBasic[0] + basicRotation[0], 0, 1);
- currentBasic[1] = this._spatial.clamp(currentBasic[1] + basicRotation[1], 0.05, 0.95);
- }
- else {
- currentBasic[0] = this._spatial.clamp(currentBasic[0] + basicRotation[0], 0, 1);
- currentBasic[1] = this._spatial.clamp(currentBasic[1] + basicRotation[1], 0, 1);
- }
- if (isSpherical(previousImage.cameraType)) {
- previousBasic[0] = this._spatial.wrap(previousBasic[0] + basicRotation[0], 0, 1);
- previousBasic[1] = this._spatial.clamp(previousBasic[1] + basicRotation[1], 0.05, 0.95);
- }
- else {
- previousBasic[0] = this._spatial.clamp(previousBasic[0] + basicRotation[0], 0, 1);
- previousBasic[1] = this._spatial.clamp(currentBasic[1] + basicRotation[1], 0, 1);
- }
- let currentLookat = currentTransform.unprojectBasic(currentBasic, this._lookatDepth);
- currentCamera.lookat.fromArray(currentLookat);
- let previousLookat = previousTransform.unprojectBasic(previousBasic, this._lookatDepth);
- previousCamera.lookat.fromArray(previousLookat);
- }
- _updateZoom(animationSpeed) {
- let diff = this._desiredZoom - this._zoom;
- let sign = diff > 0 ? 1 : diff < 0 ? -1 : 0;
- if (diff === 0) {
- return;
- }
- else if (Math.abs(diff) < 2e-3) {
- this._zoom = this._desiredZoom;
- if (this._desiredLookat != null) {
- this._desiredLookat = null;
- }
- }
- else {
- this._zoom += sign * Math.max(Math.abs(5 * animationSpeed * diff), 2e-3);
- }
- }
- _updateLookat(animationSpeed) {
- if (this._desiredLookat === null) {
- return;
- }
- let diff = this._desiredLookat.distanceToSquared(this._currentCamera.lookat);
- if (Math.abs(diff) < 1e-6) {
- this._currentCamera.lookat.copy(this._desiredLookat);
- this._desiredLookat = null;
- }
- else {
- this._currentCamera.lookat.lerp(this._desiredLookat, 5 * animationSpeed);
- }
- }
- _updateRotation() {
- if (this._requestedRotationDelta != null) {
- let length = this._rotationDelta.lengthSquared();
- let requestedLength = this._requestedRotationDelta.lengthSquared();
- if (requestedLength > length) {
- this._rotationDelta.lerp(this._requestedRotationDelta, this._rotationIncreaseAlpha);
- }
- else {
- this._rotationDelta.lerp(this._requestedRotationDelta, this._rotationDecreaseAlpha);
- }
- this._requestedRotationDelta = null;
- return;
- }
- if (this._rotationDelta.isZero) {
- return;
- }
- const alpha = isSpherical(this.currentImage.cameraType) ?
- 1 : this._alpha;
- this._rotationDelta.multiply(this._rotationAcceleration * alpha);
- this._rotationDelta.threshold(this._rotationThreshold);
- }
- _updateRotationBasic() {
- if (this._requestedBasicRotation != null) {
- let x = this._basicRotation[0];
- let y = this._basicRotation[1];
- let reqX = this._requestedBasicRotation[0];
- let reqY = this._requestedBasicRotation[1];
- if (Math.abs(reqX) > Math.abs(x)) {
- this._basicRotation[0] = (1 - this._rotationIncreaseAlpha) * x + this._rotationIncreaseAlpha * reqX;
- }
- else {
- this._basicRotation[0] = (1 - this._rotationDecreaseAlpha) * x + this._rotationDecreaseAlpha * reqX;
- }
- if (Math.abs(reqY) > Math.abs(y)) {
- this._basicRotation[1] = (1 - this._rotationIncreaseAlpha) * y + this._rotationIncreaseAlpha * reqY;
- }
- else {
- this._basicRotation[1] = (1 - this._rotationDecreaseAlpha) * y + this._rotationDecreaseAlpha * reqY;
- }
- this._requestedBasicRotation = null;
- return;
- }
- if (this._requestedBasicRotationUnbounded != null) {
- let reqX = this._requestedBasicRotationUnbounded[0];
- let reqY = this._requestedBasicRotationUnbounded[1];
- if (Math.abs(reqX) > 0) {
- this._basicRotation[0] = (1 - this._unboundedRotationAlpha) * this._basicRotation[0] + this._unboundedRotationAlpha * reqX;
- }
- if (Math.abs(reqY) > 0) {
- this._basicRotation[1] = (1 - this._unboundedRotationAlpha) * this._basicRotation[1] + this._unboundedRotationAlpha * reqY;
- }
- if (this._desiredLookat != null) {
- let desiredBasicLookat = this.currentTransform.projectBasic(this._desiredLookat.toArray());
- desiredBasicLookat[0] += reqX;
- desiredBasicLookat[1] += reqY;
- this._desiredLookat = new Vector3()
- .fromArray(this.currentTransform.unprojectBasic(desiredBasicLookat, this._lookatDepth));
- }
- this._requestedBasicRotationUnbounded = null;
- }
- if (this._basicRotation[0] === 0 && this._basicRotation[1] === 0) {
- return;
- }
- this._basicRotation[0] = this._rotationAcceleration * this._basicRotation[0];
- this._basicRotation[1] = this._rotationAcceleration * this._basicRotation[1];
- if (Math.abs(this._basicRotation[0]) < this._rotationThreshold / Math.pow(2, this._zoom) &&
- Math.abs(this._basicRotation[1]) < this._rotationThreshold / Math.pow(2, this._zoom)) {
- this._basicRotation = [0, 0];
- }
- }
- _clearRotation() {
- if (isSpherical(this._currentImage.cameraType)) {
- return;
- }
- if (this._requestedRotationDelta != null) {
- this._requestedRotationDelta = null;
- }
- if (!this._rotationDelta.isZero) {
- this._rotationDelta.reset();
- }
- if (this._requestedBasicRotation != null) {
- this._requestedBasicRotation = null;
- }
- if (this._basicRotation[0] > 0 || this._basicRotation[1] > 0) {
- this._basicRotation = [0, 0];
- }
- }
- _setDesiredCenter() {
- if (this._desiredCenter == null) {
- return;
- }
- let lookatDirection = new Vector3()
- .fromArray(this.currentTransform.unprojectBasic(this._desiredCenter, this._lookatDepth))
- .sub(this._currentCamera.position);
- this._currentCamera.lookat.copy(this._currentCamera.position.clone().add(lookatDirection));
- this._previousCamera.lookat.copy(this._previousCamera.position.clone().add(lookatDirection));
- this._desiredCenter = null;
- }
- _setDesiredZoom() {
- this._desiredZoom =
- isSpherical(this._currentImage.cameraType) ||
- this._previousImage == null ?
- this._zoom : 0;
- }
- }
-
- class TraversingState extends InteractiveStateBase {
- constructor(state) {
- super(state);
- this._adjustCameras();
- this._motionless = this._motionlessTransition();
- this._baseAlpha = this._alpha;
- this._speedCoefficient = 1;
- this._unitBezier =
- new TraversingState._interpolator(0.74, 0.67, 0.38, 0.96);
- this._useBezier = false;
- }
- static register(interpolator) {
- TraversingState._interpolator = interpolator;
- }
- append(images) {
- let emptyTrajectory = this._trajectory.length === 0;
- if (emptyTrajectory) {
- this._resetTransition();
- }
- super.append(images);
- if (emptyTrajectory) {
- this._setDesiredCenter();
- this._setDesiredZoom();
- }
- }
- prepend(images) {
- let emptyTrajectory = this._trajectory.length === 0;
- if (emptyTrajectory) {
- this._resetTransition();
- }
- super.prepend(images);
- if (emptyTrajectory) {
- this._setDesiredCenter();
- this._setDesiredZoom();
- }
- }
- set(images) {
- super.set(images);
- this._desiredLookat = null;
- this._resetTransition();
- this._clearRotation();
- this._setDesiredCenter();
- this._setDesiredZoom();
- if (this._trajectory.length < 3) {
- this._useBezier = true;
- }
- }
- setSpeed(speed) {
- this._speedCoefficient = this._spatial.clamp(speed, 0, 10);
- }
- update(fps) {
- if (this._alpha === 1 && this._currentIndex + this._alpha < this._trajectory.length) {
- this._currentIndex += 1;
- this._useBezier = this._trajectory.length < 3 &&
- this._currentIndex + 1 === this._trajectory.length;
- this._setCurrent();
- this._resetTransition();
- this._clearRotation();
- this._desiredZoom =
- isSpherical(this._currentImage.cameraType) ?
- this._zoom : 0;
- this._desiredLookat = null;
- }
- let animationSpeed = this._animationSpeed * (60 / fps);
- this._baseAlpha = Math.min(1, this._baseAlpha + this._speedCoefficient * animationSpeed);
- if (this._useBezier) {
- this._alpha = this._unitBezier.solve(this._baseAlpha);
- }
- else {
- this._alpha = this._baseAlpha;
- }
- this._updateRotation();
- if (!this._rotationDelta.isZero) {
- this._applyRotation(this._rotationDelta, this._previousCamera);
- this._applyRotation(this._rotationDelta, this._currentCamera);
- }
- this._updateRotationBasic();
- if (this._basicRotation[0] !== 0 || this._basicRotation[1] !== 0) {
- this._applyRotationBasic(this._basicRotation);
- }
- this._updateZoom(animationSpeed);
- this._updateLookat(animationSpeed);
- this._camera.lerpCameras(this._previousCamera, this._currentCamera, this.alpha);
- }
- _getAlpha() {
- return this._motionless ? Math.ceil(this._alpha) : this._alpha;
- }
- _setCurrentCamera() {
- super._setCurrentCamera();
- this._adjustCameras();
- }
- _adjustCameras() {
- if (this._previousImage == null) {
- return;
- }
- let lookat = this._camera.lookat.clone().sub(this._camera.position);
- this._previousCamera.lookat.copy(lookat.clone().add(this._previousCamera.position));
- if (isSpherical(this._currentImage.cameraType)) {
- this._currentCamera.lookat.copy(lookat.clone().add(this._currentCamera.position));
- }
- }
- _resetTransition() {
- this._alpha = 0;
- this._baseAlpha = 0;
- this._motionless = this._motionlessTransition();
- }
- }
-
- class ComponentService {
- constructor(container, navigator) {
- this._components = {};
- for (const componentName in ComponentService.registeredComponents) {
- if (!ComponentService.registeredComponents.hasOwnProperty(componentName)) {
- continue;
- }
- const component = ComponentService.registeredComponents[componentName];
- this._components[componentName] = {
- active: false,
- component: new component(componentName, container, navigator),
- };
- }
- this._coverComponent = new ComponentService.registeredCoverComponent("cover", container, navigator);
- this._coverComponent.activate();
- this._coverActivated = true;
- }
- static register(component) {
- if (ComponentService.registeredComponents[component.componentName] === undefined) {
- ComponentService.registeredComponents[component.componentName] = component;
- }
- }
- static registerCover(coverComponent) {
- ComponentService.registeredCoverComponent = coverComponent;
- }
- get coverActivated() {
- return this._coverActivated;
- }
- activateCover() {
- if (this._coverActivated) {
- return;
- }
- this._coverActivated = true;
- for (const componentName in this._components) {
- if (!this._components.hasOwnProperty(componentName)) {
- continue;
- }
- const component = this._components[componentName];
- if (component.active) {
- component.component.deactivate();
- }
- }
- }
- deactivateCover() {
- if (!this._coverActivated) {
- return;
- }
- this._coverActivated = false;
- for (const componentName in this._components) {
- if (!this._components.hasOwnProperty(componentName)) {
- continue;
- }
- const component = this._components[componentName];
- if (component.active) {
- component.component.activate();
- }
- }
- }
- activate(name) {
- this._checkName(name);
- this._components[name].active = true;
- if (!this._coverActivated) {
- this.get(name).activate();
- }
- }
- configure(name, conf) {
- this._checkName(name);
- this.get(name).configure(conf);
- }
- deactivate(name) {
- this._checkName(name);
- this._components[name].active = false;
- if (!this._coverActivated) {
- this.get(name).deactivate();
- }
- }
- get(name) {
- return this._components[name].component;
- }
- getCover() {
- return this._coverComponent;
- }
- remove() {
- this._coverComponent.deactivate();
- for (const componentName in this._components) {
- if (!this._components.hasOwnProperty(componentName)) {
- continue;
- }
- this._components[componentName].component.deactivate();
- }
- }
- _checkName(name) {
- if (!(name in this._components)) {
- throw new ArgumentMapillaryError(`Component does not exist: ${name}`);
- }
- }
- }
- ComponentService.registeredComponents = {};
-
- var nativeIsArray = Array.isArray;
- var toString$2 = Object.prototype.toString;
-
- var xIsArray = nativeIsArray || isArray;
-
- function isArray(obj) {
- return toString$2.call(obj) === "[object Array]"
- }
-
- var version = "2";
-
- VirtualPatch.NONE = 0;
- VirtualPatch.VTEXT = 1;
- VirtualPatch.VNODE = 2;
- VirtualPatch.WIDGET = 3;
- VirtualPatch.PROPS = 4;
- VirtualPatch.ORDER = 5;
- VirtualPatch.INSERT = 6;
- VirtualPatch.REMOVE = 7;
- VirtualPatch.THUNK = 8;
-
- var vpatch = VirtualPatch;
-
- function VirtualPatch(type, vNode, patch) {
- this.type = Number(type);
- this.vNode = vNode;
- this.patch = patch;
- }
-
- VirtualPatch.prototype.version = version;
- VirtualPatch.prototype.type = "VirtualPatch";
-
- var isVnode = isVirtualNode;
-
- function isVirtualNode(x) {
- return x && x.type === "VirtualNode" && x.version === version
- }
-
- var isVtext = isVirtualText;
-
- function isVirtualText(x) {
- return x && x.type === "VirtualText" && x.version === version
- }
-
- var isWidget_1 = isWidget;
-
- function isWidget(w) {
- return w && w.type === "Widget"
- }
-
- var isThunk_1 = isThunk;
-
- function isThunk(t) {
- return t && t.type === "Thunk"
- }
-
- var handleThunk_1 = handleThunk;
-
- function handleThunk(a, b) {
- var renderedA = a;
- var renderedB = b;
-
- if (isThunk_1(b)) {
- renderedB = renderThunk(b, a);
- }
-
- if (isThunk_1(a)) {
- renderedA = renderThunk(a, null);
- }
-
- return {
- a: renderedA,
- b: renderedB
- }
- }
-
- function renderThunk(thunk, previous) {
- var renderedThunk = thunk.vnode;
-
- if (!renderedThunk) {
- renderedThunk = thunk.vnode = thunk.render(previous);
- }
-
- if (!(isVnode(renderedThunk) ||
- isVtext(renderedThunk) ||
- isWidget_1(renderedThunk))) {
- throw new Error("thunk did not return a valid node");
- }
-
- return renderedThunk
- }
-
- var isObject = function isObject(x) {
- return typeof x === 'object' && x !== null;
- };
-
- var isVhook = isHook;
-
- function isHook(hook) {
- return hook &&
- (typeof hook.hook === "function" && !hook.hasOwnProperty("hook") ||
- typeof hook.unhook === "function" && !hook.hasOwnProperty("unhook"))
- }
-
- var diffProps_1 = diffProps;
-
- function diffProps(a, b) {
- var diff;
-
- for (var aKey in a) {
- if (!(aKey in b)) {
- diff = diff || {};
- diff[aKey] = undefined;
- }
-
- var aValue = a[aKey];
- var bValue = b[aKey];
-
- if (aValue === bValue) {
- continue
- } else if (isObject(aValue) && isObject(bValue)) {
- if (getPrototype$1(bValue) !== getPrototype$1(aValue)) {
- diff = diff || {};
- diff[aKey] = bValue;
- } else if (isVhook(bValue)) {
- diff = diff || {};
- diff[aKey] = bValue;
- } else {
- var objectDiff = diffProps(aValue, bValue);
- if (objectDiff) {
- diff = diff || {};
- diff[aKey] = objectDiff;
- }
- }
- } else {
- diff = diff || {};
- diff[aKey] = bValue;
- }
- }
-
- for (var bKey in b) {
- if (!(bKey in a)) {
- diff = diff || {};
- diff[bKey] = b[bKey];
- }
- }
-
- return diff
- }
-
- function getPrototype$1(value) {
- if (Object.getPrototypeOf) {
- return Object.getPrototypeOf(value)
- } else if (value.__proto__) {
- return value.__proto__
- } else if (value.constructor) {
- return value.constructor.prototype
- }
- }
-
- var diff_1$1 = diff;
-
- function diff(a, b) {
- var patch = { a: a };
- walk(a, b, patch, 0);
- return patch
- }
-
- function walk(a, b, patch, index) {
- if (a === b) {
- return
- }
-
- var apply = patch[index];
- var applyClear = false;
-
- if (isThunk_1(a) || isThunk_1(b)) {
- thunks(a, b, patch, index);
- } else if (b == null) {
-
- // If a is a widget we will add a remove patch for it
- // Otherwise any child widgets/hooks must be destroyed.
- // This prevents adding two remove patches for a widget.
- if (!isWidget_1(a)) {
- clearState(a, patch, index);
- apply = patch[index];
- }
-
- apply = appendPatch(apply, new vpatch(vpatch.REMOVE, a, b));
- } else if (isVnode(b)) {
- if (isVnode(a)) {
- if (a.tagName === b.tagName &&
- a.namespace === b.namespace &&
- a.key === b.key) {
- var propsPatch = diffProps_1(a.properties, b.properties);
- if (propsPatch) {
- apply = appendPatch(apply,
- new vpatch(vpatch.PROPS, a, propsPatch));
- }
- apply = diffChildren(a, b, patch, apply, index);
- } else {
- apply = appendPatch(apply, new vpatch(vpatch.VNODE, a, b));
- applyClear = true;
- }
- } else {
- apply = appendPatch(apply, new vpatch(vpatch.VNODE, a, b));
- applyClear = true;
- }
- } else if (isVtext(b)) {
- if (!isVtext(a)) {
- apply = appendPatch(apply, new vpatch(vpatch.VTEXT, a, b));
- applyClear = true;
- } else if (a.text !== b.text) {
- apply = appendPatch(apply, new vpatch(vpatch.VTEXT, a, b));
- }
- } else if (isWidget_1(b)) {
- if (!isWidget_1(a)) {
- applyClear = true;
- }
-
- apply = appendPatch(apply, new vpatch(vpatch.WIDGET, a, b));
- }
-
- if (apply) {
- patch[index] = apply;
- }
-
- if (applyClear) {
- clearState(a, patch, index);
- }
- }
-
- function diffChildren(a, b, patch, apply, index) {
- var aChildren = a.children;
- var orderedSet = reorder(aChildren, b.children);
- var bChildren = orderedSet.children;
-
- var aLen = aChildren.length;
- var bLen = bChildren.length;
- var len = aLen > bLen ? aLen : bLen;
-
- for (var i = 0; i < len; i++) {
- var leftNode = aChildren[i];
- var rightNode = bChildren[i];
- index += 1;
-
- if (!leftNode) {
- if (rightNode) {
- // Excess nodes in b need to be added
- apply = appendPatch(apply,
- new vpatch(vpatch.INSERT, null, rightNode));
- }
- } else {
- walk(leftNode, rightNode, patch, index);
- }
-
- if (isVnode(leftNode) && leftNode.count) {
- index += leftNode.count;
- }
- }
-
- if (orderedSet.moves) {
- // Reorder nodes last
- apply = appendPatch(apply, new vpatch(
- vpatch.ORDER,
- a,
- orderedSet.moves
- ));
- }
-
- return apply
- }
-
- function clearState(vNode, patch, index) {
- // TODO: Make this a single walk, not two
- unhook(vNode, patch, index);
- destroyWidgets(vNode, patch, index);
- }
-
- // Patch records for all destroyed widgets must be added because we need
- // a DOM node reference for the destroy function
- function destroyWidgets(vNode, patch, index) {
- if (isWidget_1(vNode)) {
- if (typeof vNode.destroy === "function") {
- patch[index] = appendPatch(
- patch[index],
- new vpatch(vpatch.REMOVE, vNode, null)
- );
- }
- } else if (isVnode(vNode) && (vNode.hasWidgets || vNode.hasThunks)) {
- var children = vNode.children;
- var len = children.length;
- for (var i = 0; i < len; i++) {
- var child = children[i];
- index += 1;
-
- destroyWidgets(child, patch, index);
-
- if (isVnode(child) && child.count) {
- index += child.count;
- }
- }
- } else if (isThunk_1(vNode)) {
- thunks(vNode, null, patch, index);
- }
- }
-
- // Create a sub-patch for thunks
- function thunks(a, b, patch, index) {
- var nodes = handleThunk_1(a, b);
- var thunkPatch = diff(nodes.a, nodes.b);
- if (hasPatches(thunkPatch)) {
- patch[index] = new vpatch(vpatch.THUNK, null, thunkPatch);
- }
- }
-
- function hasPatches(patch) {
- for (var index in patch) {
- if (index !== "a") {
- return true
- }
- }
-
- return false
- }
-
- // Execute hooks when two nodes are identical
- function unhook(vNode, patch, index) {
- if (isVnode(vNode)) {
- if (vNode.hooks) {
- patch[index] = appendPatch(
- patch[index],
- new vpatch(
- vpatch.PROPS,
- vNode,
- undefinedKeys(vNode.hooks)
- )
- );
- }
-
- if (vNode.descendantHooks || vNode.hasThunks) {
- var children = vNode.children;
- var len = children.length;
- for (var i = 0; i < len; i++) {
- var child = children[i];
- index += 1;
-
- unhook(child, patch, index);
-
- if (isVnode(child) && child.count) {
- index += child.count;
- }
- }
- }
- } else if (isThunk_1(vNode)) {
- thunks(vNode, null, patch, index);
- }
- }
-
- function undefinedKeys(obj) {
- var result = {};
-
- for (var key in obj) {
- result[key] = undefined;
- }
-
- return result
- }
-
- // List diff, naive left to right reordering
- function reorder(aChildren, bChildren) {
- // O(M) time, O(M) memory
- var bChildIndex = keyIndex(bChildren);
- var bKeys = bChildIndex.keys;
- var bFree = bChildIndex.free;
-
- if (bFree.length === bChildren.length) {
- return {
- children: bChildren,
- moves: null
- }
- }
-
- // O(N) time, O(N) memory
- var aChildIndex = keyIndex(aChildren);
- var aKeys = aChildIndex.keys;
- var aFree = aChildIndex.free;
-
- if (aFree.length === aChildren.length) {
- return {
- children: bChildren,
- moves: null
- }
- }
-
- // O(MAX(N, M)) memory
- var newChildren = [];
-
- var freeIndex = 0;
- var freeCount = bFree.length;
- var deletedItems = 0;
-
- // Iterate through a and match a node in b
- // O(N) time,
- for (var i = 0 ; i < aChildren.length; i++) {
- var aItem = aChildren[i];
- var itemIndex;
-
- if (aItem.key) {
- if (bKeys.hasOwnProperty(aItem.key)) {
- // Match up the old keys
- itemIndex = bKeys[aItem.key];
- newChildren.push(bChildren[itemIndex]);
-
- } else {
- // Remove old keyed items
- itemIndex = i - deletedItems++;
- newChildren.push(null);
- }
- } else {
- // Match the item in a with the next free item in b
- if (freeIndex < freeCount) {
- itemIndex = bFree[freeIndex++];
- newChildren.push(bChildren[itemIndex]);
- } else {
- // There are no free items in b to match with
- // the free items in a, so the extra free nodes
- // are deleted.
- itemIndex = i - deletedItems++;
- newChildren.push(null);
- }
- }
- }
-
- var lastFreeIndex = freeIndex >= bFree.length ?
- bChildren.length :
- bFree[freeIndex];
-
- // Iterate through b and append any new keys
- // O(M) time
- for (var j = 0; j < bChildren.length; j++) {
- var newItem = bChildren[j];
-
- if (newItem.key) {
- if (!aKeys.hasOwnProperty(newItem.key)) {
- // Add any new keyed items
- // We are adding new items to the end and then sorting them
- // in place. In future we should insert new items in place.
- newChildren.push(newItem);
- }
- } else if (j >= lastFreeIndex) {
- // Add any leftover non-keyed items
- newChildren.push(newItem);
- }
- }
-
- var simulate = newChildren.slice();
- var simulateIndex = 0;
- var removes = [];
- var inserts = [];
- var simulateItem;
-
- for (var k = 0; k < bChildren.length;) {
- var wantedItem = bChildren[k];
- simulateItem = simulate[simulateIndex];
-
- // remove items
- while (simulateItem === null && simulate.length) {
- removes.push(remove(simulate, simulateIndex, null));
- simulateItem = simulate[simulateIndex];
- }
-
- if (!simulateItem || simulateItem.key !== wantedItem.key) {
- // if we need a key in this position...
- if (wantedItem.key) {
- if (simulateItem && simulateItem.key) {
- // if an insert doesn't put this key in place, it needs to move
- if (bKeys[simulateItem.key] !== k + 1) {
- removes.push(remove(simulate, simulateIndex, simulateItem.key));
- simulateItem = simulate[simulateIndex];
- // if the remove didn't put the wanted item in place, we need to insert it
- if (!simulateItem || simulateItem.key !== wantedItem.key) {
- inserts.push({key: wantedItem.key, to: k});
- }
- // items are matching, so skip ahead
- else {
- simulateIndex++;
- }
- }
- else {
- inserts.push({key: wantedItem.key, to: k});
- }
- }
- else {
- inserts.push({key: wantedItem.key, to: k});
- }
- k++;
- }
- // a key in simulate has no matching wanted key, remove it
- else if (simulateItem && simulateItem.key) {
- removes.push(remove(simulate, simulateIndex, simulateItem.key));
- }
- }
- else {
- simulateIndex++;
- k++;
- }
- }
-
- // remove all the remaining nodes from simulate
- while(simulateIndex < simulate.length) {
- simulateItem = simulate[simulateIndex];
- removes.push(remove(simulate, simulateIndex, simulateItem && simulateItem.key));
- }
-
- // If the only moves we have are deletes then we can just
- // let the delete patch remove these items.
- if (removes.length === deletedItems && !inserts.length) {
- return {
- children: newChildren,
- moves: null
- }
- }
-
- return {
- children: newChildren,
- moves: {
- removes: removes,
- inserts: inserts
- }
- }
- }
-
- function remove(arr, index, key) {
- arr.splice(index, 1);
-
- return {
- from: index,
- key: key
- }
- }
-
- function keyIndex(children) {
- var keys = {};
- var free = [];
- var length = children.length;
-
- for (var i = 0; i < length; i++) {
- var child = children[i];
-
- if (child.key) {
- keys[child.key] = i;
- } else {
- free.push(i);
- }
- }
-
- return {
- keys: keys, // A hash of key name to index
- free: free // An array of unkeyed item indices