Switch to parceljs, add intial map stuff
This commit is contained in:
parent
635a85aeab
commit
8ac715b787
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
/.tern-port
|
/.tern-port
|
||||||
/node_modules/
|
/node_modules/
|
||||||
/dist/
|
/dist/
|
||||||
|
.tern-port
|
||||||
|
6217
package-lock.json
generated
6217
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@ -5,23 +5,20 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"aprs-parser": "^1.0.4",
|
"aprs-parser": "^1.0.4",
|
||||||
|
"ol": "^5.0.3",
|
||||||
"ws": "^5.2.2"
|
"ws": "^5.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"webpack": "^4.16.1",
|
"parcel": "^1.9.7"
|
||||||
"webpack-cli": "^3.0.8",
|
|
||||||
"webpack-serve": "^2.0.2"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"monkeyPatch": "sed -i '8s| APRSIS| //APRSIS|' node_modules/aprs-parser/lib/index.js",
|
"monkeyPatch": "sed -i '8s| APRSIS| //APRSIS|' node_modules/aprs-parser/lib/index.js",
|
||||||
"serve": "node src/server.js",
|
"serve": "node src/server.js",
|
||||||
|
|
||||||
"prestart": "npm run monkeyPatch",
|
"prestart": "npm run monkeyPatch",
|
||||||
"start": "node_modules/.bin/webpack-serve --content src",
|
"start": "node_modules/.bin/parcel src/index.html",
|
||||||
|
|
||||||
"prebuild": "npm run monkeyPatch",
|
"prebuild": "npm run monkeyPatch",
|
||||||
"build": "NODE_ENV=production node node_modules/.bin/webpack && cp src/index.html dist/index.html"
|
"build": "node_modules/.bin/parcel build src/index.html"
|
||||||
},
|
},
|
||||||
"author": "Adam Goldsmith <contact@adamgoldsmith.name>",
|
"author": "Adam Goldsmith <contact@adamgoldsmith.name>",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
|
BIN
src/arrow.png
Normal file
BIN
src/arrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 398 B |
@ -1,6 +1,6 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<script src="main.js"></script>
|
<script src="./index.js"></script>
|
||||||
<style>
|
<style>
|
||||||
table.stations {
|
table.stations {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
@ -29,5 +29,6 @@
|
|||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<table class="stations">
|
<table class="stations">
|
||||||
</table>
|
</table>
|
||||||
|
<a href="map.html">Map</a>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
19
src/map.html
Normal file
19
src/map.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
height: 100%
|
||||||
|
}
|
||||||
|
.map {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<title>OpenLayers example</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="map" class="map"></div>
|
||||||
|
<script src="./map.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
106
src/map.js
Normal file
106
src/map.js
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import 'ol/ol.css';
|
||||||
|
import {Map as olMap, View} from 'ol';
|
||||||
|
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
|
||||||
|
import {OSM, Vector as VectorSource} from 'ol/source';
|
||||||
|
import Feature from 'ol/Feature';
|
||||||
|
import {fromLonLat} from 'ol/proj';
|
||||||
|
import {Icon, Stroke, Style} from 'ol/style';
|
||||||
|
import Projection from 'ol/proj/Projection';
|
||||||
|
import {LineString, Point} from 'ol/geom';
|
||||||
|
|
||||||
|
import {readFileSync} from 'fs';
|
||||||
|
const packets = readFileSync(__dirname + '/../IS_packets.txt', 'utf-8');
|
||||||
|
|
||||||
|
import {APRSParser} from 'aprs-parser';
|
||||||
|
|
||||||
|
import icon from "./arrow.png";
|
||||||
|
|
||||||
|
let parser = new APRSParser();
|
||||||
|
|
||||||
|
let tile_layer = new TileLayer({source: new OSM()});
|
||||||
|
let vector_layer = new VectorLayer({
|
||||||
|
source: new VectorSource()
|
||||||
|
});
|
||||||
|
|
||||||
|
let map = new olMap({
|
||||||
|
target: 'map',
|
||||||
|
layers: [
|
||||||
|
tile_layer,
|
||||||
|
vector_layer
|
||||||
|
],
|
||||||
|
view: new View({
|
||||||
|
center: fromLonLat([-72.15, 43.90]),
|
||||||
|
zoom: 10
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let colorGen = {
|
||||||
|
hues: null,
|
||||||
|
get: function (totalNum) {
|
||||||
|
if (this.hues === null) {
|
||||||
|
let mult = Math.floor(360 / totalNum);
|
||||||
|
this.hues = Array.from(Array(totalNum).keys())
|
||||||
|
.map(x => x * mult);
|
||||||
|
|
||||||
|
// Shuffle (this is not a great shuffle, but I don't care)
|
||||||
|
this.hues.forEach((current, index, arr) => {
|
||||||
|
let randomIndex = Math.floor(Math.random() * index);
|
||||||
|
[arr[index], arr[randomIndex]] =
|
||||||
|
[arr[randomIndex], arr[index]];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this.hues.pop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let lines = packets.split("\n");
|
||||||
|
lines
|
||||||
|
// restrict to just prouty times
|
||||||
|
.filter(line => {
|
||||||
|
let date = new Date(line.slice(0,18));
|
||||||
|
return date > new Date("2018-07-14") && date < new Date("2018-07-15");
|
||||||
|
})
|
||||||
|
// parse to APRS packet
|
||||||
|
.map(line => parser.parse(line.slice(29)))
|
||||||
|
// filter by callsign
|
||||||
|
.filter(packet => (packet.from !== undefined) &&
|
||||||
|
(packet.from.toString() === "W1HS-9"))
|
||||||
|
// filter to just positional data
|
||||||
|
.filter(packet => 'data' in packet && 'latitude' in packet.data)
|
||||||
|
// join into Arrays of points
|
||||||
|
.reduce((acc, packet) => {
|
||||||
|
if (!acc.has(packet.from.toString())) acc.set(packet.from.toString(), []);
|
||||||
|
acc.get(packet.from.toString()).push([packet.data.longitude,
|
||||||
|
packet.data.latitude]);
|
||||||
|
return acc;
|
||||||
|
}, new Map())
|
||||||
|
// plot on map
|
||||||
|
.forEach((points, callsign, map) => {
|
||||||
|
let pathFeature = new Feature(new LineString(points));
|
||||||
|
let styles = [
|
||||||
|
new Style({stroke: new Stroke(
|
||||||
|
{color: 'hsl(' + colorGen.get(map.size) + ', 75%, 50%)', width: 2})})];
|
||||||
|
|
||||||
|
pathFeature.getGeometry().forEachSegment((start, end) => {
|
||||||
|
let dx = end[0] - start[0];
|
||||||
|
let dy = end[1] - start[1];
|
||||||
|
let rotation = Math.atan2(dy, dx);
|
||||||
|
// arrows
|
||||||
|
styles.push(new Style({
|
||||||
|
geometry: new Point(end),
|
||||||
|
image: new Icon({
|
||||||
|
src: icon,
|
||||||
|
anchor: [0.75, 0.5],
|
||||||
|
rotateWithView: true,
|
||||||
|
rotation: -rotation
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
pathFeature.setStyle(styles);
|
||||||
|
|
||||||
|
vector_layer.getSource().addFeature(pathFeature);
|
||||||
|
pathFeature.getGeometry().transform(new Projection({code: "EPSG:4326"}),
|
||||||
|
tile_layer.getSource().getProjection());
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user