Initial
This commit is contained in:
commit
8f98aa225e
7 changed files with 669 additions and 0 deletions
138
geolocation/index.html
Normal file
138
geolocation/index.html
Normal file
|
@ -0,0 +1,138 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Map Demo</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin=""/>
|
||||
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>
|
||||
<style>
|
||||
*{
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
body{
|
||||
margin: 0px;
|
||||
}
|
||||
.header{
|
||||
font-weight: bold;
|
||||
font-size: 2.0em;
|
||||
}
|
||||
#mapid {
|
||||
width: 600px;
|
||||
float: left;
|
||||
height: 600px;
|
||||
}
|
||||
#controls {
|
||||
padding-left: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 600px;
|
||||
width: 600px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="visualize_geolocation">
|
||||
<div id="mapid"></div>
|
||||
<div id="controls">
|
||||
<div>
|
||||
<span class="header">Visualizing Geolocation</span><br>
|
||||
<p>
|
||||
Most people are at least somewhat familiar with the notion of geolocation of users by communications networks.
|
||||
However, this can be hard to visualize, and the differences between the geolocation capabilities of various types of network
|
||||
(which are often quite substantial) are often ignored.
|
||||
</p>
|
||||
<p>
|
||||
This tool allows you to visualize the accuracy with which a user's location can be determined (shown as a red circle), using
|
||||
a map of real-world cities for scale. We hope this makes clear why we believe FemtoStar's geolocation-resistance to be so important.
|
||||
</p>
|
||||
<b>Pick a city</b><br>
|
||||
<input type="radio" id="button_nyc" name="city" onclick="setCity('nyc');" checked>
|
||||
<label for="button_nyc">New York City, USA</label><br>
|
||||
<input type="radio" id="button_rio" name="city" onclick="setCity('rio');">
|
||||
<label for="button_rio">Rio de Janeiro, Brazil</label><br>
|
||||
<input type="radio" id="button_berlin" name="city" onclick="setCity('berlin');">
|
||||
<label for="button_berlin">Berlin, Germany</label><br>
|
||||
<input type="radio" id="button_capetown" name="city" onclick="setCity('capetown');">
|
||||
<label for="button_capetown">Cape Town, South Africa</label><br>
|
||||
<input type="radio" id="button_tokyo" name="city" onclick="setCity('tokyo');">
|
||||
<label for="button_tokyo">Tokyo, Japan</label><br>
|
||||
<input type="radio" id="button_sydney" name="city" onclick="setCity('sydney');">
|
||||
<label for="button_sydney">Sydney, Australia</label>
|
||||
<br><br>
|
||||
<b>Pick a network type</b><br>
|
||||
<input type="radio" id="button_gps" name="network" onclick="setNetwork('gps');">
|
||||
<label for="button_gps">Network with GPS reporting (incl. most geostationary satellite networks)</label><br>
|
||||
<input type="radio" id="button_cellular_urban" name="network" onclick="setNetwork('cellular_urban');" checked>
|
||||
<label for="button_cellular_urban">Cellular network (urban area, no GPS reporting)</label><br>
|
||||
<input type="radio" id="button_cellular_rural" name="network" onclick="setNetwork('cellular_rural');">
|
||||
<label for="button_cellular_rural">Cellular network (rural area, no GPS reporting)</label><br>
|
||||
<input type="radio" id="button_satellite" name="network" onclick="setNetwork('satellite');">
|
||||
<label for="button_satellite">Traditional satellite network (non-geostationary orbit, no GPS reporting)</label><br>
|
||||
<input type="radio" id="button_femtostar" name="network" onclick="setNetwork('femtostar');">
|
||||
<label for="button_femtostar">FemtoStar</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* Tileservers that work well:
|
||||
https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png
|
||||
http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}
|
||||
*/
|
||||
var tileserver = "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}";
|
||||
var set_city = "nyc";
|
||||
var set_network = "cellular_urban";
|
||||
|
||||
let cities = {
|
||||
"nyc": [40.758896, -73.985130],
|
||||
"rio": [-22.91141, -43.16921],
|
||||
"berlin": [52.51938, 13.40884],
|
||||
"capetown": [-33.91496, 18.42453],
|
||||
"tokyo": [35.67671, 139.75294],
|
||||
"sydney": [-33.85907, 151.20810]
|
||||
}
|
||||
|
||||
let networks = {
|
||||
"gps": {"accuracy": 5, "zoom": 18},
|
||||
"cellular_urban": {"accuracy": 60, "zoom": 17},
|
||||
"cellular_rural": {"accuracy": 400, "zoom": 14},
|
||||
"satellite": {"accuracy": 750, "zoom": 13},
|
||||
"femtostar": {"accuracy": 300000, "zoom": 4}
|
||||
}
|
||||
|
||||
function setNetwork(new_network){
|
||||
set_network = new_network;
|
||||
|
||||
circle.setRadius(networks[set_network].accuracy);
|
||||
mymap.flyTo(cities[set_city], networks[set_network].zoom);
|
||||
}
|
||||
|
||||
function setCity(new_city){
|
||||
set_city = new_city;
|
||||
|
||||
circle.setRadius(networks[set_network].accuracy);
|
||||
circle.setLatLng(cities[set_city]);
|
||||
mymap.flyTo(cities[set_city], networks[set_network].zoom, {
|
||||
animate: false,
|
||||
duration: 6
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById("button_cellular_urban").checked = true;
|
||||
document.getElementById("button_nyc").checked = true;
|
||||
|
||||
var mymap = L.map('mapid').setView([40.758896, -73.985130], 17);
|
||||
|
||||
L.tileLayer(tileserver, {
|
||||
maxZoom: 18,
|
||||
attribution: 'Map data © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community',
|
||||
id: 'mapbox/streets-v11'
|
||||
}).addTo(mymap);
|
||||
|
||||
var circle = L.circle([40.758896, -73.985130], {
|
||||
color: 'red',
|
||||
fillColor: '#f03',
|
||||
fillOpacity: 0.5,
|
||||
radius: 60
|
||||
}).addTo(mymap);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
3
index.html
Normal file
3
index.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
<h1>FemtoStar Visualization Tests</h1>
|
||||
<a href="sats/satellites.html">Satellites</a><br>
|
||||
<a href="geolocation/index.html">Geolocation</a>
|
398
sats/index.js
Normal file
398
sats/index.js
Normal file
|
@ -0,0 +1,398 @@
|
|||
(function (L, d3, satelliteJs) {
|
||||
var RADIANS = Math.PI / 180;
|
||||
var DEGREES = 180 / Math.PI;
|
||||
var R_EARTH = 6378.137; // equatorial radius (km)
|
||||
|
||||
/* =============================================== */
|
||||
/* =============== CLOCK ========================= */
|
||||
/* =============================================== */
|
||||
|
||||
/**
|
||||
* Factory function for keeping track of elapsed time and rates.
|
||||
*/
|
||||
function Clock() {
|
||||
this._rate = 60; // 1ms elapsed : 60sec simulated
|
||||
this._date = d3.now();
|
||||
this._elapsed = 0;
|
||||
};
|
||||
|
||||
Clock.prototype.date = function (timeInMs) {
|
||||
if (!arguments.length) return this._date + (this._elapsed * this._rate);
|
||||
this._date = timeInMs;
|
||||
return this;
|
||||
};
|
||||
|
||||
Clock.prototype.elapsed = function (ms) {
|
||||
if (!arguments.length) return this._date - d3.now(); // calculates elapsed
|
||||
this._elapsed = ms;
|
||||
return this;
|
||||
};
|
||||
|
||||
Clock.prototype.rate = function (secondsPerMsElapsed) {
|
||||
if (!arguments.length) return this._rate;
|
||||
this._rate = secondsPerMsElapsed;
|
||||
return this;
|
||||
};
|
||||
|
||||
/* ==================================================== */
|
||||
/* =============== CONVERSION ========================= */
|
||||
/* ==================================================== */
|
||||
|
||||
function satrecToFeature(satrec, date, props) {
|
||||
var properties = props || {};
|
||||
var positionAndVelocity = satelliteJs.propagate(satrec, date);
|
||||
var gmst = satelliteJs.gstime(date);
|
||||
var positionGd = satelliteJs.eciToGeodetic(positionAndVelocity.position, gmst);
|
||||
properties.height = positionGd.height;
|
||||
return {
|
||||
type: 'Feature',
|
||||
properties: properties,
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [
|
||||
positionGd.longitude * DEGREES,
|
||||
positionGd.latitude * DEGREES
|
||||
]
|
||||
}
|
||||
};
|
||||
};
|
||||
/* ==================================================== */
|
||||
/* =============== TLE ================================ */
|
||||
/* ==================================================== */
|
||||
|
||||
/**
|
||||
* Factory function for working with TLE.
|
||||
*/
|
||||
function TLE() {
|
||||
this._properties;
|
||||
this._date;
|
||||
};
|
||||
TLE.prototype._lines = function (arry) {
|
||||
return arry.slice(0, 2);
|
||||
};
|
||||
|
||||
TLE.prototype.satrecs = function (tles) {
|
||||
return tles.map(function (d) {
|
||||
return satelliteJs.twoline2satrec.apply(null, this._lines(d));
|
||||
});
|
||||
};
|
||||
|
||||
TLE.prototype.features = function (tles) {
|
||||
var date = this._date || d3.now();
|
||||
|
||||
return tles.map(function (d) {
|
||||
var satrec = satelliteJs.twoline2satrec.apply(null, this._lines(d));
|
||||
return satrecToFeature(satrec, date, this._properties(d));
|
||||
});
|
||||
};
|
||||
|
||||
TLE.prototype.lines = function (func) {
|
||||
if (!arguments.length) return this._lines;
|
||||
this._lines = func;
|
||||
return this;
|
||||
};
|
||||
|
||||
TLE.prototype.properties = function (func) {
|
||||
if (!arguments.length) return this._properties;
|
||||
this._properties = func;
|
||||
return this;
|
||||
};
|
||||
|
||||
TLE.prototype.date = function (ms) {
|
||||
if (!arguments.length) return this._date;
|
||||
this._date = ms;
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/* ==================================================== */
|
||||
/* =============== PARSE ============================== */
|
||||
/* ==================================================== */
|
||||
|
||||
/**
|
||||
* Parses text file string of tle into groups.
|
||||
* @return {string[][]} Like [['tle line 1', 'tle line 2'], ...]
|
||||
*/
|
||||
function parseTle(tleString) {
|
||||
// remove last newline so that we can properly split all the lines
|
||||
var lines = tleString.replace(/\r?\n$/g, '').split(/\r?\n/);
|
||||
|
||||
return lines.reduce(function (acc, cur, index) {
|
||||
if (index % 2 === 0) acc.push([]);
|
||||
acc[acc.length - 1].push(cur);
|
||||
return acc;
|
||||
}, []);
|
||||
};
|
||||
|
||||
|
||||
/* ==================================================== */
|
||||
/* =============== SATELLITE ========================== */
|
||||
/* ==================================================== */
|
||||
|
||||
/**
|
||||
* Satellite factory function that wraps satellitejs functionality
|
||||
* and can compute footprints based on TLE and date
|
||||
*
|
||||
* @param {string[][]} tle two-line element
|
||||
* @param {Date} date date to propagate with TLE
|
||||
*/
|
||||
function Satellite(tle, date) {
|
||||
this._satrec = satelliteJs.twoline2satrec(tle[0], tle[1]);
|
||||
this._satNum = this._satrec.satnum; // NORAD Catalog Number
|
||||
|
||||
this._altitude; // km
|
||||
this._position = {
|
||||
lat: null,
|
||||
lng: null
|
||||
};
|
||||
this._halfAngle; // degrees
|
||||
this._date;
|
||||
this._gmst;
|
||||
|
||||
this.setDate(date);
|
||||
this.update();
|
||||
this._orbitType = this.orbitTypeFromAlt(this._altitude); // LEO, MEO, or GEO
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates satellite position and altitude based on current TLE and date
|
||||
*/
|
||||
Satellite.prototype.update = function () {
|
||||
var positionAndVelocity = satelliteJs.propagate(this._satrec, this._date);
|
||||
var positionGd = satelliteJs.eciToGeodetic(positionAndVelocity.position, this._gmst);
|
||||
|
||||
this._position = {
|
||||
lat: positionGd.latitude * DEGREES,
|
||||
lng: positionGd.longitude * DEGREES
|
||||
};
|
||||
this._altitude = positionGd.height;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {GeoJSON.Polygon} GeoJSON describing the satellite's current footprint on the Earth
|
||||
*/
|
||||
Satellite.prototype.getFootprint = function () {
|
||||
var theta = this._halfAngle * RADIANS;
|
||||
|
||||
coreAngle = this._coreAngle(theta, this._altitude, R_EARTH) * DEGREES;
|
||||
|
||||
return d3.geoCircle()
|
||||
.center([this._position.lng, this._position.lat])
|
||||
.radius(coreAngle)();
|
||||
};
|
||||
|
||||
/**
|
||||
* A conical satellite with half angle casts a circle on the Earth. Find the angle
|
||||
* from the center of the earth to the radius of this circle
|
||||
* @param {number} theta: Satellite half angle in radians
|
||||
* @param {number} altitude Satellite altitude
|
||||
* @param {number} r Earth radius
|
||||
* @returns {number} core angle in radians
|
||||
*/
|
||||
Satellite.prototype._coreAngle = function (theta, altitude, r) {
|
||||
// if FOV is larger than Earth, assume it goes to the tangential point
|
||||
if (Math.sin(theta) > r / (altitude + r)) {
|
||||
return Math.acos(r / (r + altitude));
|
||||
}
|
||||
return Math.abs(Math.asin((r + altitude) * Math.sin(theta) / r)) - theta;
|
||||
};
|
||||
|
||||
Satellite.prototype.halfAngle = function (halfAngle) {
|
||||
if (!arguments.length) return this._halfAngle;
|
||||
this._halfAngle = halfAngle;
|
||||
return this;
|
||||
};
|
||||
|
||||
Satellite.prototype.satNum = function (satNum) {
|
||||
if (!arguments.length) return this._satNum;
|
||||
this._satNum = satNum;
|
||||
return this;
|
||||
};
|
||||
|
||||
Satellite.prototype.altitude = function (altitude) {
|
||||
if (!arguments.length) return this._altitude;
|
||||
this._altitude = altitude;
|
||||
return this;
|
||||
};
|
||||
|
||||
Satellite.prototype.position = function (position) {
|
||||
if (!arguments.length) return this._position;
|
||||
this._position = position;
|
||||
return this;
|
||||
};
|
||||
|
||||
Satellite.prototype.getOrbitType = function () {
|
||||
return this._orbitType;
|
||||
};
|
||||
|
||||
/**
|
||||
* sets both the date and the Greenwich Mean Sidereal Time
|
||||
* @param {Date} date
|
||||
*/
|
||||
Satellite.prototype.setDate = function (date) {
|
||||
this._date = date;
|
||||
this._gmst = satelliteJs.gstime(date);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Maps an altitude to a type of satellite
|
||||
* @param {number} altitude (in KM)
|
||||
* @returns {'LEO' | 'MEO' | 'GEO'}
|
||||
*/
|
||||
Satellite.prototype.orbitTypeFromAlt = function (altitude) {
|
||||
this._altitude = altitude || this._altitude;
|
||||
return this._altitude < 1200 ? 'LEO' : this._altitude > 22000 ? 'GEO' : 'MEO';
|
||||
};
|
||||
|
||||
|
||||
/* =============================================== */
|
||||
/* =================== GLOBE ===================== */
|
||||
/* =============================================== */
|
||||
|
||||
// Approximate date the tle data was aquired from https://www.space-track.org/#recent
|
||||
var TLE_DATA_DATE = new Date(2018, 0, 26).getTime();
|
||||
|
||||
var activeClock;
|
||||
var sats;
|
||||
|
||||
var svg = d3.select('#globe');
|
||||
|
||||
var marginTop = 20;
|
||||
var width = svg.attr('width');
|
||||
var height = svg.attr('height') - marginTop;
|
||||
|
||||
var projection = d3.geoOrthographic()
|
||||
.scale((height - 10) / 2)
|
||||
.translate([width / 2, height / 2 + marginTop])
|
||||
.precision(0.1);
|
||||
|
||||
var geoPath = d3.geoPath()
|
||||
.projection(projection);
|
||||
|
||||
svg.append('path')
|
||||
.datum({
|
||||
type: 'Sphere'
|
||||
})
|
||||
.style('cursor', 'grab')
|
||||
.attr('fill', '#2E86AB')
|
||||
.attr('d', geoPath);
|
||||
|
||||
function initGlobe() {
|
||||
d3.json('world-110m.json').then(function (worldData) {
|
||||
svg.selectAll('.segment')
|
||||
.data(topojson.feature(worldData, worldData.objects.countries).features)
|
||||
.enter().append('path')
|
||||
.style('cursor', 'grab')
|
||||
.attr('class', 'segment')
|
||||
.attr('d', geoPath)
|
||||
.style('stroke', '#888')
|
||||
.style('stroke-width', '1px')
|
||||
.style('fill', '#e5e5e5')
|
||||
.style('opacity', '.4');
|
||||
});
|
||||
}
|
||||
|
||||
function updateSats(date) {
|
||||
sats.forEach(function (sat) {
|
||||
return sat.setDate(date).update()
|
||||
});
|
||||
return sats
|
||||
};
|
||||
|
||||
/**
|
||||
* Create satellite objects for each record in the TLEs and begin animation
|
||||
* @param {string[][]} parsedTles
|
||||
*/
|
||||
function initSats(parsedTles) {
|
||||
activeClock = new Clock()
|
||||
.rate(100)
|
||||
.date(TLE_DATA_DATE);
|
||||
|
||||
sats = parsedTles.map(function (tle) {
|
||||
var sat = new Satellite(tle, new Date(2018, 0, 26));
|
||||
//61.73 degree half angle corresponds to 3 degree coverage angle, obviously
|
||||
//this is far less than we intend to provide but it works well for this graphic.
|
||||
sat.halfAngle(61.73);
|
||||
return sat;
|
||||
});
|
||||
|
||||
window.requestAnimationFrame(animateSats);
|
||||
return sats;
|
||||
};
|
||||
|
||||
function draw() {
|
||||
redrawGlobe();
|
||||
svg.selectAll('.footprint')
|
||||
.data(sats, function (sat) {
|
||||
return sat.satNum();
|
||||
})
|
||||
.join(
|
||||
function (enter) {
|
||||
return enter.append('path')
|
||||
.attr('class', function (sat) {
|
||||
return 'footprint footprint--' + sat.getOrbitType()
|
||||
})
|
||||
.style('cursor', 'grab');
|
||||
}
|
||||
).attr('d', function (sat) {
|
||||
return geoPath(sat.getFootprint());
|
||||
});
|
||||
};
|
||||
|
||||
function redrawGlobe() {
|
||||
svg.selectAll('.segment')
|
||||
.attr('d', geoPath);
|
||||
}
|
||||
|
||||
var m0;
|
||||
var o0;
|
||||
|
||||
function mousedown() {
|
||||
m0 = [d3.event.pageX, d3.event.pageY];
|
||||
o0 = projection.rotate();
|
||||
d3.event.preventDefault();
|
||||
};
|
||||
|
||||
function mousemove() {
|
||||
if (m0) {
|
||||
var m1 = [d3.event.pageX, d3.event.pageY];
|
||||
const o1 = [o0[0] + (m1[0] - m0[0]) / 6, o0[1] + (m0[1] - m1[1]) / 6];
|
||||
projection.rotate(o1);
|
||||
draw();
|
||||
}
|
||||
};
|
||||
|
||||
function mouseup() {
|
||||
if (m0) {
|
||||
mousemove();
|
||||
m0 = null;
|
||||
}
|
||||
}
|
||||
|
||||
svg.on('mousedown', mousedown);
|
||||
d3.select(window)
|
||||
.on('mousemove', mousemove)
|
||||
.on('mouseup', mouseup);
|
||||
|
||||
function animateSats(elapsed) {
|
||||
var dateInMs = activeClock.elapsed(elapsed)
|
||||
.date();
|
||||
var date = new Date(dateInMs);
|
||||
svg.select('.date-counter').text('' + date);
|
||||
|
||||
updateSats(date);
|
||||
draw();
|
||||
window.requestAnimationFrame(animateSats);
|
||||
}
|
||||
|
||||
initGlobe();
|
||||
|
||||
// WARNING: THE TLES HERE ARE NOT REAL NORAD-PUBLISHED TLES - THE TLE FORMAT
|
||||
// IS USED ONLY AS A WAY TO SPECIFY THE ORBITS IN THE CONSTELLATION.
|
||||
d3.text('tles.txt')
|
||||
.then(parseTle)
|
||||
.then(initSats);
|
||||
|
||||
}(window.L, window.d3, window.satellite))
|
29
sats/satellites.html
Normal file
29
sats/satellites.html
Normal file
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.4.0/dist/leaflet.css" integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA=="
|
||||
crossorigin="" />
|
||||
<script src="https://unpkg.com/leaflet@1.4.0/dist/leaflet.js" integrity="sha512-QVftwZFqvtRNi0ZyCtsznlKSWOStnDORoefr1enyq5mVL4tmKB3S/EnC3rRJcxCPavG10IcrVGSmPh6Qw5lwrg=="
|
||||
crossorigin=""></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/promise-polyfill@8.1/dist/polyfill.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/whatwg-fetch@3.0/dist/fetch.umd.min.js"></script>
|
||||
<script src="https://d3js.org/d3.v5.min.js"></script>
|
||||
<script src="https://d3js.org/d3-geo-projection.v2.min.js"></script>
|
||||
<script src="https://d3js.org/d3-queue.v3.min.js"></script>
|
||||
<script src="https://d3js.org/topojson.v2.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/satellite.js/3.0.0/satellite.min.js"></script>
|
||||
<style>
|
||||
.footprint--LEO {
|
||||
fill: rgba(255, 177, 64, 0.08);
|
||||
stroke: rgba(255, 177, 64, 0.5);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="margin: 0px; background-color: #00111d;">
|
||||
<svg id="globe" width="500" height="500"></svg>
|
||||
<script src="index.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
4
sats/tles-test.txt
Normal file
4
sats/tles-test.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 000.0000 0000000 000.0000 000.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 000.0000 0000000 000.0000 050.6230 14.12748000000000
|
96
sats/tles.txt
Normal file
96
sats/tles.txt
Normal file
|
@ -0,0 +1,96 @@
|
|||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 000.0000 0000000 000.0000 000.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 000.0000 0000000 000.0000 090.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 000.0000 0000000 000.0000 180.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 000.0000 0000000 000.0000 270.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 030.0000 0000000 000.0000 307.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 030.0000 0000000 000.0000 037.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 030.0000 0000000 000.0000 127.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 030.0000 0000000 000.0000 217.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 060.0000 0000000 000.0000 255.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 060.0000 0000000 000.0000 345.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 060.0000 0000000 000.0000 075.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 060.0000 0000000 000.0000 165.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 090.0000 0000000 000.0000 202.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 090.0000 0000000 000.0000 292.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 090.0000 0000000 000.0000 022.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 090.0000 0000000 000.0000 112.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 120.0000 0000000 000.0000 150.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 120.0000 0000000 000.0000 240.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 120.0000 0000000 000.0000 330.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 120.0000 0000000 000.0000 060.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 150.0000 0000000 000.0000 097.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 150.0000 0000000 000.0000 187.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 150.0000 0000000 000.0000 277.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 150.0000 0000000 000.0000 007.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 180.0000 0000000 000.0000 045.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 180.0000 0000000 000.0000 135.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 180.0000 0000000 000.0000 225.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 180.0000 0000000 000.0000 315.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 210.0000 0000000 000.0000 352.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 210.0000 0000000 000.0000 082.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 210.0000 0000000 000.0000 172.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 210.0000 0000000 000.0000 262.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 240.0000 0000000 000.0000 300.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 240.0000 0000000 000.0000 030.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 240.0000 0000000 000.0000 120.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 240.0000 0000000 000.0000 210.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 270.0000 0000000 000.0000 247.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 270.0000 0000000 000.0000 337.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 270.0000 0000000 000.0000 067.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 270.0000 0000000 000.0000 157.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 300.0000 0000000 000.0000 195.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 300.0000 0000000 000.0000 285.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 300.0000 0000000 000.0000 015.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 300.0000 0000000 000.0000 105.0000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 330.0000 0000000 000.0000 142.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 330.0000 0000000 000.0000 232.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 330.0000 0000000 000.0000 322.5000 14.12748000000000
|
||||
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
|
||||
2 00000 53.0000 330.0000 0000000 000.0000 052.5000 14.12748000000000
|
1
sats/world-110m.json
Normal file
1
sats/world-110m.json
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue