UNPKG

terriajs

Version:

Geospatial data visualization platform.

171 lines (160 loc) 5.25 kB
import papaparse from "papaparse"; import loadWithXhr from "../Core/loadWithXhr"; // We'd like to use `FeatureDetection.supportsWebWorkers()` here, but // PapaParse doesn't get along with our webpack configuration. It ends up // trying to load the entire bundle into a web worker. This is inefficient // to begin with, but also breaks because we use `require` and `window` in // places and these are not defined in web workers. const useWorker = false; export default class Csv { /** * Parses a CSV from a string. * @param csv The string to parse as a CSV. * @param columnMajor True if the returned array is an array of columns; False if the returned array is an array of rows. * @returns A promise that resolves to the CSV data. */ static parseString( csv: string, columnMajor: boolean = false, filterOutComments: boolean = false, options: papaparse.ParseConfig = {} ): Promise<string[][]> { return new Promise<string[][]>((resolve, reject) => { papaparse.parse(csv, { ...getParseOptions(columnMajor, filterOutComments, resolve, reject), ...options }); }); } /** * Parses a CSV from a file. * @param csv The file to parse as a CSV. * @param columnMajor True if the returned array is an array of columns; False if the returned array is an array of rows. * @returns A promise that resolves to the CSV data. */ static parseFile( file: File, columnMajor: boolean = false, filterOutComments: boolean = false, options: papaparse.ParseConfig = {} ): Promise<string[][]> { return new Promise<string[][]>((resolve, reject) => { papaparse.parse(file, { ...getParseOptions(columnMajor, filterOutComments, resolve, reject), ...options }); }); } /** * Parses a CSV from a URL. * @param csv The URL to parse as a CSV. * @param columnMajor True if the returned array is an array of columns; False if the returned array is an array of rows. * @returns A promise that resolves to the CSV data. */ static parseUrl( url: string, columnMajor: boolean = false, filterOutComments: boolean = false, options: papaparse.ParseConfig = {} ): Promise<string[][]> { return loadWithXhr({ url }).then((csv: any) => { if (typeof csv === "string") { return Csv.parseString(csv, columnMajor, filterOutComments, options); } else { throw "Request failed"; } }); // There is currently a bug when using papaparse to fetch CSV URLs // See: https://github.com/mholt/PapaParse/pull/832 // return new Promise<string[][]>((resolve, reject) => { // papaparse.parse(url, { // ...getParseOptions(columnMajor, resolve, reject), // download: true, // }); // }); } } function getParseOptions( columnMajor: boolean, filterOutComments: boolean, resolve: (value: string[][]) => void, reject: (reason?: any) => void ): papaparse.ParseConfig { return columnMajor ? getParseOptionsColumnMajor(filterOutComments, resolve, reject) : getParseOptionsRowMajor(filterOutComments, resolve, reject); } function getParseOptionsRowMajor( filterOutComments: boolean, resolve: (value: string[][]) => void, reject: (reason?: any) => void ): papaparse.ParseConfig { const result: string[][] = []; let parser: any = null; return { comments: filterOutComments, skipEmptyLines: true, worker: useWorker, chunk: function (results, p) { parser = p; const data = results.data; for (let i = 0; i < data.length; ++i) { result.push(data[i]); } }, complete: function () { resolve(result); }, error: function (e) { // If we did manage to get some data lets use what we've got // Perhaps there was an error because there was no Content-Length header if (result.length > 0) parser.abort(); else reject(e); } }; } function getParseOptionsColumnMajor( filterOutComments: boolean, resolve: (value: string[][]) => void, reject: (reason?: any) => void ): papaparse.ParseConfig { const result: string[][] = []; let parser: any = null; return { comments: filterOutComments, skipEmptyLines: true, worker: useWorker, chunk: function (results, p) { parser = p; const data = results.data; for (let i = 0; i < data.length; ++i) { const row = data[i]; if (i === 0) cleanColumnNames(row); for (let j = 0; j < row.length; ++j) { let destColumn = result[j]; if (destColumn === undefined) { destColumn = []; result.push(destColumn); } destColumn.push(row[j]); } } }, complete: function () { resolve(result); }, error: function (e) { // If we did manage to get some data lets use what we've got // Perhaps there was an error because there was no Content-Length header if (result.length > 0) parser.abort(); else reject(e); } }; } function cleanColumnNames(columnNames: string[]) { for (let i = 0; i < columnNames.length; ++i) { if (typeof columnNames[i] === "string") { columnNames[i] = columnNames[i].trim(); } } }