diff --git a/modules/core/src/viewports/first-person-viewport.ts b/modules/core/src/viewports/first-person-viewport.ts index a60a71f76ef..79e0d8fb958 100644 --- a/modules/core/src/viewports/first-person-viewport.ts +++ b/modules/core/src/viewports/first-person-viewport.ts @@ -44,8 +44,13 @@ export type FirstPersonViewportOptions = { }; export default class FirstPersonViewport extends Viewport { + static displayName = 'FirstPersonViewport'; + longitude?: number; latitude?: number; + pitch: number; + bearing: number; + up: [number, number, number]; constructor(props: FirstPersonViewportOptions) { // TODO - push direction handling into Matrix4.lookAt @@ -75,5 +80,8 @@ export default class FirstPersonViewport extends Viewport { this.latitude = latitude; this.longitude = longitude; + this.pitch = pitch; + this.bearing = bearing; + this.up = up; } } diff --git a/modules/core/src/viewports/globe-viewport.ts b/modules/core/src/viewports/globe-viewport.ts index 6275ea1a148..5a064a09e06 100644 --- a/modules/core/src/viewports/globe-viewport.ts +++ b/modules/core/src/viewports/globe-viewport.ts @@ -67,9 +67,12 @@ export type GlobeViewportOptions = { }; export default class GlobeViewport extends Viewport { - longitude!: number; - latitude!: number; - resolution!: number; + static displayName = 'GlobeViewport'; + + longitude: number; + latitude: number; + fovy: number; + resolution: number; constructor(opts: GlobeViewportOptions = {}) { const { @@ -129,6 +132,7 @@ export default class GlobeViewport extends Viewport { this.scale = scale; this.latitude = latitude; this.longitude = longitude; + this.fovy = fovy; this.resolution = resolution; } diff --git a/modules/core/src/viewports/orbit-viewport.ts b/modules/core/src/viewports/orbit-viewport.ts index 333f6afaaf4..0e615c68d4a 100644 --- a/modules/core/src/viewports/orbit-viewport.ts +++ b/modules/core/src/viewports/orbit-viewport.ts @@ -86,7 +86,14 @@ export type OrbitViewportOptions = { }; export default class OrbitViewport extends Viewport { + static displayName = 'OrbitViewport'; + projectedCenter: number[]; + orbitAxis: 'Y' | 'Z'; + rotationOrbit: number; + rotationX: number; + target: [number, number, number]; + fovy: number; constructor(props: OrbitViewportOptions) { const { @@ -125,6 +132,11 @@ export default class OrbitViewport extends Viewport { zoom }); + this.target = target; + this.orbitAxis = orbitAxis; + this.rotationX = rotationX; + this.rotationOrbit = rotationOrbit; + this.fovy = fovy; this.projectedCenter = this.project(this.center); } diff --git a/modules/core/src/viewports/orthographic-viewport.ts b/modules/core/src/viewports/orthographic-viewport.ts index c97635c339a..bef4a6ff856 100644 --- a/modules/core/src/viewports/orthographic-viewport.ts +++ b/modules/core/src/viewports/orthographic-viewport.ts @@ -64,6 +64,10 @@ export type OrthographicViewportOptions = { /** The zoom level of the viewport. `zoom: 0` maps one unit distance to one pixel on screen, and increasing `zoom` by `1` scales the same object to twice as large. * To apply independent zoom levels to the X and Y axes, supply an array `[zoomX, zoomY]`. Default `0`. */ zoom?: number | [number, number]; + /** Independent zoom along the X axis. Overrides `zoom`. */ + zoomX?: number; + /** Independent zoom along the Y axis. Overrides `zoom`. */ + zoomY?: number; /** Padding around the viewport, in pixels. */ padding?: Padding | null; /** Distance of near clipping plane. Default `0.1`. */ @@ -75,6 +79,13 @@ export type OrthographicViewportOptions = { }; export default class OrthographicViewport extends Viewport { + static displayName = 'OrthographicViewport'; + + target: [number, number, number] | [number, number]; + zoomX: number; + zoomY: number; + flipY: boolean; + constructor(props: OrthographicViewportOptions) { const { width, @@ -86,8 +97,8 @@ export default class OrthographicViewport extends Viewport { padding = null, flipY = true } = props; - const zoomX = Array.isArray(zoom) ? zoom[0] : zoom; - const zoomY = Array.isArray(zoom) ? zoom[1] : zoom; + const zoomX = props.zoomX ?? (Array.isArray(zoom) ? zoom[0] : zoom); + const zoomY = props.zoomY ?? (Array.isArray(zoom) ? zoom[1] : zoom); const zoom_ = Math.min(zoomX, zoomY); const scale = Math.pow(2, zoom_); @@ -119,6 +130,11 @@ export default class OrthographicViewport extends Viewport { zoom: zoom_, distanceScales }); + + this.target = target; + this.zoomX = zoomX; + this.zoomY = zoomY; + this.flipY = flipY; } projectFlat([X, Y]: number[]): [number, number] { diff --git a/test/modules/core/viewports/conformance.spec.ts b/test/modules/core/viewports/conformance.spec.ts new file mode 100644 index 00000000000..1278ba39681 --- /dev/null +++ b/test/modules/core/viewports/conformance.spec.ts @@ -0,0 +1,94 @@ +import test from 'tape-promise/tape'; +import { + type Viewport, + WebMercatorViewport, + OrthographicViewport, + OrbitViewport, + _GlobeViewport as GlobeViewport, + FirstPersonViewport +} from '@deck.gl/core'; + +test('Viewport#recreate', t => { + const TEST_CASES = [ + new WebMercatorViewport({ + width: 100, + height: 100 + }), + new WebMercatorViewport({ + width: 400, + height: 300, + longitude: -122.4, + latitude: 37.8, + fovy: 50, + zoom: 12, + pitch: 24, + bearing: -160, + position: [0, 0, 2] + }), + new WebMercatorViewport({ + width: 400, + height: 300, + longitude: -122.4, + latitude: 37.8, + zoom: 12, + nearZ: 0.01, + farZMultiplier: 10 + }), + new OrbitViewport({ + width: 100, + height: 100 + }), + new OrbitViewport({ + width: 400, + height: 300, + target: [-10.24, 2833, 47.2], + orbitAxis: 'Y', + rotationX: 45, + rotationOrbit: -111, + zoom: -3, + fovy: 60 + }), + new OrthographicViewport({ + width: 100, + height: 100 + }), + new OrthographicViewport({ + width: 400, + height: 300, + target: [100, 500], + zoom: [1, -4], + flipY: false + }), + new GlobeViewport({ + width: 100, + height: 100 + }), + new GlobeViewport({ + width: 400, + height: 300, + longitude: -122.4, + latitude: 37.8, + fovy: 50, + zoom: 12 + }), + new FirstPersonViewport({ + width: 100, + height: 100 + }), + new FirstPersonViewport({ + width: 400, + height: 300, + longitude: -122.4, + latitude: 37.8, + pitch: 35, + bearing: -140, + focalDistance: 2 + }) + ]; + for (const viewport of TEST_CASES) { + const ViewportType = viewport.constructor as {new (props: unknown): Viewport}; + const clone = new ViewportType({...viewport}); + t.ok(viewport.equals(clone), String(viewport.id)); + } + t.end(); +}); diff --git a/test/modules/core/viewports/index.ts b/test/modules/core/viewports/index.ts index 5abc9a3b7a3..e29514a9d24 100644 --- a/test/modules/core/viewports/index.ts +++ b/test/modules/core/viewports/index.ts @@ -6,3 +6,4 @@ import './viewport.spec'; import './globe-viewport.spec'; import './web-mercator-project-unproject.spec'; import './web-mercator-viewport.spec'; +import './conformance.spec';