import Kernel from './Kernel' ; import Utils from './Utils' ; import Renderer from './Renderer' ; import Camera , { CameraCore } from './Camera' ; import Scene from './Scene' ; import ImageUtils from './Image' ; import EventHandler from './EventHandler' ; import TiledLayer from './layers/TiledLayer' ; import { GoogleTiledLayer } from './layers/Google' ; import { AutonaviTiledLayer , AutonaviLabelLayer } from './layers/Autonavi' ; import LabelLayer from './layers/LabelLayer' ; import TrafficLayer from './layers/TrafficLayer' ; import Atmosphere from './graphics/Atmosphere' ; import LocationGraphic from './graphics/LocationGraphic' ; import PoiLayer from './layers/PoiLayer' ; import RouteLayer from './layers/RouteLayer' ; import Extent from './Extent' ; import Service , { Location } from './Service' ; import { WebGLRenderingContextExtension } from './Definitions.d' ; import { devicePixelRatio } from './Env' ; const initLevel = Utils . isMobile ( ) ? 11 : 3 ; const initLonlat = [ 116.3975 , 39.9085 ] ; type RenderCallback = ( ) => void ; export class GlobeOptions { pauseRendering : boolean = false ; satellite : boolean = true ; level : number | 'auto' = 'auto' ; lonlat : number [ ] | 'auto' = 'auto' ; key : string = "" ; resolutionFactor : number ; } export default class Globe { renderer : Renderer = null ; scene : Scene = null ; camera : Camera = null ; tiledLayer : TiledLayer = null ; labelLayer : LabelLayer = null ; trafficLayer : TrafficLayer = null ; poiLayer : PoiLayer = null ; routeLayer : RouteLayer = null ; locationGraphic : LocationGraphic = null ; debugStopRefreshTiles : boolean = false ; private readonly REFRESH_INTERVAL : number = 150 ; private lastRefreshTimestamp : number = - 1 ; private lastRefreshCameraCore : CameraCore = null ; private eventHandler : EventHandler = null ; private allRefreshCount : number = 0 ; private realRefreshCount : number = 0 ; private width : number = 0 ; private height : number = 0 ; private afterRenderCallbacks : RenderCallback [ ] = [ ] ; public gl : WebGLRenderingContextExtension = null ; private static globe : Globe = null ; static getInstance ( options ? ) { if ( ! this . globe ) { const canvas = document . createElement ( "canvas" ) ; const width = document . documentElement . clientWidth ; const height = document . documentElement . clientHeight ; this . globe = new Globe ( canvas , width , height , options ) ; } return this . globe ; } private constructor ( public canvas , width , height , private options ? ) { if ( ! this . options ) { this . options = new GlobeOptions ( ) ; } this . resizeCanvas ( width , height ) ; this . renderer = new Renderer ( canvas , this . _onBeforeRender . bind ( this ) , this . _onAfterRender . bind ( this ) ) ; this . gl = this . renderer . gl ; this . scene = new Scene ( ) ; const radio = this . width / this . height ; let level = this . options . level >= 0 ? ( this . options . level as number ) : initLevel ; let lonlat = ( this . options . lonlat && this . options . lonlat . length === 2 ) ? ( this . options . lonlat as number [ ] ) : initLonlat ; this . camera = new Camera ( width , height , 30 , radio , 1 , Kernel . EARTH_RADIUS * 2 , level , lonlat , options . resolutionFactor ) ; this . renderer . setScene ( this . scene ) ; this . renderer . setCamera ( this . camera ) ; if ( this . options . satellite ) { this . _setTiledLayer ( new GoogleTiledLayer ( "Default" ) , this . options . pauseRendering ) ; } else { this . _setTiledLayer ( new AutonaviTiledLayer ( ) , this . options . pauseRendering ) ; } var atmosphere = Atmosphere . getInstance ( ) ; this . scene . add ( atmosphere ) ; this . routeLayer = RouteLayer . getInstance ( this . camera , this . options . key ) ; this . scene . add ( this . routeLayer ) ; this . poiLayer = PoiLayer . getInstance ( ) ; this . poiLayer . globe = this ; this . scene . add ( this . poiLayer ) ; this . locationGraphic = LocationGraphic . getInstance ( this ) ; this . scene . add ( this . locationGraphic ) ; this . eventHandler = new EventHandler ( this ) ; if ( this . options . pauseRendering !== true ) { this . renderer . resumeRendering ( ) ; } const locationCallback = ( location ) => { if ( location ) { this . afterRenderCallbacks . push ( ( ) => { this . updateUserLocation ( location ) ; } ) ; } } ; Service . getCurrentPosition ( false ) . then ( locationCallback ) . then ( ( ) => { if ( Utils . isMobile ( ) ) { Service . getCurrentPosition ( true ) . then ( locationCallback ) ; } } ) ; } placeAt ( container ) { if ( this . canvas . parentNode ) { if ( this . canvas . parentNode !== container ) { container . appendChild ( this . canvas ) ; } } else { container . appendChild ( this . canvas ) ; } } public getWidth ( ) { return this . width ; } public getHeight ( ) { return this . height ; } public resize ( width , height ) { this . resizeCanvas ( width , height ) ; this . renderer . updateViewportSize ( ) ; this . camera . setSize ( width , height ) ; Utils . publish ( "extent-change" ) ; } private resizeCanvas ( width , height ) { this . width = width ; this . height = height ; this . canvas . width = width * devicePixelRatio ; this . canvas . height = height * devicePixelRatio ; this . canvas . style . width = `${ width }px` ; this . canvas . style . height = `${ height }px` ; } private updateUserLocation ( location ) { this . locationGraphic . setLonLat ( location . lon , location . lat ) ; let [ lon , lat ] = this . camera . getLonlat ( ) ; if ( this . options . lonlat === 'auto' ) { lon = location . lon ; lat = location . lat ; } let level = this . getLevel ( ) ; if ( this . options . level === 'auto' ) { level = 8 ; if ( location . accuracy <= 100 ) { level = 16 ; } else if ( location . accuracy <= 1000 ) { level = 13 ; } else { level = 11 ; } } this . centerTo ( lon , lat , level ) ; } getLonlat ( ) { return this . camera . getLonlat ( ) ; } isRenderingPaused ( ) { return this . renderer . isRenderingPaused ( ) ; } pauseRendering ( ) { this . renderer . pauseRendering ( ) ; } resumeRendering ( ) { this . renderer . resumeRendering ( ) ; this . refresh ( true ) ; } private _setTiledLayer ( tiledLayer , dontRefresh = false ) { ImageUtils . clear ( ) ; if ( this . tiledLayer ) { var b = this . scene . remove ( this . tiledLayer ) ; if ( ! b ) { console . error ( "this.scene.remove(this.tiledLayer)失败" ) ; } this . scene . tiledLayer = null ; } tiledLayer . globe = this ; this . tiledLayer = tiledLayer ; this . scene . add ( this . tiledLayer , true ) ; if ( ! dontRefresh ) { this . refresh ( true ) ; } } showLabelLayer ( ) { if ( this . labelLayer ) { this . labelLayer . visible = true ; } } hideLabelLayer ( ) { if ( this . labelLayer ) { this . labelLayer . visible = false ; } } showTrafficLayer ( ) { if ( this . trafficLayer ) { this . trafficLayer . visible = true ; } } hideTrafficLayer ( ) { if ( this . trafficLayer ) { this . trafficLayer . visible = false ; } } getLevel ( ) { return this . camera . getLevel ( ) ; } zoomIn ( ) { this . setLevel ( this . getLevel ( ) + 1 ) ; } setLevel ( level ) { if ( this . camera ) { this . camera . setLevel ( level ) ; } } centerTo ( lon , lat , level = this . getLevel ( ) ) { return this . camera . centerTo ( lon , lat , level ) ; } animateTo ( newLon , newLat , newLevel = this . getLevel ( ) , duration = 1000 ) { return this . camera . animateTo ( newLon , newLat , newLevel , duration ) ; } setExtent ( extent ) { return this . camera . setExtent ( extent ) ; } animateToExtent ( extent , duration = 1000 ) { return this . camera . animateToExtent ( extent , duration ) ; } isAnimating ( ) { return this . camera . isAnimating ( ) ; } animateToLevel ( level , cb ? ) { if ( ! this . isAnimating ( ) ) { if ( level < Kernel . MIN_LEVEL ) { level = Kernel . MIN_LEVEL ; } if ( level > Kernel . MAX_LEVEL ) { level = Kernel . MAX_LEVEL ; } if ( level !== this . getLevel ( ) ) { this . camera . animateToLevel ( level , cb ) ; } } } animateOut ( cb ? ) { this . animateToLevel ( this . getLevel ( ) - 1 , cb ) ; } animateIn ( cb ? ) { this . animateToLevel ( this . getLevel ( ) + 1 , cb ) ; } private _onBeforeRender ( renderer ) { this . refresh ( ) ; } private _onAfterRender ( render ) { this . afterRenderCallbacks . forEach ( ( callback ) => callback ( ) ) ; this . afterRenderCallbacks = [ ] ; } logRefreshInfo ( ) { console . log ( this . realRefreshCount , this . allRefreshCount , this . realRefreshCount / this . allRefreshCount ) ; } refresh ( force = false ) { this . allRefreshCount ++ ; var timestamp = Date . now ( ) ; this . camera . update ( force ) ; if ( ! this . tiledLayer || ! this . scene || ! this . camera ) { return ; } if ( this . debugStopRefreshTiles ) { return ; } var newCameraCore = this . camera . getCameraCore ( ) ; var isNeedRefresh = false ; if ( force ) { isNeedRefresh = true ; } else { if ( this . isRenderingPaused ( ) ) { isNeedRefresh = false ; } else { if ( newCameraCore . equals ( this . lastRefreshCameraCore ) ) { isNeedRefresh = false ; } else { isNeedRefresh = timestamp - this . lastRefreshTimestamp >= this . REFRESH_INTERVAL ; } } } this . tiledLayer . updateSubLayerCount ( ) ; if ( isNeedRefresh ) { this . realRefreshCount ++ ; this . lastRefreshTimestamp = timestamp ; this . lastRefreshCameraCore = newCameraCore ; this . tiledLayer . refresh ( ) ; } this . tiledLayer . updateTileVisibility ( ) ; if ( ! this . isRenderingPaused ( ) ) { var a = ! ! ( this . labelLayer && this . labelLayer . visible ) ; var b = ! ! ( this . trafficLayer && this . trafficLayer . visible ) ; if ( a || b ) { var lastLevelTileGrids = this . tiledLayer . getLastLevelVisibleTileGrids ( ) ; if ( a ) { this . labelLayer . updateTiles ( this . getLevel ( ) , lastLevelTileGrids ) ; } if ( b ) { this . trafficLayer . updateTiles ( this . getLevel ( ) , lastLevelTileGrids ) ; } } } } getExtent ( ) { const extents = [ ] ; var layerExtent = this . tiledLayer . getExtent ( ) ; if ( layerExtent ) { extents . push ( layerExtent ) ; } var cameraExtent = this . camera . getExtent ( ) ; if ( cameraExtent ) { extents . push ( cameraExtent ) ; } if ( extents . length === 0 ) { return null ; } else if ( extents . length === 1 ) { return extents [ 0 ] ; } else { return Extent . intersect ( extents ) ; } } pick ( canvasX , canvasY ) { const pickInfo = this . camera . getPickInfoByCanvas ( canvasX , canvasY , false ) ; const line = pickInfo . line ; this . scene . pickByWorldLine ( line ) ; } test ( ) { this . debugStopRefreshTiles = true ; this . labelLayer . hideAllTiles ( ) ; this . tiledLayer . children . forEach ( ( subLayer ) => subLayer . hideAllTiles ( ) ) ; var subLayer = this . tiledLayer . children [ this . tiledLayer . children . length - 1 ] ; subLayer . visible = true ; subLayer . children [ 0 ] . visible = true ; return subLayer ; } } ;