Reputation: 51
In Openlayers 6 each layer has an independent renderer (previously, all layer rendering was managed by a single map renderer and depended on a single rendering strategy - https://openlayers.org/workshop/en/webgl/meteorites.html). In my project I have more then 20 TileLayers (TileWMS), and the loading, panning, scrolling performance worse then in openlayers 5. Can I set the rendering strategy? How can I increase performance?
The tiles are loading fast, but then (after loading tiles) panning on map is slow. The GPU usage not critical (below 30%)
Angular 9 project, logic in service classes:
@Injectable({
providedIn: 'root'
})
export class EMap {
private eMap: OlMap;
public createMapObject(): void {
this.eMap = new OlMap({
layers: [],
view: new View({
projection,
resolutions: resolutionsArray,
constrainResolution: true,
enableRotation: false
}),
controls: defaultControls({
rotate: false,
attribution: false,
zoom: false
}).extend([
mousePositionControl,
scalelineControl
])
});
}
public initMap(center: Coordinate, zoom: number, target: string): void {
this.eMap.getView().setCenter(center);
this.eMap.getView().setZoom(zoom);
this.eMap.setTarget(target);
}
public addLayer(layer: TileLayer | ImageLayer | VectorLayer): void {
this.eMap.addLayer(layer);
}
}
@Injectable({
providedIn: 'root'
})
export class EMapSupportlayers extends EMapNetworklayers {
constructor(private readonly eMap: EMap) {}
public addTilelayer(networklayerInfo: NetworklayerInfo): void {
const layer: TileLayer = this.createTileLayer(tileLayerInitValues);
this.eMap.addLayer(layer);
}
private createTileLayer(tileLayerInitValues: TileLayerInitValues): TileLayer {
const tileGrid: TileGrid = new TileGrid({
extent: tileLayerInitValues.tileGridExtent,
resolutions: tileLayerInitValues.resolutions,
tileSize: tileLayerInitValues.tileSize
});
const source = new TileWMS({
url: tileLayerInitValues.url,
params: {
LAYERS: tileLayerInitValues.layerName,
FORMAT: tileLayerInitValues.layerFormat
},
tileLoadFunction: (image: any, src: string) => this.customLoader(image, src),
tileGrid
});
return new TileLayer({
visible: tileLayerInitValues.visible,
maxZoom: tileLayerInitValues.maxZoom,
minZoom: ttileLayerInitValues.minZoom,
source,
zIndex: tileLayerInitValues.zindex
});
}
private async customLoader(tile: any, sourceUrl: string): Promise<void> {
const response = await fetch(sourceUrl, {
method: 'POST',
credentials: 'include',
headers: new Headers({
Authorization: `Bearer ${...}`
}),
body: requestBody ? requestBody : null
});
const blob = await response.blob();
tile.getImage().src = URL.createObjectURL(blob);
}
}
--- 07.19.
I have created a dummy axample (Angular9, Openlayers 6.3.1): Layers tiles are loading fast. On small screen panning is fast, but on large screen panning is slow (after loading and cacheing tiles). The performance was better in openlayers 5.
import { AfterViewInit, Component } from '@angular/core';
import TileLayer from 'ol/layer/Tile';
import Map from 'ol/Map';
import { OSM } from 'ol/source';
import View from 'ol/View';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit {
ngAfterViewInit(): void {
const mapElement = document.createElement('div');
mapElement.style.cssText = 'position:absolute;width:100%;height:100%';
const layers = [];
for (let i = 0; i < 30; ++i) {
const layer = new TileLayer({
source: new OSM(),
// className: 'layer' + i => create own canvas by layers, same performance
});
layer.setOpacity(0.03);
layers.push(layer);
}
const map = new Map({
layers,
view: new View({
center: [0, 0],
zoom: 1
})
});
document.body.appendChild(mapElement);
map.setTarget(mapElement);
}
}
Upvotes: 1
Views: 1600
Reputation: 51
I have found a solution, not perfect, but the performance is better.
map.on('movestart', () => {
layers.forEach(layer => {
layer.setExtent(map.getView().calculateExtent());
});
});
map.on('moveend', () => {
layers.forEach(layer => {
layer.setExtent(undefined);
});
});
Upvotes: 1
Reputation: 17972
URL.createObjectURL
can cause memory leaks, try
const blob = await response.blob();
const objectURL = URL.createObjectURL(blob)
tile.getImage().onload = function(){
URL.revokeObjectURL(objectURL);
};
tile.getImage().src = objectURL;
Also do any of your layers use the same WMS URL with a diiferent WMS layerName
? It would be more efficient to combine them into a single OpenLayers layer with a list of WMS layer names in the LAYERS parameter.
Upvotes: 0