2019-11-04 10:59:08 +01:00
import { GeoMap } from './map.js'
import MapView from './mapview.js'
import { EventHandler } from './utils.js'
import { PIXILayer } from '../../../../src/layers/js/layer.js'
import Logging from '../../logging.js'
2019-11-04 18:20:32 +01:00
import { GeoGraphics } from './geographics.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 {
constructor ( displayObject ) {
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-04 18:20:32 +01:00
displayObject . map = this
this . displayObject = displayObject
this . layers = [ ]
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 ) {
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-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 )
} )
} 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-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-04 18:20:32 +01:00
this . layers . push ( layer )
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 )
}
//GeoLayers have to be children of a map layer,
// therefore we can recursively get the map.
get map ( ) {
2019-11-04 18:20:32 +01:00
return this . _mapLayer . map
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 ,
{ onTransform = null , onChange = null , focus = null , zoom = null , viewport = null } = { }
) {
super ( displayObject )
let onTransformListeners = [
( ) => {
2019-11-04 10:59:08 +01:00
this . labelVisibility ( )
}
2019-11-04 18:20:32 +01:00
]
if ( onTransform ) onTransformListeners . push ( onTransform )
this . transformHandler = new EventHandler ( 'onTransform' , {
listeners : onTransformListeners
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
} )
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 ( )
}
labelVisibility ( ) {
const visibility = this . childrenVisibility
if ( visibility ) {
const zoom = this . mapview . zoom
const min = visibility . min || 0
const max = visibility . max || Number . MAX _VALUE
if ( zoom > min && zoom < max ) {
this . elements . forEach ( it => ( it . visible = true ) )
this . elements . forEach ( it => {
const scale = 1 / it . parent . scale . x
// it.children are poi groups
// it.children[0] is the poi group of the tübingen poi
// it.children[0].children are the text containers (not PIXI.Text), about 20 pieces
if ( it . children . length > 0 ) {
it . children [ 0 ] . children . forEach ( poi => {
if ( poi . children . length === 1 ) {
poi . scale . set ( scale , scale )
}
} )
}
} )
} else {
this . elements . forEach ( it => ( it . visible = false ) )
}
}
}
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-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 ) {
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 )
map . image . addChild ( this . displayObject )
this . mapview . update ( this . map )
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