UNPKG

terriajs

Version:

Geospatial data visualization platform.

153 lines (142 loc) 4.8 kB
import { runInAction } from "mobx"; import JulianDate from "terriajs-cesium/Source/Core/JulianDate"; import isDefined from "../../Core/isDefined"; import { isJsonNumber, isJsonObject, isJsonString, JsonObject } from "../../Core/Json"; import TerriaFeature from "../../Models/Feature/Feature"; import { isTerriaFeatureData } from "../../Models/Feature/FeatureData"; import { FeatureInfoFormat } from "../../Traits/TraitsClasses/FeatureInfoTraits"; import { formatDateTime } from "./mustacheExpressions"; /** * * If they require .getValue, apply that. * If they have bad keys, fix them. * If they have formatting, apply it. */ export default function getFeatureProperties( feature: TerriaFeature, currentTime: JulianDate, formats?: Record<string, FeatureInfoFormat> ) { const properties = propertyGetTimeValues(feature, currentTime); if (!properties) return undefined; // Try JSON.parse on values that look like JSON arrays or objects let result = parseValues(properties); result = replaceBadKeyCharacters(result); if (formats) { applyFormatsInPlace(result, formats); } return result; } /** * Gets the values from a Entity's properties object for the time on the current clock. */ export function propertyGetTimeValues( feature: TerriaFeature, currentTime: JulianDate ): JsonObject | undefined { // Check if feature.data is TerriaFeatureData with timeIntervalCollection // If so - use that instead of feature.properties if (isDefined(feature.data)) { if ( isTerriaFeatureData(feature.data) && feature.data.timeIntervalCollection ) return feature.data.timeIntervalCollection.getValue(currentTime); } if (isDefined(feature.properties)) { const result = feature.properties.getValue(currentTime); // Fixes a bug where FeatureInfoDownload tries to serialize a circular object // the _changedEvent._scope property contains _intervals // Serializing the Event is not very useful, anyway if (result._intervals && result._intervals._changedEvent) { result._intervals._changedEvent = undefined; } return result; } } function parseValues(properties: JsonObject) { // JSON.parse property values that look like arrays or objects const result: JsonObject = {}; for (const key in properties) { if (Object.prototype.hasOwnProperty.call(properties, key)) { let val = properties[key]; if ( val && (typeof val === "string" || val instanceof String) && /^\s*[[{]/.test(val as string) ) { try { val = JSON.parse(val as string); } catch (e) {} } result[key] = val; } } return result; } /** * Formats values in an object if their keys match the provided formats object. * @private * @param {Object} properties a map of property labels to property values. * @param {Object} formats A map of property labels to the number formats that should be applied for them. */ function applyFormatsInPlace( properties: JsonObject, formats: Record<string, FeatureInfoFormat> ) { // Optionally format each property. Updates properties in place, returning nothing. for (const key in formats) { if (Object.prototype.hasOwnProperty.call(properties, key)) { // Default type if not provided is number. const value = properties[key]; if ( (isJsonNumber(value) && !isDefined(formats[key].type)) || (isDefined(formats[key].type) && formats[key].type === "number") ) { runInAction(() => { // Convert string to number if necessary const number = isJsonNumber(value) ? value : isJsonString(value) ? parseFloat(value) : undefined; // Note we default maximumFractionDigits to 20 (not 3). properties[key] = number?.toLocaleString(undefined, { maximumFractionDigits: 20, useGrouping: true, ...formats[key] }); }); } if (isDefined(formats[key].type)) { if (formats[key].type === "dateTime" && isJsonString(value)) { runInAction(() => { properties[key] = formatDateTime(value, formats[key]); }); } } } } } /** * Recursively replace '.' and '#' in property keys with _, since Mustache cannot reference keys with these characters. * @private */ function replaceBadKeyCharacters(properties: JsonObject) { const result: JsonObject = {}; for (const key in properties) { if (Object.prototype.hasOwnProperty.call(properties, key)) { const cleanKey = key.replace(/[.#]/g, "_"); const value = properties[key]; result[cleanKey] = isJsonObject(value) ? replaceBadKeyCharacters(value) : value; } } return result; }