Compare commits
4 commits
5553b815f6
...
bb829d7a78
| Author | SHA1 | Date | |
|---|---|---|---|
| bb829d7a78 | |||
| 4b37e0fd55 | |||
| 5abb9ae18b | |||
| 69e777033e |
6 changed files with 115 additions and 18 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -7,5 +7,6 @@ layers/survey-markers/states.js
|
||||||
layers/tjx/data/chains.js
|
layers/tjx/data/chains.js
|
||||||
layers/crop-history/data/counties.js
|
layers/crop-history/data/counties.js
|
||||||
layers/mn-sales-tax/data/history.js
|
layers/mn-sales-tax/data/history.js
|
||||||
|
layers/airports/data/types.js
|
||||||
.direnv
|
.direnv
|
||||||
venv
|
venv
|
||||||
|
|
|
||||||
52
layers/airports/get_data.py
Executable file
52
layers/airports/get_data.py
Executable file
|
|
@ -0,0 +1,52 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import csv
|
||||||
|
import io
|
||||||
|
import json
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
index_imports = []
|
||||||
|
|
||||||
|
resp = urllib.request.urlopen("https://davidmegginson.github.io/ourairports-data/airports.csv")
|
||||||
|
airports = list(csv.DictReader(io.TextIOWrapper(resp)))
|
||||||
|
types = set([a['type'] for a in airports])
|
||||||
|
|
||||||
|
for airport_type in types:
|
||||||
|
|
||||||
|
geojson = {
|
||||||
|
"type": "FeatureCollection",
|
||||||
|
"features": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
for airport in airports:
|
||||||
|
if airport['type'] == airport_type:
|
||||||
|
f = {
|
||||||
|
"type": "Feature",
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [float(airport['longitude_deg']), float(airport['latitude_deg'])]
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"ID": airport['ident'],
|
||||||
|
"Name": airport['name'],
|
||||||
|
"City": airport['municipality'],
|
||||||
|
"Country": airport['iso_country'],
|
||||||
|
"Region": airport['iso_region'],
|
||||||
|
"Elevation (ft)": airport['elevation_ft'],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if airport['wikipedia_link']:
|
||||||
|
f['properties']['Wikipedia'] = airport['wikipedia_link']
|
||||||
|
if airport['home_link']:
|
||||||
|
f['properties']['Website'] = airport['home_link']
|
||||||
|
geojson['features'].append(f)
|
||||||
|
|
||||||
|
with open(f'data/{airport_type}.geojson', 'w') as f:
|
||||||
|
f.write(json.dumps(geojson))
|
||||||
|
|
||||||
|
with open("data/types.js", 'w') as f:
|
||||||
|
for airport_type in types:
|
||||||
|
f.write(f"import {airport_type} from './{airport_type}.geojson?url';\n")
|
||||||
|
f.write('\nexport default {\n')
|
||||||
|
for airport_type in types:
|
||||||
|
f.write(f" {airport_type}: {airport_type},\n")
|
||||||
|
f.write("};\n")
|
||||||
40
layers/airports/index.js
Normal file
40
layers/airports/index.js
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import GeoJSON from 'ol/format/GeoJSON.js';
|
||||||
|
import VectorLayer from 'ol/layer/Vector.js';
|
||||||
|
import VectorSource from 'ol/source/Vector.js';
|
||||||
|
|
||||||
|
import types from './data/types.js';
|
||||||
|
|
||||||
|
import { Circle, Fill, Stroke, Style } from 'ol/style.js';
|
||||||
|
|
||||||
|
const layers = {
|
||||||
|
name: "Airports",
|
||||||
|
layers: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let [name, url] of Object.entries(types)) {
|
||||||
|
const layer = new VectorLayer({
|
||||||
|
source: new VectorSource({
|
||||||
|
url,
|
||||||
|
format: new GeoJSON,
|
||||||
|
}),
|
||||||
|
style: new Style({
|
||||||
|
image: new Circle({
|
||||||
|
radius: name == 'large_airport' ? 10 : name == "small_airport" ? 3 : 5,
|
||||||
|
fill: new Fill({
|
||||||
|
color: 'rgba(255,255,255,0.4)',
|
||||||
|
}),
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: 'red',
|
||||||
|
width: name == 'large_airport' ? 4 : 2,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
layers.layers.push({
|
||||||
|
name,
|
||||||
|
layer,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default layers;
|
||||||
|
|
@ -5,24 +5,15 @@ import {Style} from 'ol/style.js';
|
||||||
import Icon from 'ol/style/Icon.js';
|
import Icon from 'ol/style/Icon.js';
|
||||||
|
|
||||||
import pinURL from '/layers/chandler/pin.svg?url'; // TODO: remove `?url`?
|
import pinURL from '/layers/chandler/pin.svg?url'; // TODO: remove `?url`?
|
||||||
import { Feature } from 'ol';
|
import { Collection, Feature } from 'ol';
|
||||||
import { Point } from 'ol/geom';
|
import { Point } from 'ol/geom';
|
||||||
import { fromLonLat } from 'ol/proj';
|
import { fromLonLat } from 'ol/proj';
|
||||||
|
|
||||||
const res = await fetch("https://whereis.chandlerswift.com/api/0/last");
|
let features = new Collection();
|
||||||
const locs = await res.json();
|
|
||||||
const loc = locs[0];
|
|
||||||
|
|
||||||
let feature = new Feature({
|
|
||||||
geometry: new Point(fromLonLat([loc.lon, loc.lat])),
|
|
||||||
...loc
|
|
||||||
});
|
|
||||||
|
|
||||||
const vectorLayer = new VectorLayer({
|
const vectorLayer = new VectorLayer({
|
||||||
source: new VectorSource({
|
source: new VectorSource({
|
||||||
features: [
|
features,
|
||||||
feature,
|
|
||||||
]
|
|
||||||
}),
|
}),
|
||||||
style: new Style({
|
style: new Style({
|
||||||
image: new Icon({
|
image: new Icon({
|
||||||
|
|
@ -32,12 +23,23 @@ const vectorLayer = new VectorLayer({
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
setInterval(async function(){
|
async function refresh(){
|
||||||
const res = await fetch("https://whereis.chandlerswift.com/api/0/last");
|
const res = await fetch("https://whereis.chandlerswift.com/api/0/last");
|
||||||
const locs = await res.json();
|
const locs = await res.json();
|
||||||
const loc = locs[0];
|
const loc = locs[0];
|
||||||
feature.setProperties(loc); // TODO: this won't remove a property if it was in a previous response but not this one
|
// TODO: I could probably just `features[0] = …` but I'm not sure if that causes problems with re-rendering features
|
||||||
feature.getGeometry().setCoordinates(fromLonLat([loc.lon, loc.lat]));
|
if (features.getLength() == 0) {
|
||||||
}, 10 * 1000);
|
features.push(new Feature({
|
||||||
|
geometry: new Point(fromLonLat([loc.lon, loc.lat])),
|
||||||
|
...loc
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
features.item(0).setProperties(loc); // TODO: this won't remove a property if it was in a previous response but not this one
|
||||||
|
features.item(0).getGeometry().setCoordinates(fromLonLat([loc.lon, loc.lat]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
setInterval(refresh, 10 * 1000);
|
||||||
|
|
||||||
export default vectorLayer;
|
export default vectorLayer;
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import upsServiceAreas from './ups/index.js';
|
||||||
import fccTowersLayer from './fcc/towers/layer.js';
|
import fccTowersLayer from './fcc/towers/layer.js';
|
||||||
import mnSalesTaxLayers from './mn-sales-tax/index.js';
|
import mnSalesTaxLayers from './mn-sales-tax/index.js';
|
||||||
import versatilesLayers from './versatiles.js';
|
import versatilesLayers from './versatiles.js';
|
||||||
|
import airports from './airports/index.js';
|
||||||
|
|
||||||
const layerCategories = [
|
const layerCategories = [
|
||||||
{ // Base maps
|
{ // Base maps
|
||||||
|
|
@ -118,6 +119,7 @@ const layerCategories = [
|
||||||
tjx,
|
tjx,
|
||||||
cropHistory,
|
cropHistory,
|
||||||
mnSalesTaxLayers,
|
mnSalesTaxLayers,
|
||||||
|
airports,
|
||||||
];
|
];
|
||||||
|
|
||||||
export default layerCategories;
|
export default layerCategories;
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ const visitedStatesLists = {
|
||||||
'SD',
|
'SD',
|
||||||
'TN',
|
'TN',
|
||||||
'TX',
|
'TX',
|
||||||
// 'UT',
|
'UT',
|
||||||
'VA',
|
'VA',
|
||||||
'VT',
|
'VT',
|
||||||
'WA',
|
'WA',
|
||||||
|
|
@ -95,7 +95,7 @@ const visitedStatesLists = {
|
||||||
'SD',
|
'SD',
|
||||||
'TN',
|
'TN',
|
||||||
'TX',
|
'TX',
|
||||||
// 'UT',
|
'UT',
|
||||||
'VA',
|
'VA',
|
||||||
// 'VT',
|
// 'VT',
|
||||||
'WA',
|
'WA',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue