import { Geometry } from "./geometry/geometry" ; import { Bound } from "./util/bound" ; import { Projection } from "./projection/projection" ; import { WebMercator } from "./projection/web-mercator" ; import { Layer } from "./layer/layer" ; import { GraphicLayer } from "./layer/graphic-layer" ; import { Graphic } from "./element/graphic" ; export class Map { private _container : HTMLDivElement ; private _canvas : HTMLCanvasElement ; private _ctx : CanvasRenderingContext2D ; private _drag : any = { flag : false , start : { x : 0 , y : 0 } , end : { x : 0 , y : 0 } } ; private _defaultGraphicLayer : GraphicLayer = new GraphicLayer ( ) ; private _layers : Layer [ ] = [ ] ; private _zoom : number = 1 ; private _center : number [ ] = [ 0 , 0 ] ; private _extent : Bound ; private _projection : Projection ; private _events : any = { "move" : [ ] , "extent" : [ ] } ; get projection ( ) : Projection { return this . _projection ; } constructor ( id ) { this . _container = id instanceof HTMLDivElement ? id : document . getElementById ( id ) as HTMLDivElement ; this . _canvas = document . createElement ( "canvas" ) ; this . _canvas . style . cssText = "position: absolute; height: 100%; width: 100%; z-index: 100" ; this . _canvas . width = this . _container . clientWidth ; this . _canvas . height = this . _container . clientHeight ; this . _container . appendChild ( this . _canvas ) ; this . _ctx = this . _canvas . getContext ( "2d" ) ; this . _onDoubleClick = this . _onDoubleClick . bind ( this ) ; this . _onMouseDown = this . _onMouseDown . bind ( this ) ; this . _onMouseMove = this . _onMouseMove . bind ( this ) ; this . _onMouseUp = this . _onMouseUp . bind ( this ) ; this . _onWheel = this . _onWheel . bind ( this ) ; this . _canvas . addEventListener ( "dblclick" , this . _onDoubleClick ) ; this . _canvas . addEventListener ( "mousedown" , this . _onMouseDown ) ; this . _canvas . addEventListener ( "mousemove" , this . _onMouseMove ) ; this . _canvas . addEventListener ( "mouseup" , this . _onMouseUp ) ; this . _canvas . addEventListener ( "wheel" , this . _onWheel ) ; this . _projection = new WebMercator ( ) ; this . setView ( [ 0 , 0 ] , 10 ) ; this . _onResize = this . _onResize . bind ( this ) ; window . addEventListener ( "resize" , this . _onResize ) ; } on ( event , handler ) { this . _events [ event ] . push ( handler ) ; } setProjection ( projection ) { this . _projection = projection ; const origin = this . _projection . project ( this . _center as any ) ; const bound = this . _projection . bound ; const a = 256 * Math . pow ( 2 , this . _zoom ) / ( bound . xmax - bound . xmin ) * bound . xscale ; const d = 256 * Math . pow ( 2 , this . _zoom ) / ( bound . ymax - bound . ymin ) * bound . yscale ; const e = this . _canvas . width / 2 - a * origin [ 0 ] ; const f = this . _canvas . height / 2 - d * origin [ 1 ] ; this . _ctx . setTransform ( a , 0 , 0 , d , e , f ) ; } setView ( center = [ 0 , 0 ] , zoom = 3 ) { this . _center = center ; this . _zoom = Math . max ( 3 , Math . min ( 20 , zoom ) ) ; const origin = this . _projection . project ( center as any ) ; const bound = this . _projection . bound ; const a = 256 * Math . pow ( 2 , this . _zoom ) / ( bound . xmax - bound . xmin ) * bound . xscale ; const d = 256 * Math . pow ( 2 , this . _zoom ) / ( bound . ymax - bound . ymin ) * bound . yscale ; const e = this . _canvas . width / 2 - a * origin [ 0 ] ; const f = this . _canvas . height / 2 - d * origin [ 1 ] ; this . _ctx . setTransform ( a , 0 , 0 , d , e , f ) ; this . redraw ( ) ; } addLayer ( layer ) { this . _layers . push ( layer ) ; layer . draw ( this . _ctx , this . _projection , this . _extent ) ; } addGraphic ( graphic ) { this . _defaultGraphicLayer . add ( graphic ) ; graphic . draw ( this . _ctx , this . _projection , this . _extent ) ; } updateExtent ( ) { const matrix = ( this . _ctx as any ) . getTransform ( ) ; const x1 = ( 0 - matrix . e ) / matrix . a , y1 = ( 0 - matrix . f ) / matrix . d , x2 = ( this . _canvas . width - matrix . e ) / matrix . a , y2 = ( this . _canvas . height - matrix . f ) / matrix . d ; this . _extent = new Bound ( Math . min ( x1 , x2 ) , Math . min ( y1 , y2 ) , Math . max ( x1 , x2 ) , Math . max ( y1 , y2 ) ) ; this . _center = this . _projection . unproject ( [ ( x1 + x2 ) / 2 , ( y1 + y2 ) / 2 ] ) ; this . _events . extent . forEach ( handler => handler ( { extent : this . _extent , center : this . _center , zoom : this . _zoom , matrix : matrix } ) ) ; } redraw ( ) { this . _ctx . save ( ) ; this . _ctx . setTransform ( 1 , 0 , 0 , 1 , 0 , 0 ) ; this . _ctx . clearRect ( 0 , 0 , this . _canvas . width , this . _canvas . height ) ; this . _ctx . restore ( ) ; this . updateExtent ( ) ; this . _defaultGraphicLayer . draw ( this . _ctx , this . _projection , this . _extent ) ; this . _layers . forEach ( layer => { layer . draw ( this . _ctx , this . _projection , this . _extent ) ; } ) ; } clear ( ) { this . _ctx . setTransform ( 1 , 0 , 0 , 1 , 0 , 0 ) ; this . _ctx . clearRect ( 0 , 0 , this . _canvas . width , this . _canvas . height ) ; } _onResize ( event ) { this . _canvas . width = this . _container . clientWidth ; this . _canvas . height = this . _container . clientHeight ; this . setView ( this . _center , this . _zoom ) ; } _onDoubleClick ( event ) { if ( this . _zoom >= 20 ) return ; const scale = 2 ; this . _zoom += 1 ; const matrix = ( this . _ctx as any ) . getTransform ( ) ; const a1 = matrix . a , e1 = matrix . e , x1 = event . x , x2 = x1 ; const e = ( x2 - scale * ( x1 - e1 ) - e1 ) / a1 ; const d1 = matrix . d , f1 = matrix . f , y1 = event . y , y2 = y1 ; const f = ( y2 - scale * ( y1 - f1 ) - f1 ) / d1 ; this . _ctx . transform ( scale , 0 , 0 , scale , e , f ) ; this . redraw ( ) ; } _onMouseDown ( event ) { this . _drag . flag = true ; this . _drag . start . x = event . x ; this . _drag . start . y = event . y ; } _onMouseMove ( event ) { } _onMouseUp ( event ) { if ( this . _drag . flag ) { this . _drag . end . x = event . x ; this . _drag . end . y = event . y ; const matrix = ( this . _ctx as any ) . getTransform ( ) ; this . _ctx . translate ( ( this . _drag . end . x - this . _drag . start . x ) / matrix . a , ( this . _drag . end . y - this . _drag . start . y ) / matrix . d ) ; this . redraw ( ) ; } this . _drag . flag = false ; } _onWheel ( event ) { event . preventDefault ( ) ; const sensitivity = 5 ; if ( Math . abs ( event . deltaY ) <= sensitivity ) return ; const delta = event . deltaY < 0 ? - 1 : 1 ; let scale = 1 ; if ( delta < 0 ) { scale *= delta * - 2 ; } else { scale /= delta * 2 ; } let zoom = Math . round ( Math . log ( scale ) ) ; if ( zoom > 0 ) { zoom = this . _zoom + zoom >= 20 ? 20 - this . _zoom : zoom ; } else if ( zoom < 0 ) { zoom = this . _zoom + zoom <= 3 ? 3 - this . _zoom : zoom ; } if ( zoom == 0 ) return ; this . _zoom += zoom ; scale = Math . pow ( 2 , zoom ) ; const matrix = ( this . _ctx as any ) . getTransform ( ) ; const a1 = matrix . a , e1 = matrix . e , x1 = event . x , x2 = x1 ; const e = ( x2 - scale * ( x1 - e1 ) - e1 ) / a1 ; const d1 = matrix . d , f1 = matrix . f , y1 = event . y , y2 = y1 ; const f = ( y2 - scale * ( y1 - f1 ) - f1 ) / d1 ; this . _ctx . transform ( scale , 0 , 0 , scale , e , f ) ; this . redraw ( ) ; } destroy ( ) { window . removeEventListener ( "resize" , this . _onResize ) ; this . _canvas . removeEventListener ( "dblclick" , this . _onDoubleClick ) ; this . _canvas . removeEventListener ( "mousedown" , this . _onMouseDown ) ; this . _canvas . removeEventListener ( "mousemove" , this . _onMouseMove ) ; this . _canvas . removeEventListener ( "mouseup" , this . _onMouseUp ) ; this . _canvas . removeEventListener ( "wheel" , this . _onWheel ) ; } }