import { SVGZoomWidget } from "@hpcc-js/common" ; import { geoPath as d3GeoPath } from "d3-geo" ; import { select as d3Select } from "d3-selection" ; import { resolve , types as projectionTypes } from "./Projection" ; import "./Utility" ; import "../src/Layered.css" ; const projectionFactor = ( 1 << 12 ) / 2 / Math . PI ; export class Layered extends SVGZoomWidget { _autoScaleOnNextRender ; _layersTarget ; _prevAutoScaleMode ; _d3GeoProjection ; constructor ( ) { super ( ) ; this . _drawStartPos = "origin" ; this . projection ( "Mercator" ) ; } data ( _ ? ) { const retVal = super . data . apply ( this , arguments ) ; if ( arguments . length ) { this . _autoScaleOnNextRender = true ; } return retVal ; } enter ( domNode , element ) { super . enter ( domNode , element ) ; this . _layersTarget = this . _renderElement . append ( "g" ) . attr ( "class" , "layersTarget" ) ; } update ( domNode , element ) { super . update ( domNode , element ) ; const layers = this . _layersTarget . selectAll ( ".layerContainer" ) . data ( this . layers ( ) . filter ( function ( d ) { return d . visible ( ) ; } ) , function ( d ) { return d . id ( ) ; } ) ; const context = this ; layers . enter ( ) . append ( "g" ) . attr ( "id" , function ( d ) { return d . id ( ) ; } ) . attr ( "class" , "layerContainer" ) . each ( function ( d ) { d . _svgElement = d3Select ( this ) ; d . _domElement = context . _parentOverlay . append ( "div" ) ; d . layerEnter ( context , d . _svgElement , d . _domElement ) ; } ) . merge ( layers ) . each ( function ( d ) { d . layerUpdate ( context ) ; } ) ; layers . exit ( ) . each ( function ( d ) { d . layerExit ( context ) ; d . _domElement . remove ( ) ; } ) . remove ( ) ; layers . order ( ) ; this . onZoomed ( ) ; } exit ( domNode , element ) { super . exit ( domNode , element ) ; } onZoomed ( ) { super . onZoomed ( ) ; const layers = this . _layersTarget . selectAll ( ".layerContainer" ) ; const context = this ; layers . each ( function ( d ) { d . layerZoomed ( context ) ; } ) ; } preRender ( callback ? ) { return Promise . all ( this . layers ( ) . filter ( function ( layer ) { return layer . visible ( ) ; } ) . map ( function ( layer ) { return layer . layerPreRender ( ) ; } ) ) ; } render ( callback ? ) { const context = this ; this . preRender ( ) . then ( function ( ) { SVGZoomWidget . prototype . render . call ( context , function ( w ) { if ( context . _layersTarget && ( ( context . _renderCount && context . _autoScaleOnNextRender ) || context . _prevAutoScaleMode !== context . autoScaleMode ( ) ) ) { context . _prevAutoScaleMode = context . autoScaleMode ( ) ; context . _autoScaleOnNextRender = false ; context . autoScale ( ) ; if ( callback ) { callback ( w ) ; } } else { if ( callback ) { callback ( w ) ; } } } ) ; } ) ; return this ; } project ( lat , long ) { if ( lat >= 90 ) lat = 89 ; else if ( lat <= - 90 ) lat = - 89 ; const pos = this . _d3GeoProjection ( [ long , lat ] ) ; if ( pos ) { } return pos ; } invert ( x , y ) { return this . _d3GeoProjection . invert ( [ x , y ] ) ; } getBounds ( ) { const bbox = this . _layersTarget . node ( ) . getBBox ( ) ; return { x : bbox . x , y : bbox . y , width : bbox . width , height : bbox . height } ; } autoScale ( ) { switch ( this . autoScaleMode ( ) ) { case "none" : return ; case "all" : this . zoomToBBox ( this . getBounds ( ) ) ; break ; } } } Layered . prototype . _class += " map_Layered" ; export interface Layered { projection ( ) : string ; projection ( _ ) : this ; projection_exists ( ) : boolean ; centerLat ( ) : number ; centerLat ( _ ) : this ; centerLat_exists ( ) : boolean ; centerLong ( ) : number ; centerLong ( _ ) : this ; centerLong_exists ( ) : boolean ; zoom ( ) : number ; zoom ( _ ) : this ; zoom_exists ( ) : boolean ; autoScaleMode ( ) : string ; autoScaleMode ( _ ) : this ; autoScaleMode_exists ( ) : boolean ; layers ( ) : any [ ] ; layers ( _ ) : this ; layers_exists ( ) : boolean ; } Layered . prototype . publish ( "projection" , null , "set" , "Map projection type" , projectionTypes ) ; Layered . prototype . publish ( "centerLat" , 0 , "number" , "Center Latitude" , null , { tags : [ "Basic" ] } ) ; Layered . prototype . publish ( "centerLong" , 0 , "number" , "Center Longitude" , null , { tags : [ "Basic" ] } ) ; Layered . prototype . publish ( "zoom" , 1 , "number" , "Zoom Level" , null , { tags : [ "Basic" ] } ) ; Layered . prototype . publish ( "autoScaleMode" , "all" , "set" , "Auto Scale" , [ "none" , "all" ] , { tags : [ "Basic" ] } ) ; Layered . prototype . publish ( "layers" , [ ] , "widgetArray" , "Layers" , null , { render : false } ) ; const projection_orig = Layered . prototype . projection ; Layered . prototype . projection = function ( _ ? ) { const retVal = projection_orig . apply ( this , arguments ) ; if ( arguments . length ) { this . _d3GeoProjection = resolve ( _ ) . scale ( projectionFactor ) . translate ( [ 0 , 0 ] ) ; switch ( _ ) { case "orthographic" : this . _d3GeoProjection . clipAngle ( 90 ) . rotate ( [ 0 , 0 ] ) ; } this . _d3GeoPath = d3GeoPath ( ) . projection ( this . _d3GeoProjection ) ; this . _autoScaleOnNextRender = true ; } return retVal ; } ;