@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
3 lines (2 loc) • 8 kB
JavaScript
/* COPYRIGHT Esri - https://js.arcgis.com/5.0.19/LICENSE.txt */
import e from"../../../../request.js";import{createTask as t}from"../../../../core/asyncUtils.js";import{parseDate as i}from"../../../../core/date.js";import n from"../../../../core/Error.js";import r from"../../../../core/Logger.js";import{isAbortError as s}from"../../../../core/promiseUtils.js";import{urlToObject as o,getFilename as a}from"../../../../core/urlUtils.js";import{projectMany as l}from"../../../../geometry/projectionUtils.js";import m from"../../../../geometry/SpatialReference.js";import{equals as c,isWebMercator as d,wgs84 as u}from"../../../../geometry/support/spatialReferenceUtils.js";import{lngLatToXY as p}from"../../../../geometry/support/webMercatorUtils.js";import{OptimizedFeature as f}from"../../OptimizedFeature.js";import y from"../../OptimizedGeometry.js";import h from"../../data/FeatureStore.js";import{checkProjectionSupport as g}from"../../data/projectionSupport.js";import{QueryEngine as I}from"../../data/QueryEngine.js";import{parseRows as _,parseNumber as F,severSlicedString as w,readRows as E,inferDelimiterAndLocationInfo as T,extractFieldNamesAndAliasesFromRow as j,inferFields as x}from"../csv/csv.js";import{createDefaultAttributesFunction as N,createDrawingInfo as S}from"./clientSideDefaults.js";import{cleanTitle as q}from"../../../support/arcgisLayerUrl.js";import b from"../../../support/FieldsIndex.js";import{getFieldDefaultValue as C}from"../../../support/fieldUtils.js";import{isNumber as O}from"../../../../support/guards.js";import{utc as v}from"../../../../time/constants.js";const D=S("esriGeometryPoint"),k=["csv"],P=[0,0];class R{constructor(e,t){this.x=e,this.y=t}}class V{constructor(){this._queryEngine=null,this._snapshotFeatures=async e=>{const t=await this._fetch(e);return this._createFeatures(t)}}destroy(){this._queryEngine?.destroy(),this._queryEngine=null}async load(e,t={}){this._loadOptions=e;const[i]=await Promise.all([this._fetch(t.signal),this._checkProjection(e?.parsingOptions?.spatialReference)]),n=L(i,e);this._locationInfo=n.locationInfo,this._delimiter=n.delimiter,this._queryEngine=this._createQueryEngine(n);const r=this._createFeatures(i);this._queryEngine.featureStore.addMany(r);const{fullExtent:s,timeExtent:o}=await this._queryEngine.fetchRecomputedExtents();if(n.layerDefinition.extent=s,o){const{start:e,end:t}=o;n.layerDefinition.timeInfo.timeExtent=[e,t]}return n}async applyEdits(){throw new n("csv-layer:editing-not-supported","applyEdits() is not supported on CSVLayer")}async queryFeatures(e={},t={}){return await this._waitSnapshotComplete(),this._queryEngine.executeQuery(e,t.signal)}async queryFeatureCount(e={},t={}){return await this._waitSnapshotComplete(),this._queryEngine.executeQueryForCount(e,t.signal)}async queryObjectIds(e={},t={}){await this._waitSnapshotComplete();return(await this._queryEngine.executeQueryForIds(e,t.signal)).filter(O)}async queryExtent(e={},t={}){return await this._waitSnapshotComplete(),this._queryEngine.executeQueryForExtent(e,t.signal)}async querySnapping(e,t={}){return await this._waitSnapshotComplete(),await this._queryEngine.executeQueryForSnapping(e,t.signal)}async queryAttributeBins(e,t={}){return await this._waitSnapshotComplete(),this._queryEngine.executeAttributeBinsQuery(e,t.signal)}async refresh(e){this._loadOptions.customParameters=e,this._snapshotTask?.abort(),this._snapshotTask=t(this._snapshotFeatures),this._snapshotTask.promise.then(e=>{this._queryEngine.featureStore.clear(),e&&this._queryEngine.featureStore.addMany(e)},e=>{this._queryEngine.featureStore.clear(),s(e)||r.getLogger("esri.layers.CSVLayer").error(new n("csv-layer:refresh","An error occurred during refresh",{error:e}))}),await this._waitSnapshotComplete();const{fullExtent:i,timeExtent:o}=await this._queryEngine.fetchRecomputedExtents();return{extent:i,timeExtent:o}}async _waitSnapshotComplete(){if(this._snapshotTask&&!this._snapshotTask.finished){try{await this._snapshotTask.promise}catch{}return this._waitSnapshotComplete()}}async _fetch(t){const{url:i,customParameters:r}=this._loadOptions;if(!i)throw new n("csv-layer:invalid-source","url not defined");const s=o(i);return(await e(s.path,{query:{...s.query,...r},responseType:"text",signal:t})).data}_createQueryEngine(e){const{objectIdField:t,fields:i,extent:n,timeInfo:r}=e.layerDefinition,s=new h({geometryType:"esriGeometryPoint",hasM:!1,hasZ:!1}),o={type:"object-id",fieldName:t};return new I({fieldsIndex:b.fromLayerJSON({fields:i,dateFieldsTimeReference:{timeZoneIANA:v}}),geometryType:"esriGeometryPoint",hasM:!1,hasZ:!1,timeInfo:r,featureIdInfo:o,spatialReference:n.spatialReference||{wkid:4326},featureStore:s})}_createFeatures(e){const{latitudeFieldName:t,longitudeFieldName:n}=this._locationInfo,{objectIdField:r,fieldsIndex:s,spatialReference:o}=this._queryEngine;let a=[];const u=[],h=s.fields.filter(e=>e.name!==r).map(e=>e.name);let g=0;const I={};for(const i of s.fields)if("esriFieldTypeOID"!==i.type&&"esriFieldTypeGlobalID"!==i.type){const e=C(i);void 0!==e&&(I[i.name]=e)}const E=_(e,h,this._delimiter,N(I,r));for(const l of E){const e=this._parseCoordinateValue(l[t]),o=this._parseCoordinateValue(l[n]);if(null!=o&&null!=e&&!isNaN(e)&&!isNaN(o)){l[t]=e,l[n]=o;for(const e in l)if(e!==t&&e!==n)if(s.isDateField(e))l[e]=i(l[e]);else if(s.isNumericField(e)){const t=F(l[e]);isNaN(t)?l[e]=null:l[e]=t}else null!=l[e]&&(l[e]=w(l[e]));l[r]=g,g++,a.push(new R(o,e)),u.push(l)}}if(!c({wkid:4326},o))if(d(o))for(const i of a)[i.x,i.y]=p(i.x,i.y,P);else a=l(a,m.WGS84,o);const T=[];for(let i=0;i<a.length;i++){const{x:e,y:t}=a[i],n=u[i];n[r]=i+1,T.push(new f(new y([],[e,t]),n,null,n[r]))}return T}_parseCoordinateValue(e){if(null==e||""===e)return null;let t=F(e);return(isNaN(t)||Math.abs(t)>181)&&(t=parseFloat(e)),t}async _checkProjection(e){try{await g(u,e)}catch{throw new n("csv-layer:projection-not-supported","Projection not supported")}}}function L(e,t){const i=t.parsingOptions||{},r={delimiter:i.delimiter,layerDefinition:null,locationInfo:{latitudeFieldName:i.latitudeField,longitudeFieldName:i.longitudeField}},s=r.layerDefinition={name:q(a(t.url,k)||"csv"),dateFieldsTimeReference:{timeZoneIANA:v},drawingInfo:D,geometryType:"esriGeometryPoint",objectIdField:null,fields:[],timeInfo:i.timeInfo,extent:{xmin:Number.POSITIVE_INFINITY,ymin:Number.POSITIVE_INFINITY,xmax:Number.NEGATIVE_INFINITY,ymax:Number.NEGATIVE_INFINITY,spatialReference:i.spatialReference||{wkid:4326}}},o=E(e),l=o.next().value?.trim(),m=o.next().value?.trim();if(!l)throw new n("csv-layer:empty-csv","CSV is empty",{csv:e});const{delimiter:c,locationInfo:d}=T(l,m,i);if(!c)throw new n("csv-layer:invalid-delimiter","Unable to detect the delimiter from CSV",{firstLine:l,secondLine:m,parsingOptions:i});if(!d)throw new n("csv-layer:location-fields-not-found","Unable to identify latitude and longitude fields from the CSV file",{firstLine:l,secondLine:m,parsingOptions:i});r.locationInfo=d,r.delimiter=c;const{names:u,aliases:p}=j(l,c),f=x(e,r.delimiter,u,p,r.locationInfo);if(i.fields?.length){const e=new b(i.fields);for(const t of f){const i=e.get(t.name);i&&Object.assign(t,i)}}if(!f.some(e=>"esriFieldTypeOID"===e.type&&(s.objectIdField=e.name,!0))){const e={name:"__OBJECTID",alias:"__OBJECTID",type:"esriFieldTypeOID",editable:!1,nullable:!1};s.objectIdField=e.name,f.unshift(e)}s.fields=f;const y=new b(s.fields);if(r.locationInfo&&(r.locationInfo.latitudeFieldName=y.get(r.locationInfo.latitudeFieldName).name,r.locationInfo.longitudeFieldName=y.get(r.locationInfo.longitudeFieldName).name),s.timeInfo){const e=s.timeInfo;if(e.startTimeField){const t=y.get(e.startTimeField);t?(e.startTimeField=t.name,t.type="esriFieldTypeDate"):e.startTimeField=null}if(e.endTimeField){const t=y.get(e.endTimeField);t?(e.endTimeField=t.name,t.type="esriFieldTypeDate"):e.endTimeField=null}if(e.trackIdField){const t=y.get(e.trackIdField);e.trackIdField=t?t.name:null}e.startTimeField||e.endTimeField||(s.timeInfo=null)}return r}export{V as default};