UNPKG

thematic-earth

Version:

HTML-based, whole-Earth thematic maps using locally hosted data layers

2 lines 15 kB
/* Copyright (c) 2023 Read Write Tools. Legal use subject to the Thematic Earth Software License Agreement. */ import Cursors from'./cursors.class.js';import PointerHandler from'./pointer-handler.class.js';import KeyboardHandler from'./keyboard-handler.class.js';import KC from'../enum/keycodes.enum.js';import CA from'../enum/cursor-action.enum.js';import*as MapScale from'../projection/map-scale.js';import terminal from'../dev/terminal.js';import expect from'../dev/expect.js';export default class UserInterface{constructor(t){this.thematicEarthElement=t,this.earth=this.thematicEarthElement.earth,this.signal=this.thematicEarthElement.signal,this.pointerHandler=new PointerHandler(this.thematicEarthElement),this.keyboardHandler=new KeyboardHandler(this.signal),this.cursors=new Cursors(this.thematicEarthElement.canvas),this.initialLatitude=0,this.initialLongitude=0,this.initialMapScale=MapScale.INITIAL_MAP_SCALE,this.initialTranslationEastWest=0,this.initialTranslationNorthSouth=0,this.initialCanvasX=0,this.initialCanvasY=0,this.registerEventListeners()}registerEventListeners(){this.signal.listen('keyboard/begin-cursor',this.beginCursor.bind(this)),this.signal.listen('keyboard/nsew/north',this.nsewNorth.bind(this)),this.signal.listen('keyboard/nsew/south',this.nsewSouth.bind(this)),this.signal.listen('keyboard/nsew/east',this.nsewEast.bind(this)),this.signal.listen('keyboard/nsew/west',this.nsewWest.bind(this)),this.signal.listen('keyboard/nsew/north-pole',this.nsewNorthPole.bind(this)),this.signal.listen('keyboard/nsew/south-pole',this.nsewSouthPole.bind(this)),this.signal.listen('keyboard/nsew/prime-meridian',this.nsewPrimeMeridian.bind(this)),this.signal.listen('keyboard/nsew/dateline',this.nsewDateline.bind(this)),this.signal.listen('keyboard/zoom/in',this.zoomIn.bind(this)),this.signal.listen('keyboard/zoom/out',this.zoomOut.bind(this)),this.signal.listen('keyboard/zoom/fit',this.zoomFit.bind(this)),this.signal.listen('keyboard/zoom/scale',this.zoomScale.bind(this)),this.signal.listen('keyboard/pan-space/north',this.panSpaceNorth.bind(this)),this.signal.listen('keyboard/pan-space/south',this.panSpaceSouth.bind(this)),this.signal.listen('keyboard/pan-space/east',this.panSpaceEast.bind(this)),this.signal.listen('keyboard/pan-space/west',this.panSpaceWest.bind(this)),this.signal.listen('keyboard/pan-space/recenter',this.panSpaceRecenter.bind(this)),this.signal.listen('keyboard/pan-canvas/north',this.panCanvasNorth.bind(this)),this.signal.listen('keyboard/pan-canvas/south',this.panCanvasSouth.bind(this)),this.signal.listen('keyboard/pan-canvas/east',this.panCanvasEast.bind(this)),this.signal.listen('keyboard/pan-canvas/west',this.panCanvasWest.bind(this)),this.signal.listen('keyboard/pan-canvas/recenter',this.panCanvasRecenter.bind(this)),this.signal.listen('mouse/hover/ctrlkey',this.noop.bind(this)),this.signal.listen('mouse/hover/altkey',this.noop.bind(this)),this.signal.listen('mouse/hover/shiftkey',this.noop.bind(this)),this.signal.listen('mouse/hover/nokey',this.locatePositionAndDiscoverFeatures.bind(this)),this.signal.listen('gesture/begin/ctrlkey',this.noop.bind(this)),this.signal.listen('gesture/begin/altkey',this.noop.bind(this)),this.signal.listen('gesture/begin/shiftkey',this.noop.bind(this)),this.signal.listen('gesture/begin/nokey',this.noop.bind(this)),this.signal.listen('gesture/tap/ctrlkey',this.selectFeatures.bind(this)),this.signal.listen('gesture/tap/altkey',this.nsewFromCursorPosition.bind(this)),this.signal.listen('gesture/tap/shiftkey',this.identifyFeatures.bind(this)),this.signal.listen('gesture/tap/nokey',this.tapAlphabeticKey.bind(this)),this.signal.listen('gesture/doubletap/ctrlkey',this.noop.bind(this)),this.signal.listen('gesture/doubletap/altkey',this.noop.bind(this)),this.signal.listen('gesture/doubletap/shiftkey',this.noop.bind(this)),this.signal.listen('gesture/doubletap/nokey',this.noop.bind(this)),this.signal.listen('gesture/press/ctrlkey',this.noop.bind(this)),this.signal.listen('gesture/press/altkey',this.noop.bind(this)),this.signal.listen('gesture/press/shiftkey',this.noop.bind(this)),this.signal.listen('gesture/press/nokey',this.noop.bind(this)),this.signal.listen('gesture/track/ctrlkey',this.noop.bind(this)),this.signal.listen('gesture/track/altkey',this.nsewAny.bind(this)),this.signal.listen('gesture/track/shiftkey',this.noop.bind(this)),this.signal.listen('gesture/track/nokey',this.trackAlphabeticKey.bind(this)),this.signal.listen('gesture/spread',this.zoomSpreadGesture.bind(this)),this.signal.listen('gesture/pinch',this.zoomPinchGesture.bind(this)),this.signal.listen('gesture/xypan',this.panXYGesture.bind(this)),this.signal.listen('gesture/horizontalpan',this.panHorizontalGesture.bind(this)),this.signal.listen('gesture/verticalpan',this.panVerticalGesture.bind(this)),this.signal.listen('gesture/twofingertap',this.noop.bind(this)),this.signal.listen('gesture/threefingertap',this.noop.bind(this)),this.signal.listen('gesture/horizontalflick',this.noop.bind(this)),this.signal.listen('gesture/verticalflick',this.noop.bind(this)),this.signal.listen('gesture/stationtrack',this.locatePositionAndDiscoverFeatures.bind(this)),this.signal.listen('gesture/twostationtrack',this.noop.bind(this)),this.signal.listen('gesture/counterclockwise',this.noop.bind(this)),this.signal.listen('gesture/clockwise',this.noop.bind(this))}captureEarthState(){this.initialLatitude=this.earth.getTangentLatitude(),this.initialLongitude=this.earth.getTangentLongitude(),this.initialMapScale=this.earth.getMapScale(),this.initialTranslationEastWest=this.earth.getTranslationEastWest(),this.initialTranslationNorthSouth=this.earth.getTranslationNorthSouth(),this.initialCanvasX=this.earth.getCenterPoint().x,this.initialCanvasY=this.earth.getCenterPoint().y}beginCursor(t){switch(t){case CA.RESTING_STATE:var s=this.earth.canvasCoordsToProjectedPoint();this.setRestingStateCursor(s);break;case CA.FEATURE_DISCOVER:this.cursors.featureDiscover();break;case CA.FEATURE_IDENTIFY:this.cursors.featureIdentify();break;case CA.FEATURE_SELECT:this.cursors.featureSelect();break;case CA.FEATURE_SYMBOL_SPECIFIER:this.cursors.featureSymbolSpecifier();break;case CA.INDETERMINATE_ACTION:s=this.earth.canvasCoordsToProjectedPoint();this.setRestingStateCursor(s);break;case CA.NSEW_ANY:this.cursors.nsewAny();break;case CA.NSEW_FROM_CURSOR:this.cursors.nsewFromCursor();break;case CA.NSEW_NORTH:this.cursors.nsewNorth();break;case CA.NSEW_SOUTH:this.cursors.nsewSouth();break;case CA.NSEW_EAST:this.cursors.nsewEast();break;case CA.NSEW_WEST:this.cursors.nsewWest();break;case CA.NSEW_NORTH_POLE:this.cursors.nsewNorthPole();break;case CA.NSEW_SOUTH_POLE:this.cursors.nsewSouthPole();break;case CA.NSEW_PRIME_MERIDIAN:this.cursors.nsewPrimeMeridian();break;case CA.NSEW_DATELINE:this.cursors.nsewDateline();break;case CA.ZOOM_ANY:this.cursors.zoomAny();break;case CA.ZOOM_IN:this.cursors.zoomIn();break;case CA.ZOOM_OUT:this.cursors.zoomOut();break;case CA.ZOOM_FIT:case CA.ZOOM_SCALE:this.cursors.zoomFit();break;case CA.PAN_SPACE_ANY:this.cursors.panSpaceAny();break;case CA.PAN_SPACE_NORTH:this.cursors.panSpaceNorth();break;case CA.PAN_SPACE_SOUTH:this.cursors.panSpaceSouth();break;case CA.PAN_SPACE_EAST:this.cursors.panSpaceEast();break;case CA.PAN_SPACE_WEST:this.cursors.panSpaceWest();break;case CA.PAN_SPACE_RECENTER:this.cursors.panSpaceRecenter();break;case CA.PAN_CANVAS_ANY:this.cursors.panCanvasAny();break;case CA.PAN_CANVAS_NORTH:this.cursors.panCanvasNorth();break;case CA.PAN_CANVAS_SOUTH:this.cursors.panCanvasSouth();break;case CA.PAN_CANVAS_EAST:this.cursors.panCanvasEast();break;case CA.PAN_CANVAS_WEST:this.cursors.panCanvasWest();break;case CA.PAN_CANVAS_RECENTER:this.cursors.panCanvasRecenter();break;case CA.SET_POINT_A:this.cursors.setPointA();break;case CA.SET_POINT_B:this.cursors.setPointB();break;case CA.SET_PLACE_OF_INTEREST:this.cursors.placeOfInterest();break;default:terminal.logic(`Unknown action ${t.cursorAction} with beginCursor`)}}setRestingStateCursor(t){expect(t,'ProjectedPoint'),this.keyboardHandler.pressedDown.has(KC.ALT)||(t.isOnEarth?this.cursors.featureDiscover():this.cursors.standard())}tapAlphabeticKey(t){this.keyboardHandler.pressedDown.has(KC.LETTER_A)?this.setPointA(t):this.keyboardHandler.pressedDown.has(KC.LETTER_B)?this.setPointB(t):this.keyboardHandler.pressedDown.has(KC.LETTER_D)?this.setPlaceOfInterest(t):this.keyboardHandler.pressedDown.has(KC.LETTER_S)&&this.requestSymbolSpecifier(t)}trackAlphabeticKey(t){this.keyboardHandler.pressedDown.has(KC.LETTER_C)?this.panCanvasAny(t):this.keyboardHandler.pressedDown.has(KC.LETTER_X)?this.panSpaceAny(t):this.keyboardHandler.pressedDown.has(KC.LETTER_Z)?this.zoomAny(t):this.reserved(t)}locatePositionAndDiscoverFeatures(t){this.signal.broadcast('user/changeCanvasCoords',{x:t.x,y:t.y})}identifyFeatures(t){this.signal.broadcast('user/requestFeatureIdentification',{x:t.x,y:t.y})}selectFeatures(t){this.signal.broadcast('user/requestFeatureSelection',{x:t.x,y:t.y})}requestSymbolSpecifier(t){this.signal.broadcast('user/requestSymbolSpecifier',{x:t.x,y:t.y})}setPlaceOfInterest(t){this.signal.broadcast('user/changePlaceOfInterest',{x:t.x,y:t.y})}setPointA(t){this.signal.broadcast('user/setPointA',{x:t.x,y:t.y})}setPointB(t){this.signal.broadcast('user/setPointB',{x:t.x,y:t.y})}noop(t){}reserved(t){this.cursors.reserved()}zoomAny(t){var s=t.initialY-t.y,e=this.determineScalingFactor(s,1),a=s<0?Math.max(this.initialMapScale/e,MapScale.MIN_MAP_SCALE):Math.min(this.initialMapScale*e,MapScale.MAX_MAP_SCALE);this.earth.supressCanvasCoords(),this.thematicEarthElement.setMapScale(a),this.thematicEarthElement.explicitMapScale=!0}zoomIn(){var t=this.earth.getMapScale(),s=MapScale.mapScaleToSlider(t),e=MapScale.sliderToMapScale(s+1);this.thematicEarthElement.setMapScale(e),this.thematicEarthElement.explicitMapScale=!0}zoomOut(){var t=this.earth.getMapScale(),s=MapScale.mapScaleToSlider(t),e=MapScale.sliderToMapScale(s-1);this.thematicEarthElement.setMapScale(e),this.thematicEarthElement.explicitMapScale=!0}zoomFit(){var t=Math.min(this.thematicEarthElement.canvas.width,this.thematicEarthElement.canvas.height)/2-10;this.thematicEarthElement.setMapScale(this.earth.getEarthRadius()/t),this.thematicEarthElement.explicitMapScale=!1}zoomScale(t){var s=parseInt(t);if(!(s<0||s>9)){var e;if(0==s)e=MapScale.stops[0];else{var a=Math.floor(MapScale.numStops/10*s),i=MapScale.numStops-1-a;e=MapScale.stops[i]}this.thematicEarthElement.setMapScale(e),this.thematicEarthElement.explicitMapScale=!0}}zoomSpreadGesture(t){var s=this.determineScalingFactor(t.deltaDistance,5),e=Math.max(this.initialMapScale/s,MapScale.MIN_MAP_SCALE);e=MapScale.normalizeMapScale(e),this.earth.supressCanvasCoords(),this.earth.setMapScale(e),this.thematicEarthElement.explicitMapScale=!0}zoomPinchGesture(t){var s=this.determineScalingFactor(t.deltaDistance,5),e=Math.min(this.initialMapScale*s,MapScale.MAX_MAP_SCALE);e=MapScale.normalizeMapScale(e),this.earth.supressCanvasCoords(),this.earth.setMapScale(e),this.thematicEarthElement.explicitMapScale=!0}determineScalingFactor(t,s){var e=Math.log(MapScale.MIN_MAP_SCALE),a=(Math.log(MapScale.MAX_MAP_SCALE)-e)/(Math.min(this.thematicEarthElement.canvas.width,this.thematicEarthElement.canvas.height)*s-1);return Math.exp(e+a*(Math.abs(t)-1))}panSpaceAny(t){var s=t.x-t.initialX,e=t.y-t.initialY,a=s*this.earth.getMapScale()+this.initialTranslationEastWest,i=e*this.earth.getMapScale()+this.initialTranslationNorthSouth;this.earth.supressCanvasCoords(),this.earth.setTranslationEastWest(a),this.earth.setTranslationNorthSouth(i)}panSpaceNorth(){var t=this.earth.getTranslationNorthSouth();t-=100*this.earth.getMapScale(),this.earth.setTranslationNorthSouth(t)}panSpaceSouth(){var t=this.earth.getTranslationNorthSouth();t+=100*this.earth.getMapScale(),this.earth.setTranslationNorthSouth(t)}panSpaceEast(){var t=this.earth.getTranslationEastWest();t+=100*this.earth.getMapScale(),this.earth.setTranslationEastWest(t)}panSpaceWest(){var t=this.earth.getTranslationEastWest();t-=100*this.earth.getMapScale(),this.earth.setTranslationEastWest(t)}panSpaceRecenter(){this.earth.setTranslationNorthSouth(0),this.earth.setTranslationEastWest(0)}panXYGesture(t){this.panHorizontalGesture(t),this.panVerticalGesture(t)}panHorizontalGesture(t){var s=t.deltaX;'left'==t.directionX&&(s*=-1);var e=s*this.earth.getMapScale()+this.initialTranslationEastWest;this.earth.supressCanvasCoords(),this.earth.setTranslationEastWest(e)}panVerticalGesture(t){var s=t.deltaY;'up'==t.directionY&&(s*=-1);var e=s*this.earth.getMapScale()+this.initialTranslationNorthSouth;this.earth.supressCanvasCoords(),this.earth.setTranslationNorthSouth(e)}panCanvasAny(t){var s=t.x-t.initialX,e=t.y-t.initialY,a=s+this.initialCanvasX,i=e+this.initialCanvasY;this.earth.supressCanvasCoords(),this.earth.setCenterPointX(a),this.earth.setCenterPointY(i)}panCanvasNorth(){var t=this.earth.getCenterPointY();t-=50;var s=0-this.earth.getVisualizedRadius();t=Math.max(t,s),this.earth.setCenterPointY(t)}panCanvasSouth(){var t=this.earth.getCenterPointY();t+=50;var s=this.earth.getCanvasHeight()+this.earth.getVisualizedRadius();t=Math.min(t,s),this.earth.setCenterPointY(t)}panCanvasEast(){var t=this.earth.getCenterPointX();t+=50;var s=this.earth.getCanvasWidth()+this.earth.getVisualizedRadius();t=Math.min(t,s),this.earth.setCenterPointX(t)}panCanvasWest(){var t=this.earth.getCenterPointX();t-=50;var s=0-this.earth.getVisualizedRadius();t=Math.max(t,s),this.earth.setCenterPointX(t)}panCanvasRecenter(){this.earth.setCenterPointX(this.earth.getCanvasWidth()/2),this.earth.setCenterPointY(this.earth.getCanvasHeight()/2)}nsewAny(t){this.earth.supressCanvasCoords();var s=t.x-t.initialX,e=t.y-t.initialY,a='mouse'==t.pointerType?1:3,{newLongitude:i,newLatitude:n}=this.nsewFromCanvasDelta(s,e,a);this.earth.setTangentLongitude(i),this.earth.setTangentLatitude(n)}nsewNorth(){var t=this.earth.getTangentLatitude();t+=5,t=Math.min(90,t),this.earth.setTangentLatitude(t)}nsewSouth(){var t=this.earth.getTangentLatitude();t-=5,t=Math.max(-90,t),this.earth.setTangentLatitude(t)}nsewEast(){var t=this.earth.getTangentLongitude();(t+=5)>180&&(t-=360),this.earth.setTangentLongitude(t)}nsewWest(){var t=this.earth.getTangentLongitude();(t-=5)<-180&&(t+=360),this.earth.setTangentLongitude(t)}nsewNorthPole(){this.earth.setTangentLatitude(90)}nsewSouthPole(){this.earth.setTangentLatitude(-90)}nsewPrimeMeridian(){this.earth.setTangentLatitude(0),this.earth.setTangentLongitude(0)}nsewDateline(){this.earth.setTangentLatitude(0),this.earth.setTangentLongitude(180)}nsewFromCanvasDelta(t,s,e){var a=2*this.earth.getVisualizedRadius(),i=t/a*-180/e,n=this.initialLongitude+i,r=s/a*180/e,h=this.initialLatitude+r;return h=Math.min(h,90),{newLongitude:n,newLatitude:h=Math.max(h,-90)}}nsewFromCursorPosition(t){this.cursors.nsewFromCursor();var s=this.earth.getCoordinatesFromCanvasXY(t.x,t.y);this.earth.setTangentLongitude(s.longitude),this.earth.setTangentLatitude(s.latitude)}}