Fix pdf export, fix feature switches

This commit is contained in:
Pieter Vander Vennet 2021-07-28 02:51:07 +02:00
parent 6cd75a8260
commit ede67ca58c
19 changed files with 390 additions and 144 deletions

View file

@ -17,12 +17,14 @@ export default class Minimap extends BaseUIElement {
private _isInited = false;
private _allowMoving: boolean;
private readonly _leafletoptions: any;
private readonly _onFullyLoaded: (leaflet: L.Map) => void
constructor(options?: {
background?: UIEventSource<BaseLayer>,
location?: UIEventSource<Loc>,
allowMoving?: boolean,
leafletOptions?: any
leafletOptions?: any,
onFullyLoaded?: (leaflet: L.Map) => void
}
) {
super()
@ -32,6 +34,7 @@ export default class Minimap extends BaseUIElement {
this._id = "minimap" + Minimap._nextId;
this._allowMoving = options.allowMoving ?? true;
this._leafletoptions = options.leafletOptions ?? {}
this._onFullyLoaded = options.onFullyLoaded
Minimap._nextId++
}
@ -74,10 +77,10 @@ export default class Minimap extends BaseUIElement {
}
this._isInited = true;
const location = this._location;
const self = this;
let currentLayer = this._background.data.layer()
const options = {
center: <[number, number]> [location.data?.lat ?? 0, location.data?.lon ?? 0],
center: <[number, number]>[location.data?.lat ?? 0, location.data?.lon ?? 0],
zoom: location.data?.zoom ?? 2,
layers: [currentLayer],
zoomControl: false,
@ -90,10 +93,17 @@ export default class Minimap extends BaseUIElement {
// Disabling this breaks the geojson layer - don't ask me why! zoomAnimation: this._allowMoving,
fadeAnimation: this._allowMoving
}
Utils.Merge(this._leafletoptions, options)
const map = L.map(this._id, options);
if (self._onFullyLoaded !== undefined) {
currentLayer.on("load", () => {
console.log("Fully loaded all tiles!")
self._onFullyLoaded(map)
})
}
map.setMaxBounds(
[[-100, -200], [100, 200]]
@ -105,6 +115,13 @@ export default class Minimap extends BaseUIElement {
map.removeLayer(currentLayer);
}
currentLayer = newLayer;
if (self._onFullyLoaded !== undefined) {
currentLayer.on("load", () => {
console.log("Fully loaded all tiles!")
self._onFullyLoaded(map)
})
}
map.addLayer(newLayer);
})

View file

@ -36,17 +36,7 @@ export default class LayerControlPanel extends ScrollableFullScreen {
undefined,
State.state.featureSwitchEnableExport
))
elements.push(
new Toggle(
new DownloadPanel(),
undefined,
State.state.featureSwitchEnableExport
)
);
return new Combine(elements).SetClass("flex flex-col");
}
return new Combine(elements).SetClass("flex flex-col");
}
}

145
UI/ExportPDF.ts Normal file
View file

@ -0,0 +1,145 @@
/**
* 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 LayoutConfig from "../Customizations/JSON/LayoutConfig";
import {FixedUiElement} from "./Base/FixedUiElement";
import Translations from "./i18n/Translations";
export default class ExportPDF {
// dimensions of the map in milimeter
// A4: 297 * 210mm
private readonly mapW = 297;
private readonly mapH = 210;
private readonly scaling = 2
private readonly freeDivId: string;
private readonly _layout: UIEventSource<LayoutConfig>;
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
const minimap = new Minimap({
location: options.location.map(l => ({
lat : l.lat,
lon: l.lon,
zoom: l.zoom + 1
})),
background: options.background,
allowMoving: true,
onFullyLoaded: leaflet => window.setTimeout(() => {
try{
self.CreatePdf(leaflet)
.then(() => self.cleanup())
.catch(() => self.cleanup())
}catch(e){
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
)
}
private cleanup(){
new FixedUiElement("Screenshot taken!").AttachTo(this.freeDivId)
}
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)
doc.roundedRect(12, 5, 125, 30, 5, 5, 'FD')
doc.setFontSize(20)
doc.text(layout.title.txt, 40, 20, { maxWidth: 100
})
doc.setFontSize(10)
doc.text(t.attr.txt, 40, 25, {
maxWidth: 100
})
// Add the logo of the layout
let img = document.createElement('img');
const imgSource = layout.icon
img.src = imgSource
try {
doc.addImage(img, imgSource.substr(imgSource.lastIndexOf(".")), 15, 12, 20, 20);
} catch (e) {
// TODO: support svg rendering...
console.error(e)
}
doc.save("MapComplete_export.pdf");
}
}

View file

@ -45,8 +45,8 @@ export default class SplitRoadWizard extends Toggle {
const roadElement = State.state.allElements.ContainingFeatures.get(id)
const roadEventSource = new UIEventSource([{feature: roadElement, freshness: new Date()}]);
// Datalayer displaying the road and the cut points (if any)
new ShowDataLayer(roadEventSource, miniMap.leafletMap, State.state.layoutToUse, false, true, "splitRoadWay");
new ShowDataLayer(splitPoints, miniMap.leafletMap, SplitRoadWizard.splitLayout, false, false, "splitRoad: splitpoints")
new ShowDataLayer(roadEventSource, miniMap.leafletMap, State.state.layoutToUse, false, true);
new ShowDataLayer(splitPoints, miniMap.leafletMap, SplitRoadWizard.splitLayout, false, false)
/**
* Handles a click on the overleaf map.

View file

@ -16,14 +16,13 @@ export default class ShowDataLayer {
private readonly _leafletMap: UIEventSource<L.Map>;
private _cleanCount = 0;
private readonly _enablePopups: boolean;
private readonly _features: UIEventSource<{ feature: any, freshness: Date }[]>
private readonly _features: UIEventSource<{ feature: any}[]>
constructor(features: UIEventSource<{ feature: any, freshness: Date }[]>,
constructor(features: UIEventSource<{ feature: any}[]>,
leafletMap: UIEventSource<L.Map>,
layoutToUse: UIEventSource<LayoutConfig>,
enablePopups = true,
zoomToFeatures = false,
name?: string) {
zoomToFeatures = false) {
this._leafletMap = leafletMap;
this._enablePopups = enablePopups;
this._features = features;