forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			90 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			90 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import ThemeViewState from "../Models/ThemeViewState"
 | 
						|
import { Utils } from "../Utils"
 | 
						|
import { UIEventSource } from "../Logic/UIEventSource"
 | 
						|
import { Map as MlMap } from "maplibre-gl"
 | 
						|
import { MapLibreAdaptor } from "../UI/Map/MapLibreAdaptor"
 | 
						|
import { AvailableRasterLayers } from "../Models/RasterLayers"
 | 
						|
 | 
						|
export interface PngMapCreatorOptions {
 | 
						|
    readonly width: number
 | 
						|
    readonly height: number
 | 
						|
}
 | 
						|
 | 
						|
export class PngMapCreator {
 | 
						|
    private static id = 0
 | 
						|
    private readonly _options: PngMapCreatorOptions
 | 
						|
    private readonly _state: ThemeViewState
 | 
						|
 | 
						|
    constructor(state: ThemeViewState, options: PngMapCreatorOptions) {
 | 
						|
        this._state = state
 | 
						|
        this._options = options
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates a base64-encoded PNG image
 | 
						|
     * @constructor
 | 
						|
     */
 | 
						|
    public async CreatePng(freeComponentId: string, status?: UIEventSource<string>): Promise<Blob> {
 | 
						|
        const div = document.createElement("div")
 | 
						|
        div.id = "mapdiv-" + PngMapCreator.id
 | 
						|
        div.style.width = this._options.width + "mm"
 | 
						|
        div.style.height = this._options.height + "mm"
 | 
						|
        PngMapCreator.id++
 | 
						|
        try {
 | 
						|
            const layout = this._state.layout
 | 
						|
 | 
						|
            function setState(msg: string) {
 | 
						|
                status?.setData(layout.id + ": " + msg)
 | 
						|
            }
 | 
						|
 | 
						|
            setState("Initializing map")
 | 
						|
 | 
						|
            const settings = this._state.mapProperties
 | 
						|
            const l = settings.location.data
 | 
						|
 | 
						|
            document.getElementById(freeComponentId).appendChild(div)
 | 
						|
            const pixelRatio = 4
 | 
						|
            const mapElem = new MlMap({
 | 
						|
                container: div.id,
 | 
						|
                style: AvailableRasterLayers.maplibre.properties.url,
 | 
						|
                center: [l.lon, l.lat],
 | 
						|
                zoom: settings.zoom.data,
 | 
						|
                pixelRatio,
 | 
						|
            })
 | 
						|
 | 
						|
            const map = new UIEventSource<MlMap>(mapElem)
 | 
						|
            const mla = new MapLibreAdaptor(map)
 | 
						|
            mla.zoom.setData(settings.zoom.data)
 | 
						|
            mla.location.setData(settings.location.data)
 | 
						|
            mla.rasterLayer.setData(settings.rasterLayer.data)
 | 
						|
            mla.allowZooming.setData(false)
 | 
						|
            mla.allowMoving.setData(false)
 | 
						|
 | 
						|
            this._state?.showNormalDataOn(map)
 | 
						|
            console.log("Creating a map with size", this._options.width, this._options.height)
 | 
						|
 | 
						|
            setState("Waiting for the data")
 | 
						|
            await this._state.dataIsLoading.AsPromise((loading) => !loading)
 | 
						|
            setState("Waiting for styles to be fully loaded")
 | 
						|
            while (!map?.data?.isStyleLoaded()) {
 | 
						|
                console.log("Waiting for the style to be loaded...")
 | 
						|
                await Utils.waitFor(250)
 | 
						|
            }
 | 
						|
            // Some extra buffer...
 | 
						|
            setState("One second pause to make sure all images are loaded...")
 | 
						|
            await Utils.waitFor(1000)
 | 
						|
            setState(
 | 
						|
                "Exporting png (" +
 | 
						|
                    this._options.width +
 | 
						|
                    "mm * " +
 | 
						|
                    this._options.height +
 | 
						|
                    "mm , maplibre-canvas-pixelratio: " +
 | 
						|
                    pixelRatio +
 | 
						|
                    ")"
 | 
						|
            )
 | 
						|
            return await mla.exportAsPng(pixelRatio)
 | 
						|
        } finally {
 | 
						|
            div.parentElement.removeChild(div)
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |