Source: ol/format/CsvPoint.js

/**
 * @module nyc/ol/format/CsvPoint
 */

import Papa from 'papaparse'

import Encoding from 'text-encoding'

import OlFeature from 'ol/Feature'
import OlFormatFeature from 'ol/format/Feature'
import OlGeomPoint from 'ol/geom/Point'
import OlFormatFormatType from 'ol/format/FormatType'
import StandardCsv from 'nyc/ol/format/StandardCsv'

import {get as olProjGet} from 'ol/proj'

/**
 * @desc Class to create point features from CSV data
 * @public
 * @class
 * @extends ol.format.Feature
 * @see http://openlayers.org/en/latest/apidoc/module-ol_format_Feature-FeatureFormat.html
 */
class CsvPoint extends OlFormatFeature {
  /**
   * @desc Create an instance of CsvPoint
   * @public
   * @constructor
   * @param {module:nyc/ol/format/CsvPoint~CsvPoint.Options} options Constructor options
   */
  constructor(options) {
    super()
    /**
     * @private
     * @member {boolean}
     */
    this.autoDetect = options.autoDetect === true
    /**
     * @private
     * @member {ol.Projection}
     */
    this.dataProjection = olProjGet(options.dataProjection || 'EPSG:4326')
    /**
     * @private
     * @member {ol.Projection}
     */
    this.featureProjection = olProjGet(options.featureProjection || 'EPSG:3857')
    /**
     * @private
     * @member {string}
     */
    this.id = options.id
    /**
     * @private
     * @member {string}
     */
    this.x = options.x
    /**
     * @private
     * @member {string}
     */
    this.y = options.y
    /**
     * @private
     * @member {number}
     */
    this.lastId = 0
  }
  /**
   * @desc Read a single feature from a source
   * @public
   * @method
   * @param {Object} source A row from a CSV data source
   * @param {olx.format.ReadOptions=} options Read options
   * @return {ol.Feature} Feature
   */
  readFeature(source, options) {
    let id
    if (source[this.id]) {
      id = source[this.id]
    } else {
      id = this.lastId
      this.lastId += 1
    }
    const x = source[this.x] = parseFloat(source[this.x])
    const y = source[this.y] = parseFloat(source[this.y])
    if (isNaN(x) || isNaN(y)) {
      throw `Invalid coordinate [${x}, ${y}] for id ${id}`
    }
    const point = new OlGeomPoint([x, y])
    const feature = new OlFeature(source)
    point.transform(
      options && options.dataProjection ? options.dataProjection : this.dataProjection,
      options && options.featureProjection ? options.featureProjection : this.featureProjection
    )
    feature.setGeometry(point)
    feature.setId(id)
    return feature
  }
  /**
   * @desc Read all features from a source
   * @public
   * @method
   * @param {Object} source Rows from a CSV data source
   * @param {olx.format.ReadOptions=} options Read options
   * @return {Array.<ol.Feature>} Features
   */
  readFeatures(source, options) {
    const features = []
    source = this.parseSource(source)
    source.forEach((row) => {
      try {
        features.push(this.readFeature(row, options))
      } catch (error) {
        console.error(error, row)
      }
    })
    return features
  }
  /**
   * @private
   * @method
   * @param {Object} source Rows from a CSV data source
   * @return {ol.proj.Projection} The projection
   */
  parseSource(source) {
    if (source instanceof ArrayBuffer) {
      source = new Encoding.TextDecoder('utf-8').decode(source)
    }
    if (typeof source === 'string') {
      source = Papa.parse(source, {header: true}).data
    }
    this.detectCsvFormat(source)
    return source
  }
  /**
   * @desc Detect CSV columns and projection based on standard format
   * @public
   * @method
   * @param {Object<string, Object>} source Parsed CSV data
   */
  detectCsvFormat(source) {
    if (this.autoDetect) {
      this.id = StandardCsv.ID
      if (source[0][StandardCsv.X]) {
        this.x = StandardCsv.X
        this.y = StandardCsv.Y
        this.dataProjection = olProjGet('EPSG:2263')
      } else {
        this.x = StandardCsv.LNG
        this.y = StandardCsv.LAT
        this.dataProjection = olProjGet('EPSG:4326')
      }
    }
  }
  /**
   * @desc Read the projection from a source
   * @public
   * @override
   * @method
   * @param {Document|Node|Object|string} source Source
   * @return {ol.proj.Projection} The projection
   */
  readProjection(source) {
    return this.dataProjection
  }
  /**
   * @desc Return format type
   * @public
   * @override
   * @method
   * @return {ol.format.FormatType} The format type
   */
  getType() {
    return OlFormatFormatType.ARRAY_BUFFER
  }
}

/**
* @desc Constructor options for {@link module:nyc/ol/format/CsvPoint~CsvPoint}
* @public
* @typedef {Object}
* @property {boolean} [autoDetect=false] Attempt to determine standard column names and projection
* @property {string=} x The name of the field containing the x ordinate of the point
* @property {string=} y The name of the field containing the y ordinate of the point
* @property {string=} id The name of the field containing the unique id of the point
* @property {ol.ProjectionLike} [dataProjection=EPSG:4326] The projection of the source data
* @property {ol.ProjectionLike} [featureProjection=EPSG:3857] The projection of the resulting features
*/
CsvPoint.Options

export default CsvPoint