@deck.gl/core
Version:
deck.gl core library
80 lines • 3.54 kB
JavaScript
// deck.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
import Viewport from "../viewports/viewport.js";
import { Matrix4 } from '@math.gl/core';
import { pixelsToWorld, fovyToAltitude } from '@math.gl/web-mercator';
const DEGREES_TO_RADIANS = Math.PI / 180;
function getViewMatrix({ height, focalDistance, orbitAxis, rotationX, rotationOrbit, zoom }) {
// We position the camera so that one common space unit (world space unit scaled by zoom)
// at the target maps to one screen pixel.
// This is a similar technique to that used in web mercator projection
// By doing so we are able to convert between common space and screen space sizes efficiently
// in the vertex shader.
const up = orbitAxis === 'Z' ? [0, 0, 1] : [0, 1, 0];
const eye = orbitAxis === 'Z' ? [0, -focalDistance, 0] : [0, 0, focalDistance];
const viewMatrix = new Matrix4().lookAt({ eye, up });
viewMatrix.rotateX(rotationX * DEGREES_TO_RADIANS);
if (orbitAxis === 'Z') {
viewMatrix.rotateZ(rotationOrbit * DEGREES_TO_RADIANS);
}
else {
viewMatrix.rotateY(rotationOrbit * DEGREES_TO_RADIANS);
}
// When height increases, we need to increase the distance from the camera to the target to
// keep the 1:1 mapping. However, this also changes the projected depth of each position by
// moving them further away between the near/far plane.
// Without modifying the default near/far planes, we instead scale down the common space to
// remove the distortion to the depth field.
const projectionScale = Math.pow(2, zoom) / height;
viewMatrix.scale(projectionScale);
return viewMatrix;
}
export default class OrbitViewport extends Viewport {
constructor(props) {
const { height, projectionMatrix, fovy = 50, // For setting camera position
orbitAxis = 'Z', // Orbit axis with 360 degrees rotating freedom, can only be 'Y' or 'Z'
target = [0, 0, 0], // Which point is camera looking at, default origin
rotationX = 0, // Rotating angle around X axis
rotationOrbit = 0, // Rotating angle around orbit axis
zoom = 0 } = props;
const focalDistance = projectionMatrix ? projectionMatrix[5] / 2 : fovyToAltitude(fovy);
super({
...props,
// in case viewState contains longitude/latitude values,
// make sure that the base Viewport class does not treat this as a geospatial viewport
longitude: undefined,
viewMatrix: getViewMatrix({
height: height || 1,
focalDistance,
orbitAxis,
rotationX,
rotationOrbit,
zoom
}),
fovy,
focalDistance,
position: target,
zoom
});
this.projectedCenter = this.project(this.center);
}
unproject(xyz, { topLeft = true } = {}) {
const [x, y, z = this.projectedCenter[2]] = xyz;
const y2 = topLeft ? y : this.height - y;
const [X, Y, Z] = pixelsToWorld([x, y2, z], this.pixelUnprojectionMatrix);
return [X, Y, Z];
}
panByPosition(coords, pixel) {
const p0 = this.project(coords);
const nextCenter = [
this.width / 2 + p0[0] - pixel[0],
this.height / 2 + p0[1] - pixel[1],
this.projectedCenter[2]
];
return {
target: this.unproject(nextCenter)
};
}
}
//# sourceMappingURL=orbit-viewport.js.map