mapcomplete/UI/BigComponents/DownloadPanel.ts

114 lines
No EOL
4.3 KiB
TypeScript

import {SubtleButton} from "../Base/SubtleButton";
import Svg from "../../Svg";
import Translations from "../i18n/Translations";
import State from "../../State";
import {Utils} from "../../Utils";
import Combine from "../Base/Combine";
import CheckBoxes from "../Input/Checkboxes";
import {BBox, GeoOperations} from "../../Logic/GeoOperations";
import Toggle from "../Input/Toggle";
import Title from "../Base/Title";
import FeaturePipeline from "../../Logic/FeatureSource/FeaturePipeline";
import {UIEventSource} from "../../Logic/UIEventSource";
import SimpleMetaTagger from "../../Logic/SimpleMetaTagger";
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
import {meta} from "@turf/turf";
export class DownloadPanel extends Toggle {
constructor() {
const state: {
featurePipeline: FeaturePipeline,
layoutToUse: UIEventSource<LayoutConfig>,
currentBounds: UIEventSource<BBox>
} = State.state
const t = Translations.t.general.download
const name = State.state.layoutToUse.data.id;
const includeMetaToggle = new CheckBoxes([t.includeMetaData.Clone()])
const metaisIncluded = includeMetaToggle.GetValue().map(selected => selected.length > 0)
const buttonGeoJson = new SubtleButton(Svg.floppy_ui(),
new Combine([t.downloadGeojson.Clone().SetClass("font-bold"),
t.downloadGeoJsonHelper.Clone()]).SetClass("flex flex-col"))
.onClick(() => {
const geojson = DownloadPanel.getCleanGeoJson(state, metaisIncluded.data)
Utils.offerContentsAsDownloadableFile(JSON.stringify(geojson, null, " "),
`MapComplete_${name}_export_${new Date().toISOString().substr(0, 19)}.geojson`, {
mimetype: "application/vnd.geo+json"
});
})
const buttonCSV = new SubtleButton(Svg.floppy_ui(), new Combine(
[t.downloadCSV.Clone().SetClass("font-bold"),
t.downloadCSVHelper.Clone()]).SetClass("flex flex-col"))
.onClick(() => {
const geojson = DownloadPanel.getCleanGeoJson(state, metaisIncluded.data)
const csv = GeoOperations.toCSV(geojson.features)
Utils.offerContentsAsDownloadableFile(csv,
`MapComplete_${name}_export_${new Date().toISOString().substr(0, 19)}.csv`, {
mimetype: "text/csv"
});
})
const downloadButtons = new Combine(
[new Title(t.title),
buttonGeoJson,
buttonCSV,
includeMetaToggle,
t.licenseInfo.Clone().SetClass("link-underline")])
.SetClass("w-full flex flex-col border-4 border-gray-300 rounded-3xl p-4")
super(
downloadButtons,
t.noDataLoaded.Clone(),
state.featurePipeline.somethingLoaded)
}
private static getCleanGeoJson(state: {
featurePipeline: FeaturePipeline,
currentBounds: UIEventSource<BBox>
}, includeMetaData: boolean) {
const resultFeatures = []
const featureList = state.featurePipeline.GetAllFeaturesWithin(state.currentBounds.data);
for (const tile of featureList) {
for (const feature of tile) {
const cleaned = {
type: feature.type,
geometry: feature.geometry,
properties: {...feature.properties}
}
if (!includeMetaData) {
for (const key in cleaned.properties) {
if (key === "_lon" || key === "_lat") {
continue;
}
if (key.startsWith("_")) {
delete feature.properties[key]
}
}
}
const datedKeys = [].concat(SimpleMetaTagger.metatags.filter(tagging => tagging.includesDates).map(tagging => tagging.keys))
for (const key of datedKeys) {
delete feature.properties[key]
}
resultFeatures.push(feature)
}
}
return {
type:"FeatureCollection",
features: resultFeatures
}
}
}