diff --git a/packages/geo/src/lib/datasource/shared/datasources/wfs-datasource.ts b/packages/geo/src/lib/datasource/shared/datasources/wfs-datasource.ts index 9ffa03fff0..da7306647a 100644 --- a/packages/geo/src/lib/datasource/shared/datasources/wfs-datasource.ts +++ b/packages/geo/src/lib/datasource/shared/datasources/wfs-datasource.ts @@ -23,7 +23,6 @@ import { AuthInterceptor } from '@igo2/auth'; export class WFSDataSource extends DataSource { public declare ol: olSourceVector; - public mostRecentIdCallOGCFilter: number = 0; set ogcFilters(value: OgcFiltersOptions) { (this.options as OgcFilterableDataSourceOptions).ogcFilters = value; @@ -100,7 +99,6 @@ export class WFSDataSource extends DataSource { setOgcFilters(ogcFilters: OgcFiltersOptions, triggerEvent: boolean = false) { this.ogcFilters = ogcFilters; - this.mostRecentIdCallOGCFilter += 1; if (triggerEvent) { this.ol.notify('ogcFilters', this.ogcFilters); } diff --git a/packages/geo/src/lib/layer/shared/layers/vector-layer.ts b/packages/geo/src/lib/layer/shared/layers/vector-layer.ts index aa4ed7f9f6..089daf7197 100644 --- a/packages/geo/src/lib/layer/shared/layers/vector-layer.ts +++ b/packages/geo/src/lib/layer/shared/layers/vector-layer.ts @@ -9,6 +9,7 @@ import olFeature from 'ol/Feature'; import olProjection from 'ol/proj/Projection'; import * as olproj from 'ol/proj'; import * as olformat from 'ol/format'; +import OlFeature from 'ol/Feature'; import { FeatureDataSource } from '../../../datasource/shared/datasources/feature-datasource'; import { WFSDataSource } from '../../../datasource/shared/datasources/wfs-datasource'; @@ -27,7 +28,10 @@ import { buildUrl, defaultMaxFeatures } from '../../../datasource/shared/datasources/wms-wfs.utils'; -import { OgcFilterableDataSourceOptions } from '../../../filter/shared/ogc-filter.interface'; +import { + OgcFilterableDataSourceOptions, + OgcFiltersOptions +} from '../../../filter/shared/ogc-filter.interface'; import { GeoNetworkService, SimpleGetOptions @@ -48,8 +52,14 @@ import BaseEvent from 'ol/events/Event'; import { olStyleToBasicIgoStyle } from '../../../style/shared/vector/conversion.utils'; import { FeatureDataSourceOptions } from '../../../datasource/shared/datasources/feature-datasource.interface'; import { ObjectUtils } from '@igo2/utils'; +import { Extent } from 'ol/extent'; +import { FeatureLoader } from 'ol/featureloader'; export class VectorLayer extends Layer { + private previousLoadExtent: Extent; + private previousLoadResolution: number; + private previousOgcFilters: OgcFiltersOptions; + private xhrAccumulator: XMLHttpRequest[] = []; public declare dataSource: | FeatureDataSource | WFSDataSource @@ -167,8 +177,11 @@ export class VectorLayer extends Layer { const vector = new olLayerVector(olOptions); const vectorSource = vector.getSource() as olSourceVector; const url = vectorSource.getUrl(); + if (typeof url === 'function') { + return vector; + } if (url) { - let loader; + let loader: FeatureLoader; const wfsOptions = olOptions.sourceOptions as WFSDataSourceOptions; if ( wfsOptions?.type === 'wfs' && @@ -436,14 +449,14 @@ export class VectorLayer extends Layer { * @param randomParam random parameter to ensure cache is not causing problems in retrieving new data */ public customWFSLoader( - vectorSource, - options, - interceptor, - extent, - resolution, - proj, - success, - failure, + vectorSource: olSourceVector, + options: WFSDataSourceOptions, + interceptor: AuthInterceptor, + extent: Extent, + resolution: number, + proj: olProjection, + success: (features: olFeature[]) => void, + failure: () => void, randomParam?: boolean ) { { @@ -452,12 +465,31 @@ export class VectorLayer extends Layer { ? new olProjection({ code: paramsWFS.srsName }) : proj; const currentExtent = olproj.transformExtent(extent, proj, wfsProj); + const ogcFilters = (options as OgcFilterableDataSourceOptions).ogcFilters; + + if ( + (this.previousLoadExtent && + this.previousLoadExtent !== currentExtent) || + (this.previousLoadResolution && + this.previousLoadResolution !== resolution) || + (this.previousOgcFilters && this.previousOgcFilters !== ogcFilters) + ) { + vectorSource.removeLoadedExtent(this.previousLoadExtent); + for (let xhr of this.xhrAccumulator) { + xhr.abort(); + } + } + + this.previousLoadExtent = currentExtent; + this.previousLoadResolution = resolution; + this.previousOgcFilters = ogcFilters; + paramsWFS.srsName = paramsWFS.srsName || proj.getCode(); const url = buildUrl( options, currentExtent, wfsProj, - (options as OgcFilterableDataSourceOptions).ogcFilters, + ogcFilters, randomParam ); let startIndex = 0; @@ -481,7 +513,6 @@ export class VectorLayer extends Layer { wfsProj, proj, alteredUrl, - nbOfFeature, success, failure ); @@ -495,7 +526,6 @@ export class VectorLayer extends Layer { wfsProj, proj, url, - paramsWFS.maxFeatures, success, failure ); @@ -512,23 +542,19 @@ export class VectorLayer extends Layer { * @param dataProjection the projection of the retrieved data * @param featureProjection the projection of the created features * @param url the url string to retrieve the data - * @param threshold the threshold to manage "more features" (TODO) * @param success success callback * @param failure failure callback */ private getFeatures( vectorSource: olSourceVector, - interceptor, - extent, - dataProjection, - featureProjection, + interceptor: AuthInterceptor, + extent: Extent, + dataProjection: olProjection, + featureProjection: olProjection, url: string, - threshold: number, - success, - failure + success: (features: olFeature[]) => void, + failure: () => void ) { - const idAssociatedCall = (this.dataSource as WFSDataSource) - .mostRecentIdCallOGCFilter; const xhr = new XMLHttpRequest(); const alteredUrlWithKeyAuth = interceptor.alterUrlWithKeyAuth(url); let modifiedUrl = url; @@ -552,15 +578,7 @@ export class VectorLayer extends Layer { dataProjection, featureProjection }) as olFeature[]; - // TODO Manage "More feature" - /*if (features.length === 0 || features.length < threshold ) { - console.log('No more data to download at this resolution'); - }*/ - // Avoids retrieving an older call that took longer to be process - if ( - idAssociatedCall === - (this.dataSource as WFSDataSource).mostRecentIdCallOGCFilter - ) { + if (features) { vectorSource.addFeatures(features); success(features); } else { @@ -570,6 +588,7 @@ export class VectorLayer extends Layer { onError(); } }; + this.xhrAccumulator.push(xhr); xhr.send(); } @@ -584,14 +603,14 @@ export class VectorLayer extends Layer { * @param projection the projection to retrieve the data */ private customLoader( - vectorSource, - url, - interceptor, - extent, - resolution, - projection, - success, - failure + vectorSource: olSourceVector, + url: string, + interceptor: AuthInterceptor, + extent: Extent, + resolution: number, + projection: olProjection, + success: (features: olFeature[]) => void, + failure: () => void ) { const xhr = new XMLHttpRequest(); let modifiedUrl = url; @@ -600,8 +619,6 @@ export class VectorLayer extends Layer { if (alteredUrlWithKeyAuth) { modifiedUrl = alteredUrlWithKeyAuth; } - } else { - modifiedUrl = url(extent, resolution, projection); } if (this.geoNetworkService && typeof url !== 'function') { @@ -622,7 +639,7 @@ export class VectorLayer extends Layer { concatMap((r) => r ? of(r) - : this.geoNetworkService.get(modifiedUrl, options).pipe( + : this.geoNetworkService.get(modifiedUrl as string, options).pipe( first(), catchError((res) => { onError(); @@ -653,8 +670,8 @@ export class VectorLayer extends Layer { const features = format.readFeatures(source, { extent, featureProjection: projection - }); - vectorSource.addFeatures(features, format.readProjection(source)); + }) as OlFeature[]; + vectorSource.addFeatures(features); success(features); } else { onError(); @@ -662,13 +679,13 @@ export class VectorLayer extends Layer { } }); } else { - xhr.open('GET', modifiedUrl); + xhr.open('GET', modifiedUrl as string); const format = vectorSource.getFormat(); if (format.getType() === 'arraybuffer') { xhr.responseType = 'arraybuffer'; } if (interceptor) { - interceptor.interceptXhr(xhr, modifiedUrl); + interceptor.interceptXhr(xhr, modifiedUrl as string); } const onError = () => { @@ -698,8 +715,8 @@ export class VectorLayer extends Layer { const features = format.readFeatures(source, { extent, featureProjection: projection - }); - vectorSource.addFeatures(features, format.readProjection(source)); + }) as OlFeature[]; + vectorSource.addFeatures(features); success(features); } else { onError(); diff --git a/packages/geo/src/lib/offline/shared/geo-network.service.ts b/packages/geo/src/lib/offline/shared/geo-network.service.ts index 7fd38ca6a3..f7cd9145f5 100644 --- a/packages/geo/src/lib/offline/shared/geo-network.service.ts +++ b/packages/geo/src/lib/offline/shared/geo-network.service.ts @@ -3,6 +3,7 @@ import { Injectable } from '@angular/core'; import { ConnectionState, NetworkService } from '@igo2/core'; import { Observable } from 'rxjs'; import { GeoDBService } from '../geoDB/geoDB.service'; +import { Type } from 'ol/format/Feature'; export enum ResponseType { Arraybuffer = 'arraybuffer', @@ -11,7 +12,7 @@ export enum ResponseType { Json = 'json' } export interface SimpleGetOptions { - responseType: ResponseType; + responseType: Type; withCredentials?: boolean; } @Injectable({ @@ -49,12 +50,6 @@ export class GeoNetworkService { withCredentials: simpleGetOptions.withCredentials }); break; - case 'blob': - request = this.http.get(url, { - responseType: 'blob', - withCredentials: simpleGetOptions.withCredentials - }); - break; case 'text': request = this.http.get(url, { responseType: 'text', diff --git a/packages/geo/src/lib/workspace/shared/edition-workspace.service.ts b/packages/geo/src/lib/workspace/shared/edition-workspace.service.ts index b5db5e2a39..6ccc72c6b1 100644 --- a/packages/geo/src/lib/workspace/shared/edition-workspace.service.ts +++ b/packages/geo/src/lib/workspace/shared/edition-workspace.service.ts @@ -54,6 +54,7 @@ import olSourceImageWMS from 'ol/source/ImageWMS'; import type { default as OlGeometry } from 'ol/geom/Geometry'; import { BehaviorSubject, Observable, throwError } from 'rxjs'; import { createFilterInMapExtentOrResolutionStrategy } from './workspace.utils'; +import { FeatureLoader } from 'ol/featureloader'; @Injectable({ providedIn: 'root' @@ -738,10 +739,16 @@ export class EditionWorkspaceService { */ refreshMap(layer: VectorLayer, map: MapBase) { const wfsOlLayer = layer.dataSource.ol; - const loader = (extent, resolution, proj, success, failure) => { + const loader: FeatureLoader = ( + extent, + resolution, + proj, + success, + failure + ) => { layer.customWFSLoader( layer.ol.getSource(), - layer.options.sourceOptions, + layer.options.sourceOptions as WFSDataSourceOptions, this.authInterceptor, extent, resolution,