2022-01-19 20:34:04 +01:00
import Combine from "../Base/Combine" ;
import { UIEventSource } from "../../Logic/UIEventSource" ;
import { BBox } from "../../Logic/BBox" ;
import UserRelatedState from "../../Logic/State/UserRelatedState" ;
import Translations from "../i18n/Translations" ;
import { AllKnownLayouts } from "../../Customizations/AllKnownLayouts" ;
import Constants from "../../Models/Constants" ;
import { DropDown } from "../Input/DropDown" ;
import { Utils } from "../../Utils" ;
import LayerConfig from "../../Models/ThemeConfig/LayerConfig" ;
import BaseLayer from "../../Models/BaseLayer" ;
import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers" ;
import Loc from "../../Models/Loc" ;
import Minimap from "../Base/Minimap" ;
import Attribution from "../BigComponents/Attribution" ;
import ShowDataMultiLayer from "../ShowDataLayer/ShowDataMultiLayer" ;
import FilteredLayer , { FilterState } from "../../Models/FilteredLayer" ;
import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource" ;
import Toggle from "../Input/Toggle" ;
import Table from "../Base/Table" ;
import { VariableUiElement } from "../Base/VariableUIElement" ;
import { FixedUiElement } from "../Base/FixedUiElement" ;
import { FlowStep } from "./FlowStep" ;
2022-01-21 01:57:16 +01:00
import ScrollableFullScreen from "../Base/ScrollableFullScreen" ;
import { AllTagsPanel } from "../SpecialVisualizations" ;
import Title from "../Base/Title" ;
class PreviewPanel extends ScrollableFullScreen {
constructor ( tags , layer ) {
super (
_ = > new FixedUiElement ( "Element to import" ) ,
_ = > new Combine ( [ "The tags are:" ,
new AllTagsPanel ( tags )
] ) . SetClass ( "flex flex-col" ) ,
"element"
) ;
}
}
2022-01-19 20:34:04 +01:00
/ * *
* Shows the data to import on a map , asks for the correct layer to be selected
* /
export class DataPanel extends Combine implements FlowStep < { bbox : BBox , layer : LayerConfig , geojson : any } > {
public readonly IsValid : UIEventSource < boolean > ;
public readonly Value : UIEventSource < { bbox : BBox , layer : LayerConfig , geojson : any } >
constructor (
state : UserRelatedState ,
geojson : { features : { properties : any , geometry : { coordinates : [ number , number ] } } [ ] } ) {
const t = Translations . t . importHelper ;
const propertyKeys = new Set < string > ( )
for ( const f of geojson . features ) {
Object . keys ( f . properties ) . forEach ( key = > propertyKeys . add ( key ) )
}
const availableLayers = AllKnownLayouts . AllPublicLayers ( ) . filter ( l = > l . name !== undefined && Constants . priviliged_layers . indexOf ( l . id ) < 0 )
const layerPicker = new DropDown ( "Which layer does this import match with?" ,
[ { shown : t.selectLayer , value : undefined } ] . concat ( availableLayers . map ( l = > ( {
shown : l.name ,
value : l
} ) ) )
)
let autodetected = new UIEventSource ( false )
for ( const layer of availableLayers ) {
const mismatched = geojson . features . some ( f = >
! layer . source . osmTags . matchesProperties ( f . properties )
)
if ( ! mismatched ) {
2022-01-21 01:57:16 +01:00
console . log ( "Autodected layer" , layer . id )
2022-01-19 20:34:04 +01:00
layerPicker . GetValue ( ) . setData ( layer ) ;
layerPicker . GetValue ( ) . addCallback ( _ = > autodetected . setData ( false ) )
autodetected . setData ( true )
break ;
}
}
const withId = geojson . features . map ( ( f , i ) = > {
const copy = Utils . Clone ( f )
copy . properties . id = "to-import/" + i
return copy
} )
const matching : UIEventSource < { properties : any , geometry : { coordinates : [ number , number ] } } [ ] > = layerPicker . GetValue ( ) . map ( ( layer : LayerConfig ) = > {
if ( layer === undefined ) {
return undefined ;
}
const matching : { properties : any , geometry : { coordinates : [ number , number ] } } [ ] = [ ]
for ( const feature of withId ) {
if ( layer . source . osmTags . matchesProperties ( feature . properties ) ) {
matching . push ( feature )
}
}
return matching
} )
const background = new UIEventSource < BaseLayer > ( AvailableBaseLayers . osmCarto )
const location = new UIEventSource < Loc > ( { lat : 0 , lon : 0 , zoom : 1 } )
const currentBounds = new UIEventSource < BBox > ( undefined )
const map = Minimap . createMiniMap ( {
allowMoving : true ,
location ,
background ,
bounds : currentBounds ,
attribution : new Attribution ( location , state . osmConnection . userDetails , undefined , currentBounds )
} )
map . SetClass ( "w-full" ) . SetStyle ( "height: 500px" )
new ShowDataMultiLayer ( {
2022-01-21 01:57:16 +01:00
layers : new UIEventSource < FilteredLayer [ ] > ( AllKnownLayouts . AllPublicLayers ( )
. filter ( l = > l . source . geojsonSource === undefined )
. map ( l = > ( {
2022-01-19 20:34:04 +01:00
layerDef : l ,
isDisplayed : new UIEventSource < boolean > ( true ) ,
appliedFilters : new UIEventSource < Map < string , FilterState > > ( undefined )
} ) ) ) ,
zoomToFeatures : true ,
features : new StaticFeatureSource ( matching , false ) ,
leafletMap : map.leafletMap ,
2022-01-21 01:57:16 +01:00
popup : ( tag , layer ) = > new PreviewPanel ( tag , layer ) . SetClass ( "font-lg" )
2022-01-19 20:34:04 +01:00
} )
var bbox = matching . map ( feats = > BBox . bboxAroundAll ( feats . map ( f = > new BBox ( [ f . geometry . coordinates ] ) ) ) )
super ( [
2022-01-21 01:57:16 +01:00
new Title ( geojson . features . length + " features to import" ) ,
2022-01-19 20:34:04 +01:00
layerPicker ,
new Toggle ( "Automatically detected layer" , undefined , autodetected ) ,
new Table ( [ "" , "Key" , "Values" , "Unique values seen" ] ,
Array . from ( propertyKeys ) . map ( key = > {
const uniqueValues = Utils . Dedup ( Utils . NoNull ( geojson . features . map ( f = > f . properties [ key ] ) ) )
uniqueValues . sort ( )
return [ geojson . features . filter ( f = > f . properties [ key ] !== undefined ) . length + "" , key , uniqueValues . join ( ", " ) , "" + uniqueValues . length ]
} )
) . SetClass ( "zebra-table table-auto" ) ,
new VariableUiElement ( matching . map ( matching = > {
if ( matching === undefined ) {
return undefined
}
const diff = geojson . features . length - matching . length ;
if ( diff === 0 ) {
return undefined
}
const obligatory = layerPicker . GetValue ( ) . data ? . source ? . osmTags ? . asHumanString ( false , false , { } ) ;
return new FixedUiElement ( ` ${ diff } features will _not_ match this layer. Make sure that all obligatory objects are present: ${ obligatory } ` ) . SetClass ( "alert" ) ;
} ) ) ,
map
] ) ;
this . Value = bbox . map ( bbox = >
( {
bbox ,
geojson ,
layer : layerPicker.GetValue ( ) . data
} ) , [ layerPicker . GetValue ( ) ] )
this . IsValid = matching . map ( matching = > {
if ( matching === undefined ) {
return false
}
const diff = geojson . features . length - matching . length ;
return diff === 0 ;
} )
}
}