2021-07-28 02:51:07 +02:00
/ * *
* Creates screenshoter to take png screenshot
* Creates jspdf and downloads it
* - landscape pdf
*
* To add new layout :
* - add new possible layout name in constructor
* - add new layout in "PDFLayout"
* - > in there are more instructions
* /
import jsPDF from "jspdf" ;
import { SimpleMapScreenshoter } from "leaflet-simple-map-screenshoter" ;
import { UIEventSource } from "../Logic/UIEventSource" ;
import Minimap from "./Base/Minimap" ;
import Loc from "../Models/Loc" ;
import { BBox } from "../Logic/GeoOperations" ;
import ShowDataLayer from "./ShowDataLayer" ;
import BaseLayer from "../Models/BaseLayer" ;
import { FixedUiElement } from "./Base/FixedUiElement" ;
import Translations from "./i18n/Translations" ;
2021-07-29 01:57:45 +02:00
import State from "../State" ;
import Constants from "../Models/Constants" ;
2021-08-07 23:11:34 +02:00
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig" ;
2021-07-28 02:51:07 +02:00
export default class ExportPDF {
// dimensions of the map in milimeter
2021-09-09 00:05:51 +02:00
public isRunning = new UIEventSource ( true )
2021-07-28 02:51:07 +02:00
// A4: 297 * 210mm
private readonly mapW = 297 ;
private readonly mapH = 210 ;
private readonly scaling = 2
private readonly freeDivId : string ;
private readonly _layout : UIEventSource < LayoutConfig > ;
2021-07-28 15:14:13 +02:00
private _screenhotTaken = false ;
2021-07-28 02:51:07 +02:00
constructor (
options : {
freeDivId : string ,
location : UIEventSource < Loc > ,
background? : UIEventSource < BaseLayer >
features : UIEventSource < { feature : any } [ ] > ,
layout : UIEventSource < LayoutConfig >
}
) {
this . freeDivId = options . freeDivId ;
this . _layout = options . layout ;
const self = this ;
// We create a minimap at the given location and attach it to the given 'hidden' element
2021-07-28 12:36:39 +02:00
const l = options . location . data ;
const loc = {
2021-07-28 15:14:13 +02:00
lat : l.lat ,
2021-07-28 12:36:39 +02:00
lon : l.lon ,
zoom : l.zoom + 1
}
2021-07-28 15:14:13 +02:00
2021-07-28 02:51:07 +02:00
const minimap = new Minimap ( {
2021-07-28 12:36:39 +02:00
location : new UIEventSource < Loc > ( loc ) , // We remove the link between the old and the new UI-event source as moving the map while the export is running fucks up the screenshot
2021-07-28 02:51:07 +02:00
background : options.background ,
2021-07-28 12:36:39 +02:00
allowMoving : false ,
2021-09-09 00:05:51 +02:00
2021-07-28 02:51:07 +02:00
onFullyLoaded : leaflet = > window . setTimeout ( ( ) = > {
2021-07-28 15:14:13 +02:00
if ( self . _screenhotTaken ) {
return ;
}
try {
self . CreatePdf ( leaflet )
. then ( ( ) = > self . cleanup ( ) )
. catch ( ( ) = > self . cleanup ( ) )
} catch ( e ) {
2021-07-28 02:51:07 +02:00
console . error ( e )
self . cleanup ( )
}
} , 500 )
} )
minimap . SetStyle ( ` width: ${ this . mapW * this . scaling } mm; height: ${ this . mapH * this . scaling } mm; ` )
minimap . AttachTo ( options . freeDivId )
// Next: we prepare the features. Only fully contained features are shown
const bounded = options . features . map ( feats = > {
const leaflet = minimap . leafletMap . data ;
if ( leaflet === undefined ) {
return feats
}
const bounds = BBox . fromLeafletBounds ( leaflet . getBounds ( ) . pad ( 0.2 ) )
return feats . filter ( f = > BBox . get ( f . feature ) . isContainedIn ( bounds ) )
} , [ minimap . leafletMap ] )
// Add the features to the minimap
new ShowDataLayer (
bounded ,
minimap . leafletMap ,
options . layout ,
false
)
}
2021-07-28 15:14:13 +02:00
private cleanup() {
2021-07-29 01:57:45 +02:00
// new FixedUiElement("Screenshot taken!").AttachTo(this.freeDivId)
2021-07-28 15:14:13 +02:00
this . _screenhotTaken = true ;
2021-07-28 02:51:07 +02:00
}
private async CreatePdf ( leaflet : L.Map ) {
const t = Translations . t . general . pdf ;
const layout = this . _layout . data
const screenshotter = new SimpleMapScreenshoter ( ) ;
//minimap op index.html -> hidden daar alles op doen en dan weg
//minimap - leaflet map ophalen - boundaries ophalen - State.state.featurePipeline
screenshotter . addTo ( leaflet ) ;
console . log ( "Taking screenshot" )
let doc = new jsPDF ( 'landscape' ) ;
const image = ( await screenshotter . takeScreen ( 'image' ) )
// @ts-ignore
doc . addImage ( image , 'PNG' , 0 , 0 , this . mapW , this . mapH ) ;
doc . setDrawColor ( 255 , 255 , 255 )
doc . setFillColor ( 255 , 255 , 255 )
2021-07-29 01:57:45 +02:00
doc . roundedRect ( 12 , 10 , 145 , 25 , 5 , 5 , 'FD' )
2021-07-28 02:51:07 +02:00
doc . setFontSize ( 20 )
2021-07-29 01:57:45 +02:00
doc . textWithLink ( layout . title . txt , 40 , 18.5 , {
maxWidth : 125 ,
url : window.location.href
2021-07-28 02:51:07 +02:00
} )
doc . setFontSize ( 10 )
2021-07-29 01:57:45 +02:00
doc . text ( t . generatedWith . txt , 40 , 23 , {
maxWidth : 125
2021-07-28 02:51:07 +02:00
} )
2021-08-22 20:10:19 +02:00
const backgroundLayer : BaseLayer = State . state . backgroundLayer . data
2021-07-29 01:57:45 +02:00
const attribution = new FixedUiElement ( backgroundLayer . layer ( ) . getAttribution ( ) ? ? backgroundLayer . name ) . ConstructElement ( ) . innerText
doc . textWithLink ( t . attr . txt , 40 , 26.5 , {
maxWidth : 125 ,
url : "https://www.openstreetmap.org/copyright"
} )
doc . text ( t . attrBackground . Subs ( {
background : attribution
} ) . txt , 40 , 30 )
2021-08-22 20:10:19 +02:00
let date = new Date ( ) . toISOString ( ) . substr ( 0 , 16 )
2021-07-29 01:57:45 +02:00
doc . setFontSize ( 7 )
doc . text ( t . versionInfo . Subs ( {
version : Constants.vNumber ,
date : date
} ) . txt , 40 , 34 , {
maxWidth : 125
} )
2021-08-22 20:10:19 +02:00
2021-07-28 02:51:07 +02:00
// Add the logo of the layout
let img = document . createElement ( 'img' ) ;
const imgSource = layout . icon
2021-07-29 01:57:45 +02:00
const imgType = imgSource . substr ( imgSource . lastIndexOf ( "." ) + 1 ) ;
2021-07-28 02:51:07 +02:00
img . src = imgSource
2021-07-29 01:57:45 +02:00
console . log ( imgType )
if ( imgType . toLowerCase ( ) === "svg" ) {
new FixedUiElement ( "" ) . AttachTo ( this . freeDivId )
// This is an svg image, we use the canvas to convert it to a png
const canvas = document . createElement ( 'canvas' )
const ctx = canvas . getContext ( '2d' ) ;
canvas . width = 500
canvas . height = 500
img . style . width = "100%"
img . style . height = "100%"
ctx . drawImage ( img , 0 , 0 , 500 , 500 ) ;
const base64img = canvas . toDataURL ( "image/png" )
doc . addImage ( base64img , 'png' , 15 , 12 , 20 , 20 ) ;
} else {
try {
doc . addImage ( img , imgType , 15 , 12 , 20 , 20 ) ;
} catch ( e ) {
console . error ( e )
}
2021-07-28 02:51:07 +02:00
}
2021-07-29 01:57:45 +02:00
doc . save ( ` MapComplete_ ${ layout . title . txt } _ ${ date } .pdf ` ) ;
2021-07-28 02:51:07 +02:00
2021-08-22 20:10:19 +02:00
this . isRunning . setData ( false )
2021-07-28 02:51:07 +02:00
}
}