Browse Source

UI: added image caching and async optimisation for map markers rendering

pull/10147/head
Dmitriymush 2 years ago
parent
commit
0b1956be49
  1. 37
      ui-ngx/src/app/core/http/image.service.ts
  2. 23
      ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts
  3. 3
      ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts

37
ui-ngx/src/app/core/http/image.service.ts

@ -18,7 +18,7 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { PageLink } from '@shared/models/page/page-link';
import { defaultHttpOptionsFromConfig, defaultHttpUploadOptions, RequestConfig } from '@core/http/http-utils';
import { Observable, of } from 'rxjs';
import { Observable, of, ReplaySubject } from 'rxjs';
import { PageData } from '@shared/models/page/page-data';
import {
NO_IMAGE_DATA_URI,
@ -36,6 +36,9 @@ import { ResourcesService } from '@core/services/resources.service';
providedIn: 'root'
})
export class ImageService {
private imagesLoading: { [url: string]: ReplaySubject<Blob> } = {};
constructor(
private http: HttpClient,
private sanitizer: DomSanitizer,
@ -95,12 +98,34 @@ export class ImageService {
parts[parts.length - 1] = encodeURIComponent(key);
const encodedUrl = parts.join('/');
const imageLink = preview ? (encodedUrl + '/preview') : encodedUrl;
const options = defaultHttpOptionsFromConfig({ignoreLoading: true, ignoreErrors: true});
return this.http
.get(imageLink, {...options, ...{ responseType: 'blob' } }).pipe(
return this.loadImageDataUrl(imageLink, asString, emptyUrl);
}
private loadImageDataUrl(imageLink: string, asString = false, emptyUrl = NO_IMAGE_DATA_URI): Observable<SafeUrl | string> {
let request: ReplaySubject<Blob>;
if (this.imagesLoading[imageLink]) {
request = this.imagesLoading[imageLink];
} else {
request = new ReplaySubject<Blob>(1);
this.imagesLoading[imageLink] = request;
const options = defaultHttpOptionsFromConfig({ignoreLoading: true, ignoreErrors: true});
this.http.get(imageLink, {...options, ...{ responseType: 'blob' } }).subscribe({
next: (value) => {
request.next(value);
request.complete();
},
error: err => {
request.error(err);
},
complete: () => {
delete this.imagesLoading[imageLink];
}
});
}
return request.pipe(
switchMap(val => blobToBase64(val).pipe(
map((dataUrl) => asString ? dataUrl : this.sanitizer.bypassSecurityTrustUrl(dataUrl))
)),
map((dataUrl) => asString ? dataUrl : this.sanitizer.bypassSecurityTrustUrl(dataUrl))
)),
catchError(() => of(asString ? emptyUrl : this.sanitizer.bypassSecurityTrustUrl(emptyUrl)))
);
}

23
ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts

@ -32,7 +32,7 @@ import {
WidgetUnitedMapSettings
} from './map-models';
import { Marker } from './markers';
import { map, Observable, of, switchMap } from 'rxjs';
import { map, Observable, of } from 'rxjs';
import { Polyline } from './polyline';
import { Polygon } from './polygon';
import { Circle } from './circle';
@ -64,6 +64,7 @@ import { MatDialog } from '@angular/material/dialog';
import { FormattedData, ReplaceInfo } from '@shared/models/widget.models';
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
import { ImagePipe } from '@shared/pipe/image.pipe';
import { take, tap } from 'rxjs/operators';
export default abstract class LeafletMap {
@ -940,7 +941,12 @@ export default abstract class LeafletMap {
this.markersData = markersData;
if (this.options.useClusterMarkers) {
if (createdMarkers.length) {
this.markersCluster.addLayers(createdMarkers.map(marker => marker.leafletMarker));
createdMarkers.forEach((marker) => {
marker.createMarkerIconSubject.pipe(
tap(() => this.markersCluster.addLayer(marker.leafletMarker)),
take(1)
).subscribe();
});
}
if (updatedMarkers.length) {
this.markersCluster.refreshClusters(updatedMarkers.map(marker => marker.leafletMarker));
@ -971,10 +977,15 @@ export default abstract class LeafletMap {
}
this.markers.set(key, newMarker);
if (!this.options.useClusterMarkers) {
this.map.addLayer(newMarker.leafletMarker);
if (this.map.pm.globalDragModeEnabled() && newMarker.leafletMarker.pm) {
newMarker.leafletMarker.pm.enableLayerDrag();
}
newMarker.createMarkerIconSubject.pipe(
tap(() => {
this.map.addLayer(newMarker.leafletMarker);
if (this.map.pm.globalDragModeEnabled() && newMarker.leafletMarker.pm) {
newMarker.leafletMarker.pm.enableLayerDrag();
}
}),
take(1)
).subscribe();
}
return newMarker;
}

3
ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts

@ -23,6 +23,7 @@ import { fillDataPattern, isDefined, isDefinedAndNotNull, processDataPattern, sa
import LeafletMap from './leaflet-map';
import { FormattedData } from '@shared/models/widget.models';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { ReplaySubject } from 'rxjs';
export class Marker {
@ -33,6 +34,7 @@ export class Marker {
tooltipOffset: L.LatLngTuple;
markerOffset: L.LatLngTuple;
tooltip: L.Popup;
createMarkerIconSubject = new ReplaySubject<MarkerIconInfo>();
constructor(private map: LeafletMap,
private location: L.LatLng,
@ -148,6 +150,7 @@ export class Marker {
this.labelOffset = [0, -iconInfo.size[1] * this.markerOffset[1] + 10];
}
this.updateMarkerLabel(settings);
this.createMarkerIconSubject.next(iconInfo);
});
}

Loading…
Cancel
Save