UNPKG

terriajs

Version:

Geospatial data visualization platform.

83 lines (75 loc) 2.6 kB
import joinUrl from "./joinUrl"; import loadCsv from "../../Core/loadCsv"; import { IndexBase, IndexType } from "./Types"; import sortedIndexBy from "lodash-es/sortedIndexBy"; import sortedLastIndexBy from "lodash-es/sortedLastIndexBy"; // Minimum and maxiumum values in a numeric range export type NumericRange = { min: number; max: number }; // Start and end numbers type NumericSearchQuery = { start: number; end: number; }; /** * An index used for searching numeric values. * * It is represented as an array of [id, value] pairs sorted by the value. * Searching is done by performing a binary search on the array. */ export default class NumericIndex implements IndexBase<NumericSearchQuery> { readonly type = IndexType.numeric; idValuePairs?: Promise<{ dataRowId: number; value: number }[]>; /** * Constructs a NumericIndex. * * @param url Url of the NumericIndex CSV file. This could be a relative URL. * @param range The maximum and minimum value in the index. */ constructor(readonly url: string, readonly range: NumericRange) {} /** * Load a numeric index. * * @param indexRootUrl The URL of the index root directory * @param _valueHint Ignored for NumericIndex. */ async load( indexRootUrl: string, _valueHint: NumericSearchQuery ): Promise<void> { if (this.idValuePairs) return; const indexUrl = joinUrl(indexRootUrl, this.url); const promise = loadCsv(indexUrl, { dynamicTyping: true, header: true }); this.idValuePairs = promise; return promise.then(() => {}); } /** * Search the numeric index for values between the start and end value in NumericSearchQuery. * * @param value The start and end value to be searched. * @return Set of IDs that matches the search value. */ async search(value: NumericSearchQuery): Promise<Set<number>> { if (!this.idValuePairs) throw new Error(`Index not loaded`); const range = this.range; const idValuePairs = await this.idValuePairs; const startValue = value.start === undefined ? range.min : value.start; const endValue = value.end === undefined ? range.max : value.end; const startIndex = sortedIndexBy( idValuePairs, { dataRowId: 0, value: startValue }, (entry) => entry.value ); const endIndex = sortedLastIndexBy( idValuePairs, { dataRowId: 0, value: endValue }, (entry) => entry.value ); const matchingIds = idValuePairs .slice(startIndex, endIndex) .map(({ dataRowId }) => dataRowId); return new Set(matchingIds); } }