"use strict";
define(["underscore", "backbone", "models/maps/viewfinder/ZoomPresetModel"], (
_,
Backbone,
ZoomPresetModel,
) => {
// The LEO Network domain for zoom presets. This is used to determine if the
// presets are from the LEO Network and to use as the base URL for images.
const LEO_NEWTORK_DOMAIN = "leonetwork.org";
// Default height for zoom presets if not specified.
const DEFAULT_HEIGHT = 800;
/**
* Determine if array is empty.
* @param {Array} a The array in question.
* @returns {boolean} Whether the array is empty.
*/
function isNonEmptyArray(a) {
return a && a.length && Array.isArray(a);
}
/**
* Configuration options for preset map locations and enabled layers that
* will be shown in the viewfinder UI.
* @typedef {MapConfig#ZoomPreset[]|MapConfig#LeoNetworkZoomPresetConfig} MapConfig#ZoomPresets
* @since 2.35.0
*/
/**
* A configuration object for fetching zoom presets from the LEO Network.
* @typedef {object} MapConfig#LeoNetworkZoomPresetConfig
* @property {string} url The URL to fetch the GeoJSON of zoom presets from
* the LEO Network, e.g.
* `https://leonetwork.org/en/lists/geojson/A54B4AEA-21F9-4162-AEB7-AFE930C0D4E4`
* @property {string[]} [layerIds] An optional list of layer IDs to enable
* when a preset is selected. If not provided, the visible layers will not
* change when a preset is selected.
* @since 2.35.0
*/
/**
* Configuration options for a zoom preset in the MapConfig.
* @typedef {object} MapConfig#ZoomPreset
* @property {string} title The displayed title for the preset.
* @property {number} latitude The latitude of the preset location.
* @property {number} longitude The longitude of the preset location.
* @property {number} height The height of the preset location in meters.
* @property {string} description A brief description of the layers and
* location.
* @property {string[]} enabledLayerIds A list of layer IDs which are to be
* enabled for this preset. Must match the IDs of layers in the
* MapConfig#MapAssetConfig.
* @property {string[]} enabledLayerLabels A corresponding list of layer
* labels which are enabled for this preset.
* @property {string} [imageUrl] An optional URL to an image that represents
* this preset.
*/
/**
* @class ZoomPresets
* @classdesc A ZoomPresets collection is a group of ZoomPresetModel models
* that provide a location and list of layers to make visible when the user
* selects.
* @class ZoomPresets
* @classcategory Collections/Maps
* @augments Backbone.Collection
* @since 2.29.0
* @class
*/
const ZoomPresets = Backbone.Collection.extend(
/** @lends ZoomPresets.prototype */ {
/** @inheritdoc */
model: ZoomPresetModel,
/**
* Constructor for the ZoomPresets collection.
* @param {Array} _models The initial set of models to be added to the
* collection.
* @param {object} [options] Options for the collection.
* @param {MapModel} options.mapModel The map model that this collection
* is associated with.
*/
initialize(_models, options = {}) {
this.mapModel = options.mapModel;
},
/**
* Checks if this collection of presets is fetched from the LEO Network.
* @returns {boolean} True if there is a URL and it contains the LEO
* Network domain, false otherwise.
*/
isLEONetwork() {
return this.url && this.url.includes(LEO_NEWTORK_DOMAIN);
},
/**
* Parse the configured zoom presets or the GeoJSON response from the LEO
* Network.
* @param {object[]|object} resp The configured zoom presets passed to
* parse may be one of:
* 1. custom presets directly from a map config: a list of objects with
* properties like `description`, `latitude`, `longitude`, `height`,
* `title`, and `image`
* 2. the configuration for the LEO Network collection: an object with a
* `url` and optionally `layerIds` property
* 2. a GeoJSON response from the LEO Network.
* @param {object} options Options for parsing the response.
* @param {MapModel} [options.mapModel] The map model that this collection
* is associated with, used to get all layers.
* @returns {ZoomPresetModel[]} A list of ZoomPresetModel instances
* representing the parsed zoom presets.
*/
parse(resp, options = {}) {
// So we can re-assign the response
let response = resp;
if (response?.url) {
this.url = response.url;
this.defaults = {
layerIds: response.layerIds,
featureLayerId: response.featureLayerId,
};
}
if (this.isLEONetwork()) {
response = this.parseLEONetwork(response);
}
if (!isNonEmptyArray(response)) return [];
const map = options.mapModel || this.mapModel;
const allLayers = map.get("allLayers");
let featureLayer = null;
const zoomPresets = response.map((zoomPresetObj) => {
const enabledLayerIds = [];
const enabledLayerLabels = [];
allLayers.models.forEach((layer) => {
const layerId = layer.get("layerId");
if (zoomPresetObj.layerIds?.find((id) => id === layerId)) {
enabledLayerIds.push(layerId);
enabledLayerLabels.push(layer.get("label"));
}
if (
zoomPresetObj.featureLayerId &&
zoomPresetObj.featureLayerId === layerId
) {
featureLayer = layer;
}
});
return new ZoomPresetModel(
{
description: zoomPresetObj.description,
enabledLayerLabels,
enabledLayerIds,
position: {
latitude: zoomPresetObj.latitude,
longitude: zoomPresetObj.longitude,
height: zoomPresetObj.height,
},
title: zoomPresetObj.title,
image: zoomPresetObj.image,
featureId: zoomPresetObj.featureId,
isLEONetwork: zoomPresetObj.isLEONetwork === true,
featureLayerId: zoomPresetObj.featureLayerId || null,
featureLayer: featureLayer,
},
{ parse: true },
);
});
return zoomPresets;
},
/**
* Parse the GeoJSON response from the LEO Network to extract zoom preset
* data.
* @param {GeoJSON} response The GeoJSON response from the LEO Network.
* @returns {object[]} An array of objects representing zoom presets.
* @since 2.35.0
*/
parseLEONetwork(response) {
if (!response.features || !isNonEmptyArray(response.features)) {
return [];
}
const imgBaseUrl = `https://${LEO_NEWTORK_DOMAIN}`;
return response.features.map((feature) => {
// Extract zoom preset data from the GeoJSON
const { properties, geometry } = feature;
const { observation, id } = properties;
const localizedDate = properties.localized_date;
const thumbnailUrl = properties.thumbnail_url;
const { title, summary } = observation;
const { coordinates } = geometry;
const [longitude, latitude] = coordinates;
return {
description: `<b>${localizedDate}:</b> ${summary}`,
layerIds: this.defaults?.layerIds || [],
latitude,
longitude,
height: DEFAULT_HEIGHT,
title,
image: thumbnailUrl ? `${imgBaseUrl}${thumbnailUrl}` : null,
featureId: id,
isLEONetwork: true,
featureLayerId: this.defaults?.featureLayerId,
};
});
},
},
);
return ZoomPresets;
});