UNPKG

terriajs

Version:

Geospatial data visualization platform.

340 lines (303 loc) 9.74 kB
import { action, computed, makeObservable, observable, runInAction } from "mobx"; import ImageryLayerFeatureInfo from "terriajs-cesium/Source/Scene/ImageryLayerFeatureInfo"; import ImageryProvider from "terriajs-cesium/Source/Scene/ImageryProvider"; import WebMapServiceImageryProvider from "terriajs-cesium/Source/Scene/WebMapServiceImageryProvider"; import { DiscreteTimeAsJS } from "../../lib/ModelMixins/DiscretelyTimeVaryingMixin"; import MappableMixin from "../../lib/ModelMixins/MappableMixin"; import TimeFilterMixin from "../../lib/ModelMixins/TimeFilterMixin"; import CommonStrata from "../../lib/Models/Definition/CommonStrata"; import CreateModel from "../../lib/Models/Definition/CreateModel"; import { ModelConstructorParameters } from "../../lib/Models/Definition/Model"; import Terria from "../../lib/Models/Terria"; import mixTraits from "../../lib/Traits/mixTraits"; import TimeFilterTraits from "../../lib/Traits/TraitsClasses/TimeFilterTraits"; describe("TimeFilterMixin", function () { let terria: Terria; beforeEach(function () { terria = new Terria(); }); describe("canFilterTimeByFeature", function () { it( "returns false if timeFilterPropertyName is not set", action(function () { const testItem = new TestTimeFilterableItem("test", terria); expect(testItem.canFilterTimeByFeature).toBe(false); }) ); it( "returns true if timeFilterPropertyName is set", action(function () { const testItem = new TestTimeFilterableItem("test", terria); testItem.setTrait( CommonStrata.user, "timeFilterPropertyName", "filter-dates" ); expect(testItem.canFilterTimeByFeature).toBe(true); }) ); }); describe("setTimeFilterFromLocation", function () { let item: TestTimeFilterableItem; let imageryProvider: ImageryProvider; beforeEach(function () { item = new TestTimeFilterableItem("test", terria); item.setTrait( CommonStrata.user, "timeFilterPropertyName", "availabilityAtLocation" ); imageryProvider = new WebMapServiceImageryProvider({ url: "test", layers: "testlayer" }); item.imageryProviders = [imageryProvider]; const fullAvailability = [ "2023-01-01", "2023-01-02", "2023-01-03", "2023-01-04", "2023-01-05" ]; item.discreteTimes = fullAvailability.map((time) => ({ time, tag: undefined })); }); it( "loads the filter with dates available for the given location and updates the timeFilterCoordinates traits", action(async function () { // Set filter property to provide 2 dates from the available set const fakeImageryFeature = new ImageryLayerFeatureInfo(); fakeImageryFeature.properties = { availabilityAtLocation: ["2023-01-02", "2023-01-03"] }; spyOn(imageryProvider, "pickFeatures").and.callFake(() => Promise.resolve([fakeImageryFeature]) ); await item.setTimeFilterFromLocation({ // Position to pick position: { // in degrees latitude: -37.831, longitude: 144.973 }, // Coordinates of the tiles tileCoords: { x: 1, y: 2, level: 3 } }); expect( runInAction(() => item.discreteTimesAsSortedJulianDates)?.map((dt) => dt.time.toString() ) ).toEqual(["2023-01-02T00:00:00Z", "2023-01-03T00:00:00Z"]); }) ); it("should correctly update the timeFilterCoordinates", async function () { // Set filter property to provide 2 dates from the available set const fakeImageryFeature = new ImageryLayerFeatureInfo(); fakeImageryFeature.properties = { availabilityAtLocation: ["2023-01-02", "2023-01-03"] }; spyOn(imageryProvider, "pickFeatures").and.callFake(() => Promise.resolve([fakeImageryFeature]) ); await item.setTimeFilterFromLocation({ // Position to pick position: { // in degrees latitude: -37.831, longitude: 144.973 }, // Coordinates of the tiles tileCoords: { x: 1, y: 2, level: 3 } }); const { tile: { x, y, level }, latitude, longitude, height } = runInAction(() => item.timeFilterCoordinates); expect({ x, y, level }).toEqual({ x: 1, y: 2, level: 3 }); expect({ latitude, longitude, height }).toEqual({ longitude: 144.973, latitude: -37.831, height: 0 }); }); describe("when there are multiple imageryProviders", function () { it("queries all of them", async function () { item.imageryProviders = [ new WebMapServiceImageryProvider({ url: "test1", layers: "layer1" }), new WebMapServiceImageryProvider({ url: "test2", layers: "layer2" }) ]; const spy0 = spyOn( item.imageryProviders[0], "pickFeatures" ).and.returnValue(undefined); const spy1 = spyOn( item.imageryProviders[1], "pickFeatures" ).and.returnValue(undefined); await item.setTimeFilterFromLocation({ // Position to pick position: { // in degrees latitude: -37.831, longitude: 144.973 }, // Coordinates of the tiles tileCoords: { x: 1, y: 2, level: 3 } }); expect(spy0).toHaveBeenCalledTimes(1); expect(spy1).toHaveBeenCalledTimes(1); }); it( "sets the time filter from the first imageryProvider that returns a valid pick result", action(async function () { item.imageryProviders = [ new WebMapServiceImageryProvider({ url: "test1", layers: "layer1" }), new WebMapServiceImageryProvider({ url: "test2", layers: "layer2" }) ]; const featureInfo1 = new ImageryLayerFeatureInfo(); featureInfo1.properties = { someprop: ["2023-01-01"] }; const featureInfo2 = new ImageryLayerFeatureInfo(); featureInfo2.properties = { timeprop: ["2023-01-04"] }; item.setTrait( CommonStrata.user, "timeFilterPropertyName", "timeprop" ); const spy0 = spyOn( item.imageryProviders[0], "pickFeatures" ).and.callFake(() => Promise.resolve([featureInfo1])); const spy1 = spyOn( item.imageryProviders[1], "pickFeatures" ).and.callFake(() => Promise.resolve([featureInfo2])); await item.setTimeFilterFromLocation({ // Position to pick position: { // in degrees latitude: -37.831, longitude: 144.973 }, // Coordinates of the tiles tileCoords: { x: 1, y: 2, level: 3 } }); expect(spy0).toHaveBeenCalledTimes(1); expect(spy1).toHaveBeenCalledTimes(1); expect( (item.discreteTimesAsSortedJulianDates ?? []).map((dt) => dt.time.toString() ) ).toEqual(["2023-01-04T00:00:00Z"]); }) ); }); it("passes the correct arguments when picking the imagery provider", async function () { const spy = spyOn(imageryProvider, "pickFeatures").and.returnValue( undefined ); await item.setTimeFilterFromLocation({ // Position to pick position: { // in degrees latitude: -37.831, longitude: 144.973 }, // Coordinates of the tiles tileCoords: { x: 1, y: 2, level: 3 } }); const [x, y, level, longitude, latitude] = spy.calls.mostRecent().args; expect([x, y, level]).toEqual([1, 2, 3]); expect(longitude).toBeCloseTo(2.5302); expect(latitude).toBeCloseTo(-0.6602); }); it("does nothing when terria.allowFeatureInfoRequests is set to `false`", async function () { const pickFeatures = spyOn( imageryProvider, "pickFeatures" ).and.returnValue(undefined); terria.allowFeatureInfoRequests = false; await item.setTimeFilterFromLocation({ // Position to pick position: { // in degrees latitude: -37.831, longitude: 144.973 }, // Coordinates of the tiles tileCoords: { x: 1, y: 2, level: 3 } }); expect(pickFeatures).not.toHaveBeenCalled(); }); }); }); class TestTimeFilterableItem extends TimeFilterMixin( MappableMixin(CreateModel(mixTraits(TimeFilterTraits))) ) { @observable discreteTimes: DiscreteTimeAsJS[] = []; @observable imageryProviders: ImageryProvider[] = []; constructor(...args: ModelConstructorParameters) { super(...args); makeObservable(this); } protected async forceLoadMapItems(): Promise<void> {} @computed get mapItems() { return this.imageryProviders.map((imageryProvider) => ({ imageryProvider, alpha: 1.0, show: true, clippingRectangle: imageryProvider.rectangle })); } }