rwt-orthographic-earth
Version:
An orthographic projection of Earth, a standards-based DOM Component
396 lines (364 loc) • 17.4 kB
JavaScript
/* Copyright (c) 2022 Read Write Tools. Legal use subject to the JavaScript Orthographic Earth Software License Agreement. */
import Earth from './joe/earth.class.js';
import Layer from './joe/layers/layer.class.js';
import Space from './joe/packages/space.class.js';
import Sphere from './joe/packages/sphere.class.js';
import Night from './joe/packages/night.class.js';
import Crosshairs from './joe/packages/crosshairs.class.js';
import Graticule from './joe/packages/graticule.class.js';
import NamedMeridians from './joe/packages/named-meridians.class.js';
import NamedParallels from './joe/packages/named-parallels.class.js';
import GreatCircles from './joe/packages/great-circles.class.js';
import PlaceOfInterest from './joe/packages/place-of-interest.class.js';
import TopojsonPackage from './joe/packages/topojson-package.class.js';
import GcsPackage from './joe/packages/gcs-package.class.js';
import Animation from './joe/render/animation.class.js';
import UserInterface from './joe/interaction/user-interface.class.js';
import Menu from './joe/menu/menu.class.js';
import expect from './joe/dev/expect.js';
import terminal from 'softlib/terminal.js';
const Static = {
componentName: 'rwt-orthographic-earth',
elementInstance: 1,
componentPath: '/',
vssURL: 'joe/visualization/rwt-orthographic-earth.vss',
zOrder: 1
};
Object.seal(Static);
export default class rwtOrthographicEarth extends HTMLElement {
constructor() {
super(), this.instance = Static.elementInstance++, this.isComponentLoaded = !1,
this.canvas = null, this.menu = null, this.earth = null, this.userInterface = null,
this.explicitMapScale = !1, this.explicitCenterPoint = !1, this.resizeObserver = null,
Object.seal(this);
}
async connectedCallback() {
if (this.isConnected) try {
this.determineComponentPath(), this.attachShadow({
mode: 'open'
}), this.createCanvas(), this.createEarth(), this.createUserInterface(), this.addVisualizationStyleSheet(`${Static.componentPath}${Static.vssURL}`),
await this.addDockablePanels(), this.registerMenuListeners(), this.registerUserListeners(),
this.registerVisualizationListeners(), this.registerEarthPositionListeners(), this.registerResizeListener(),
this.resizeCanvas(), this.setupAnimations(), this.initializeEarthValues(), this.reflectValues(),
this.sendComponentLoaded(), this.validate();
} catch (e) {
terminal.caught(e);
}
}
determineComponentPath() {
Static.componentPath = new URL(import.meta.url).pathname;
var e = Static.componentPath.lastIndexOf('/');
-1 != e && (Static.componentPath = Static.componentPath.substr(0, e + 1));
}
createCanvas() {
this.canvas = document.createElement('canvas'), this.canvas.style.position = 'absolute',
this.canvas.style.touchAction = 'none', this.canvas.width = 100, this.canvas.height = 100,
this.canvas.tabIndex = 0, this.shadowRoot.appendChild(this.canvas);
}
createEarth() {
this.earth = new Earth(this);
}
createUserInterface() {
this.userInterface = new UserInterface(this, this.canvas);
}
addVisualizationStyleSheet(e) {
this.earth.addVisualizationStyleSheet(e);
}
runCourtesyValidator() {
this.earth.runCourtesyValidator();
}
async addDockablePanels() {
this.style.position = 'relative', this.menu = new Menu(this), await this.menu.initialize();
}
registerResizeListener() {
this.resizeObserver = new ResizeObserver(this.resizeCanvas.bind(this)), this.resizeObserver.observe(this);
}
initializeEarthValues() {
var e = new Date;
this.earth.earthPosition.changeUTC(e);
var t = this.getAttribute('geolocation');
if (null != t && '' != t) {
if ('timezone' == t || 'auto' == t) {
var a = e.getTimezoneOffset() / 60 * -1;
this.earth.changeTimezoneOffset(a);
var s = 15 * a;
this.earth.setTangentLongitude(s), this.setPlaceOfInterest(this.earth.getTangentLongitude(), this.earth.getTangentLatitude());
}
'auto' == t && 'geolocation' in navigator && navigator.geolocation.getCurrentPosition((e => {
this.earth.setTangentLongitude(e.coords.longitude), this.earth.setTangentLatitude(e.coords.latitude),
this.setPlaceOfInterest(e.coords.longitude, e.coords.latitude), this.earth.recalculateLongitudeDependants(),
this.earth.recalculateLatitudeDependants();
}));
}
}
reflectValues() {
this.earth.reflectValues(this.menu);
}
sendComponentLoaded() {
this.isComponentLoaded = !0, this.dispatchEvent(new Event('component-loaded', {
bubbles: !0
}));
}
waitOnLoading() {
return new Promise((e => {
1 == this.isComponentLoaded ? e() : this.addEventListener('component-loaded', e);
}));
}
broadcastMessage(e, t) {
var a = new CustomEvent(e, {
detail: t
});
this.dispatchEvent(a);
}
resizeCanvas() {
if (this.canvas.width = this.offsetWidth, this.canvas.height = this.offsetHeight,
this.earth.viewport.syncCanvasDimensions(this.canvas.width, this.canvas.height),
0 == this.explicitCenterPoint) {
var e = Math.round(this.canvas.width / 2), t = Math.round(this.canvas.height / 2);
this.earth.setCenterPoint({
x: e,
y: t
});
}
if (0 == this.explicitMapScale) {
var a = Math.min(this.canvas.width, this.canvas.height) / 2 - 10, s = this.menu.rwtDockablePanels.shadowRoot.getElementById('adjust-px-x-slider'), i = this.menu.rwtDockablePanels.shadowRoot.getElementById('adjust-px-y-slider');
null != s && null != i && (s.setAttribute('min', (-1 * a).toFixed(0)), s.setAttribute('max', (this.canvas.width + a).toFixed(0)),
s.value = e, i.setAttribute('min', (-1 * a).toFixed(0)), i.setAttribute('max', (this.canvas.height + a).toFixed(0)),
i.value = t), this.earth.setMapScale(this.earth.getEarthRadius() / a);
}
this.invalidateCanvas();
}
invalidateCanvas() {
null != this.earth && this.earth.invalidateCanvas();
}
setMenuTitlebar(e) {
this.menu.rwtDockablePanels.setTitlebar(e);
}
async addMapItem(e) {
e.zOrder = e.zOrder ?? Static.zOrder++;
var t = await this.addPackage(e);
return !1 !== t && {
layerId: this.addLayer(t, e),
packageId: t
};
}
async addPackage(e) {
expect(e.layerType, 'String');
var t = null;
switch (e.layerType) {
case 'space':
e.vssClassname = e.vssClassname ?? 'space', t = this.earth.addPackage(new Space(this));
break;
case 'sphere':
e.vssClassname = e.vssClassname ?? 'sphere', t = this.earth.addPackage(new Sphere(this));
break;
case 'night':
e.vssClassname = e.vssClassname ?? 'night', t = this.earth.addPackage(new Night(this));
break;
case 'crosshairs':
e.vssClassname = e.vssClassname ?? 'crosshairs';
var a = null == e.parallelFrequency ? 10 : e.parallelFrequency, s = null == e.meridianFrequency ? 10 : e.meridianFrequency;
t = this.earth.addPackage(new Crosshairs(this, a, s));
break;
case 'graticule':
e.vssClassname = e.vssClassname ?? 'graticule';
a = null == e.parallelFrequency ? 10 : e.parallelFrequency, s = null == e.meridianFrequency ? 10 : e.meridianFrequency;
var i = null != e.drawToPoles && e.drawToPoles;
t = this.earth.addPackage(new Graticule(this, a, s, i));
break;
case 'named-meridians':
e.vssClassname = e.vssClassname ?? 'named-meridians';
var n = e.namedMeridians ?? {}, r = e.frequency ?? 1;
t = this.earth.addPackage(new NamedMeridians(this, n, r));
break;
case 'named-parallels':
e.vssClassname = e.vssClassname ?? 'named-parallels';
var h = e.namedParallels ?? {};
r = e.frequency ?? 1;
t = this.earth.addPackage(new NamedParallels(this, h, r));
break;
case 'great-circles':
e.vssClassname = e.vssClassname ?? 'great-circles', e.routes = e.routes ?? [], t = this.earth.addPackage(new GreatCircles(this, e.routes));
break;
case 'place-of-interest':
e.vssClassname;
t = this.earth.addPackage(new PlaceOfInterest(this));
break;
case 'topojson-package':
var o = new TopojsonPackage(this);
t = await this.retreiveExternalFile(o, e);
break;
case 'gcs-package':
var c = new GcsPackage(this);
t = await this.retreiveExternalFile(c, e);
break;
default:
terminal.abnormal(`Unrecognized layerType ${e.layerType}`), t = !1;
}
return t;
}
async retreiveExternalFile(e, t) {
expect(e, [ 'TopojsonPackage', 'GcsPackage' ]), expect(t, 'Object');
var a = t.url ?? '', s = this.earth.addPackage(e);
return await e.retrieveData('replace', a, t), this.invalidateCanvas(), s;
}
addLayer(e, t) {
expect(e, 'Number');
var a = t.zOrder ?? Static.zOrder++, s = t.layerName ?? '', i = t.vssIdentifier ?? '', n = t.vssClassname ?? '', r = t.featureKey ?? '', h = t.identifiable ?? 'disallow', o = t.identifyCallback ?? null, c = t.selectable ?? 'disallow';
return this.earth.addLayer(new Layer(this, e, a, s, i, n, r, h, o, c));
}
getPackage(e) {
return expect(e, 'Number'), this.earth.getPackage(e);
}
getLayer(e) {
return expect(e, 'Number'), this.earth.getLayer(e);
}
setTangentLongitude(e) {
this.earth.setTangentLongitude(e);
}
setTangentLatitude(e) {
this.earth.setTangentLatitude(e);
}
setTranslationEastWest(e) {
this.earth.setTranslationEastWest(e);
}
setTranslationNorthSouth(e) {
this.earth.setTranslationNorthSouth(e);
}
setMapScale(e) {
this.earth.setMapScale(e), this.explicitMapScale = !0;
}
setCenterPoint(e) {
this.earth.setCenterPoint(e);
}
setCenterPointX(e) {
this.earth.setCenterPointX(e);
}
setCenterPointY(e) {
this.earth.setCenterPointY(e);
}
changeTimezoneOffset(e) {
this.earth.changeTimezoneOffset(e);
}
setPlaceOfInterest(e, t) {
this.earth.setPlaceOfInterest(e, t);
}
setRotationSpeed(e) {
this.earth.renderLoop.getAnimationByName('time-lapse-animation').setDeltaPerSecond(e),
this.broadcastMessage('animation/rotationDegreesPerSecond', e);
}
registerMenuListeners() {
this.addEventListener('menu/seasonDayMonthYearUTC', (e => {
var t = e.detail;
this.earth.changeDayMonthYear(t), this.earth.recalculateJulianDateDependants();
})), this.addEventListener('menu/seasonSpecialDay', (e => {
this.earth.changeSpecialDay(e.detail), this.earth.recalculateJulianDateDependants();
})), this.addEventListener('menu/seasonDayOfYear', (e => {
this.earth.changeDayOfYear(e.detail), this.earth.recalculateJulianDateDependants();
})), this.addEventListener('menu/timeOfDayHMS', (e => {
this.earth.changeTimeOfDayHMS(e.detail), this.earth.recalculateJulianDateDependants();
})), this.addEventListener('menu/timezoneOffset', (e => {
this.earth.changeTimezoneOffset(e.detail), this.earth.recalculateTimezoneDependants();
})), this.addEventListener('menu/tangentLongitude', (e => {
this.earth.setTangentLongitude(e.detail), this.earth.recalculateLongitudeDependants();
})), this.addEventListener('menu/tangentLatitude', (e => {
this.earth.setTangentLatitude(e.detail), this.earth.recalculateLatitudeDependants();
})), this.addEventListener('menu/timeLapseRotation', (e => {
var t = e.detail;
this.earth.renderLoop.getAnimationByName('time-lapse-animation').setDeltaPerSecond(t);
})), this.addEventListener('menu/mapScale', (e => {
this.earth.setMapScale(e.detail), this.explicitMapScale = !0;
})), this.addEventListener('menu/translationEastWest', (e => {
this.earth.setTranslationEastWest(e.detail);
})), this.addEventListener('menu/translationNorthSouth', (e => {
this.earth.setTranslationNorthSouth(e.detail);
})), this.addEventListener('menu/centerPointX', (e => {
this.earth.setCenterPointX(e.detail), this.explicitCenterPoint = !0;
})), this.addEventListener('menu/centerPointY', (e => {
this.earth.setCenterPointY(e.detail), this.explicitCenterPoint = !0;
}));
}
registerUserListeners() {
this.addEventListener('user/changeCanvasCoords', (e => {
var t = e.detail;
this.earth.changeCanvasCoords(t.x, t.y);
})), this.addEventListener('user/requestFeatureIdentification', (e => {
var t = e.detail;
this.earth.requestFeatureIdentification(t.x, t.y);
})), this.addEventListener('user/requestFeatureSelection', (e => {
var t = e.detail;
this.earth.requestFeatureSelection(t.x, t.y);
})), this.addEventListener('user/setPointA', (e => {
var t = e.detail;
this.earth.setPointA(t.x, t.y);
})), this.addEventListener('user/setPointB', (e => {
var t = e.detail;
this.earth.setPointB(t.x, t.y);
})), this.addEventListener('user/changePlaceOfInterest', (e => {
var t = e.detail;
this.earth.changePlaceOfInterest(t.x, t.y), this.earth.recalculatePlaceOfInterestDependants();
}));
}
registerVisualizationListeners() {
this.addEventListener('visualization/styleSheetAdded', (e => {
this.earth.visual.allFeaturesNeedRestyling = !0, this.invalidateCanvas();
}));
}
registerEarthPositionListeners() {
this.addEventListener('earthPosition/declination', (e => {
this.earth.reflectDeclination(e.detail), this.earth.recalculateDeclinationDependants();
}));
}
setupAnimations() {
var e = this.earth.getTangentLongitude.bind(this.earth), t = this.earth.setTangentLongitude.bind(this.earth), a = new Animation('time-lapse-animation', this.earth, e, t, {
deltaPerSecond: 0,
maxThreshold: 180,
minThreshold: -180,
thresholdWrap: !0
});
this.earth.renderLoop.addAnimation(a);
}
async validate() {
if (1 == this.instance) {
var e = (n = window.location.hostname).split('.'), t = 25;
if (e.length >= 2) {
var a = e[e.length - 2].charAt(0);
(a < 'a' || a > 'z') && (a = 'q'), t = a.charCodeAt(a) - 97, t = Math.max(t, 0),
t = Math.min(t, 25);
}
var s = new Date;
s.setUTCMonth(0, 1);
var i = (Math.floor((Date.now() - s) / 864e5) + 1) % 26, n = window.location.hostname, r = `Unregistered ${Static.componentName} component.`;
try {
var h = (await import('../../rwt-registration-keys.js')).default;
for (let e = 0; e < h.length; e++) {
var o = h[e];
if (o.hasOwnProperty('product-key') && o['product-key'] == Static.componentName) return n != o.registration && terminal.warning(`${r} See https://readwritetools.com/licensing.blue to learn more.`),
void (i == t && window.setTimeout(this.authenticate.bind(this, o), 1e3));
}
terminal.warning(`${r} rwt-registration-key.js file missing "product-key": "${Static.componentName}"`);
} catch (e) {
terminal.warning(`${r} rwt-registration-key.js missing from website's root directory.`);
}
}
}
async authenticate(e) {
var t = encodeURIComponent(window.location.hostname), a = encodeURIComponent(window.location.href), s = encodeURIComponent(e.registration), i = encodeURIComponent(e['customer-number']), n = encodeURIComponent(e['access-key']), r = {
method: 'POST',
mode: 'cors',
credentials: 'omit',
cache: 'no-cache',
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
body: `product-name=${Static.componentName}&hostname=${t}&href=${a}®istration=${s}&customer-number=${i}&access-key=${n}`
};
try {
var h = await fetch('https://validation.readwritetools.com/v1/genuine/component', r);
if (200 == h.status) await h.json();
} catch (e) {
terminal.caught(e);
}
}
}
window.customElements.define(Static.componentName, rwtOrthographicEarth);