2019-11-04 10:59:08 +01:00
import { GeoMap } from './map.js'
import MapView from './mapview.js'
import { EventHandler } from './utils.js'
2019-11-04 18:20:32 +01:00
import { GeoGraphics } from './geographics.js'
2019-11-13 12:42:06 +01:00
import { MapList } from './maplist.js'
2019-11-04 10:59:08 +01:00
//import { GeoGraphics } from "../pixi/geographics.js"
/ * *
* The GeoLayer is a special PIXILayer , that recognizes other GeoLayers and
* GeoGraphics . The layer can be adapted to a map and notifies all Geo - Children
* of the Adaption .
* /
2019-11-04 18:20:32 +01:00
export class GeoLayer {
2019-11-13 12:42:06 +01:00
constructor ( displayObject , opts = { } ) {
2019-11-04 18:20:32 +01:00
if ( displayObject == null || ! ( displayObject instanceof PIXI . DisplayObject ) ) {
console . error (
` You need to provide a displayObject to make a ${ this . constructor . name } out of it. ` ,
displayObject
)
return null
} else {
2019-11-05 11:07:36 +01:00
this . geographics = [ ]
2019-11-13 12:42:06 +01:00
// displayObject.map = this
2019-11-04 18:20:32 +01:00
this . displayObject = displayObject
2019-11-05 11:07:36 +01:00
this . pixiAddChild = displayObject . addChild . bind ( displayObject )
2019-11-04 18:20:32 +01:00
displayObject . addChild = ( ... elements ) => {
elements . forEach ( element => {
if ( element instanceof GeoGraphics ) {
2019-11-13 12:42:06 +01:00
element . setLayer ( this )
2019-11-04 18:20:32 +01:00
this . geographics . push ( element )
2019-11-05 11:07:36 +01:00
this . pixiAddChild ( element . graphics )
2019-11-04 18:20:32 +01:00
} else {
2019-11-05 11:07:36 +01:00
this . pixiAddChild ( element )
2019-11-04 18:20:32 +01:00
}
} )
}
}
2019-11-13 12:42:06 +01:00
this . name = opts [ 'name' ] != null ? opts . name : 'Unnamed Layer'
this . parent = null
this . parentMapLayerTransformedHandler = new EventHandler ( 'onParentMapLayerTransformed' )
this . layers = [ ]
this . _visibility = { min : 0 , max : Number . MAX _VALUE }
}
parentMapLayerTransformed ( mapLayer ) {
this . layers . forEach ( layer => {
if ( ! ( layer instanceof MapList ) ) {
layer . parentMapLayerTransformed ( )
}
} )
this . parentMapLayerTransformedHandler . call ( null , mapLayer )
this . rescaleChildren ( )
}
rescaleChildren ( ) {
let map = this . map
if ( this . rescale ) {
if ( map != null ) {
let scale = map . image . scatter . scale
this . displayObject . children . forEach ( graphics => {
graphics . scale . set ( 1 / scale , 1 / scale )
} )
}
}
let mapLayer = this . mapLayer
if ( this . visibility && mapLayer != null ) {
const zoom = mapLayer . mapview . zoom
// TODO
// Currently I dont know what elemnts was.
// We just log an error and resolve this on a later point.
if ( zoom > this . visibility . min && zoom < this . visibility . max ) {
this . displayObject . children . forEach ( it => ( it . visible = true ) )
} else {
this . displayObject . children . forEach ( it => ( it . visible = false ) )
}
}
}
set visibility ( value ) {
let { min = 0 , max = Infinity } = value
console . log ( min )
this . _visibility = { min , max }
}
get visibility ( ) {
return this . _visibility
2019-11-04 10:59:08 +01:00
}
2019-11-05 11:23:18 +01:00
addChild ( element ) {
this . displayObject . addChild ( element )
}
2019-11-04 10:59:08 +01:00
/ * *
* Adapts to a map . If the maplayer should adapt to the parent maplayer ,
* no parameter must be specified .
* /
adapt ( map = null ) {
if ( ! map ) map = this . map
if ( map ) {
this . geographics . forEach ( geographic => {
geographic . adaptTo ( map )
} )
this . layers . forEach ( layer => {
if ( layer . adapt ) layer . adapt ( map )
} )
2019-11-13 12:42:06 +01:00
this . rescaleChildren ( )
2019-11-04 10:59:08 +01:00
} else console . error ( 'There was no map specified.' , this )
}
2019-11-04 18:20:32 +01:00
// place(geographic) {
// if (geographic.constructor.name.startsWith('Geo') && geographic.graphics) {
// // Fix to remove the rollupjs circular dependency
// //if (geographic instanceof GeoGraphics) {
// this.geographics.push(geographic)
// super.place(geographic.graphics)
// } else super.place(geographic)
// }
2019-11-04 10:59:08 +01:00
2019-11-13 12:42:06 +01:00
removeFromParent ( ) {
if ( this . parent ) {
this . parent . removeLayer ( this )
}
}
removeLayer ( layer ) {
let idx = this . layers . indexOf ( layer )
if ( idx != - 1 ) {
layer . parent = null
this . layers . splice ( idx , 1 )
if ( layer . displayObject . parent ) {
layer . displayObject . parent . removeChild ( layer . displayObject )
}
} else console . warn ( 'Tried to remove layer that was not set.' , this , layer )
}
set parent ( parent ) {
this . _parent = parent
}
get parent ( ) {
return this . _parent
}
2019-11-04 18:20:32 +01:00
addLayer ( layer ) {
2019-11-04 10:59:08 +01:00
if ( layer instanceof GeoLayer || layer instanceof MapLayer ) {
2019-11-13 12:42:06 +01:00
layer . removeFromParent ( )
2019-11-04 18:20:32 +01:00
this . layers . push ( layer )
2019-11-13 12:42:06 +01:00
layer . parent = this
layer . parentChanged ( )
2019-11-04 18:20:32 +01:00
this . displayObject . addChild ( layer . displayObject )
2019-11-04 10:59:08 +01:00
if ( this . map ) layer . geographics . forEach ( geographics => geographics . adaptTo ( this . map ) )
} else
console . error ( 'Could not place layer. Only MapLayer and GeoLayers can be child layers of GeoLayers.' , layer )
}
2019-11-13 12:42:06 +01:00
parentChanged ( ) {
this . rescaleChildren ( )
}
2019-11-04 10:59:08 +01:00
//GeoLayers have to be children of a map layer,
// therefore we can recursively get the map.
get map ( ) {
2019-11-13 12:42:06 +01:00
return this . mapLayer ? this . mapLayer . map : null
2019-11-04 10:59:08 +01:00
}
get mapLayer ( ) {
return this . _mapLayer ? this . _mapLayer : this . parent . mapLayer
}
2019-11-04 18:20:32 +01:00
// clone(mapLayerClone) {
// const opts = {
// mapLayer: mapLayerClone,
// map: mapLayerClone.map
// }
// let geoLayerClone = new GeoLayer(opts)
// this.layers.forEach(layer => {
// let layerClone = layer.clone(opts)
// if (layerClone) {
// geoLayerClone.placeLayer(layerClone)
// }
// })
// this.geographics.forEach(geographics => {
// let clone = geographics.clone()
// if (clone) {
// geoLayerClone.place(clone)
// }
// })
// return geoLayerClone
// }
}
2019-11-04 10:59:08 +01:00
2019-11-04 18:20:32 +01:00
export class MapLayer extends GeoLayer {
constructor (
scatterContainer ,
displayObject ,
2019-11-13 12:42:06 +01:00
{ onTransform = null , onChange = null , focus = null , zoom = null , viewport = null , mapList = null } = { }
2019-11-04 18:20:32 +01:00
) {
super ( displayObject )
this . transformHandler = new EventHandler ( 'onTransform' , {
2019-11-13 12:42:06 +01:00
listeners : onTransform
2019-11-04 10:59:08 +01:00
} )
this . scatterContainer = scatterContainer
this . changeHandler = new EventHandler ( 'onChange' , {
2019-11-04 18:20:32 +01:00
listeners : onChange
2019-11-04 10:59:08 +01:00
} )
2019-11-04 18:20:32 +01:00
this . mapview = new MapView ( {
zoom ,
focus ,
viewport
} )
2019-11-13 12:42:06 +01:00
this . mapList = mapList
2019-11-04 18:20:32 +01:00
this . _map = null
// //TODO Implement error handling here.
// this.maps = maps
// if (opts.map) this.placeMap(opts.map)
2019-11-04 10:59:08 +01:00
this . dynamicElements = new Map ( )
}
adapt ( ) {
this . layers . forEach ( layer => {
if ( layer . adapt ) layer . adapt ( this . map )
} )
}
2019-11-04 18:20:32 +01:00
// placeLayer(layer) {
// super.placeLayer(layer)
// if (layer instanceof GeoLayer && this.map) {
// layer.adapt(this.map)
// }
// }
2019-11-04 10:59:08 +01:00
transformed ( e ) {
2019-11-04 18:20:32 +01:00
this . mapview . transformed ( this . map )
2019-11-13 12:42:06 +01:00
this . layers . forEach ( layer => layer . parentMapLayerTransformed ( this ) )
2019-11-04 10:59:08 +01:00
this . transformHandler . call ( this )
}
clone ( container = null ) {
let clone = { }
for ( let name of Object . keys ( this . maps ) ) {
//console.info(this.maps[name])
clone [ name ] = this . maps [ name ] . clone ( container )
}
//console.info(this.active)
let mapLayerClone = new MapLayer ( this . active , clone , container , {
name : MapLayer . idx ++ ,
viewport : this . mapview . viewport ,
focus : this . mapview . focus ,
zoom : this . mapview . zoom
} )
//mapLayerClone._map = clone['luftbild']
mapLayerClone . childrenVisibility = this . childrenVisibility
return mapLayerClone
}
2019-11-05 11:07:36 +01:00
/ * *
* Changes the map to the specified one , keeping the position and the zoom of the old map .
*
* @ public
* @ param { GeoMap } map
* @ memberof MapLayer
* /
2019-11-04 10:59:08 +01:00
changeMap (
2019-11-05 11:07:36 +01:00
map / * ,
useScatterAsContainer = true // If set to false, the normal container is used. This is necessary when using submaps and the container need to be a RigidContainer.*/
2019-11-04 10:59:08 +01:00
) {
2019-11-05 11:07:36 +01:00
if ( map instanceof GeoMap ) {
2019-11-13 12:42:06 +01:00
console . log ( 'Change map to: ' , map )
2019-11-05 11:07:36 +01:00
let oldMap = this . map
if ( oldMap ) oldMap . unload ( )
this . _map = map
2019-11-04 18:20:32 +01:00
2019-11-05 11:07:36 +01:00
this . map . load ( )
this . scatterContainer . addChild ( this . map . image )
2019-11-13 12:42:06 +01:00
this . mapview . apply ( this . map )
2019-11-05 11:07:36 +01:00
map . image . addChild ( this . displayObject )
2019-11-04 18:20:32 +01:00
2019-11-05 11:07:36 +01:00
// A geolayer's displayObject is on the parent layer.
// A maplayer's displayobject is always the child of the map.
this . adapt ( )
this . changeHandler . call ( this , map , oldMap )
2019-11-05 11:23:18 +01:00
//Call transform one time manually.
this . transformed ( )
this . map . onTransform . add ( this . transformed . bind ( this ) )
2019-11-05 11:07:36 +01:00
} else {
console . error ( "Could not set map, it's not of type GeoMap." , map )
}
2019-11-04 18:20:32 +01:00
/ * L o g g i n g . l o g ( ` M a p c h a n g e : $ { k e y } ` )
2019-11-04 10:59:08 +01:00
if ( this . active !== key ) {
if ( this . maps . hasOwnProperty ( key ) ) {
let old = this . map ? this . map : null
this . _map = this . maps [ key ]
this . _map . name = key
this . active = key
let container = useScatterAsContainer ? this . scatterContainer : this . container
this . map . load ( container )
// Copies all layers.
this . layers . forEach ( layer => {
if ( old ) this . map . image . addChild ( layer . container )
} )
this . placeMap ( this . map )
/ * *
* TODO : Improve
*
* I ' m quite sure if I made a design mistake here .
* In an earlier version I did not need to migrate the
* layers manually from the map to the next map .
*
* I believe the old version was a container next to the
* map , which got updated on transform .
*
* - SO
* /
2019-11-04 18:20:32 +01:00
/ *
2019-11-04 10:59:08 +01:00
if ( old ) old . unload ( )
2019-11-04 18:20:32 +01:00
2019-11-04 10:59:08 +01:00
} else {
let keys = Object . keys ( this . maps )
if ( keys . length == 0 ) console . error ( 'There is no map set for the map layer!' )
else {
let fallbackMap = keys [ 0 ]
console . error (
` A map with the key ( ${ key } ) does not exists within the mapapp. Fallback to map: ${ fallbackMap } . `
)
this . changeMap ( fallbackMap , {
useScatterAsContainer
} )
}
}
2019-11-04 18:20:32 +01:00
} * /
2019-11-04 10:59:08 +01:00
}
get map ( ) {
return this . _map
}
/ * *
* This is required for the consistency of georelated layers .
* The request traverses up to the mapLayer where it then returns
* the responsible map layer .
* /
get mapLayer ( ) {
return this
}
}
MapLayer . idx = 0