mirror of
https://github.com/Findus23/RainbowRoad.git
synced 2024-09-18 14:53:51 +02:00
allow multiple areas
This commit is contained in:
parent
0c666a1d11
commit
80cbd705fe
19 changed files with 221 additions and 70 deletions
BIN
assets/favicons/derstandard.at.png
Normal file
BIN
assets/favicons/derstandard.at.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 481 B |
|
@ -3,8 +3,8 @@ import type {Crossing, OSMNodeSource, OSMWaySource, OverPassNode, OverPassRespon
|
|||
import {nodeData, wayData} from "./overpass";
|
||||
import {lineLengthInM} from "../utils/geo";
|
||||
|
||||
async function runfetch() {
|
||||
const data: Crossing[] = JSON.parse(fs.readFileSync("../data/data.json", 'utf8'));
|
||||
async function runfetch(filename: string) {
|
||||
const data: Crossing[] = JSON.parse(fs.readFileSync(filename, 'utf8'));
|
||||
|
||||
function firstLastNodeCoords(nodeMap: { [id: number]: OverPassNode }, nodeList: number[]) {
|
||||
const coords: number[][] = []
|
||||
|
@ -75,8 +75,14 @@ async function runfetch() {
|
|||
length: lineLengthInM(coords[0], coords[1])
|
||||
}
|
||||
// crossings[i] = d
|
||||
fs.writeFileSync("../data/data.json", JSON.stringify(data, null, 2))
|
||||
fs.writeFileSync(filename, JSON.stringify(data, null, 2))
|
||||
}
|
||||
}
|
||||
|
||||
runfetch()
|
||||
fs.readdirSync("../data/").forEach(file => {
|
||||
if (file === "schema.json") {
|
||||
return
|
||||
}
|
||||
console.info(file)
|
||||
runfetch("../data/" + file)
|
||||
})
|
||||
|
|
|
@ -2,10 +2,10 @@ import * as fs from "fs";
|
|||
import type {Crossing} from "../interfaces";
|
||||
|
||||
function runstats() {
|
||||
const data: Crossing[] = JSON.parse(fs.readFileSync("../data/data.json", 'utf8'));
|
||||
const data: Crossing[] = JSON.parse(fs.readFileSync("../data/Wien.json", 'utf8'));
|
||||
|
||||
|
||||
const bezirke = data.map(c => c.bezirk)
|
||||
const bezirke = data.map(c => c.bezirk!)
|
||||
const counts: { [key: number]: number } = {};
|
||||
|
||||
for (const num of bezirke) {
|
||||
|
|
2
custom.d.ts
vendored
2
custom.d.ts
vendored
|
@ -1,3 +1,5 @@
|
|||
import "vite/client"
|
||||
|
||||
declare module "*.svg" {
|
||||
const content: string;
|
||||
export default content;
|
||||
|
|
31
data/Oberösterreich.json
Normal file
31
data/Oberösterreich.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Nordico",
|
||||
"type": "prideFlag",
|
||||
"sources": [
|
||||
{
|
||||
"type": "official",
|
||||
"url": "https://www.linz.at/medienservice/2022/202206_115655.php",
|
||||
"date": "2022-06-22"
|
||||
}
|
||||
],
|
||||
"geosource": {
|
||||
"type": "OSMway",
|
||||
"wayID": 140435401
|
||||
},
|
||||
"geo": {
|
||||
"coords": [
|
||||
[
|
||||
14.2911588,
|
||||
48.3037437
|
||||
],
|
||||
[
|
||||
14.2911232,
|
||||
48.3038253
|
||||
]
|
||||
],
|
||||
"length": 9.45
|
||||
}
|
||||
}
|
||||
]
|
|
@ -68,6 +68,7 @@
|
|||
"news",
|
||||
"official",
|
||||
"proposal",
|
||||
"photo",
|
||||
"streetview",
|
||||
"in person"
|
||||
]
|
||||
|
@ -153,7 +154,6 @@
|
|||
},
|
||||
"required": [
|
||||
"id",
|
||||
"bezirk",
|
||||
"name",
|
||||
"type",
|
||||
"sources",
|
||||
|
|
|
@ -19,7 +19,7 @@ export interface OSMNodeSource {
|
|||
}
|
||||
|
||||
export interface Source {
|
||||
type: "news" | "official" | "proposal" | "streetview" | "in person"
|
||||
type: "news" | "official" | "proposal" | "photo" | "streetview" | "in person"
|
||||
date: string
|
||||
url?: string
|
||||
}
|
||||
|
@ -32,9 +32,9 @@ export interface GeoData {
|
|||
export interface Crossing {
|
||||
id: number
|
||||
name: string
|
||||
bezirk: number
|
||||
comment?:string
|
||||
set?:string
|
||||
bezirk?: number
|
||||
comment?: string
|
||||
set?: string
|
||||
type: FlagType
|
||||
sources: Source[]
|
||||
geosource: OSMWaySource | OSMNodeSource | RawCoordSource,
|
||||
|
|
|
@ -5,3 +5,9 @@ Mariahilfer Straße
|
|||
|
||||
Unbekannter Trans-Pride-Streifen in Rudolfsheim-Fünfhaus
|
||||
https://www.wien.gv.at/bezirke/rudolfsheim-fuenfhaus/politik/sitzungen/pdf/20210701-antrag-pride-schutzweg.pdf
|
||||
|
||||
|
||||
Linz:
|
||||
https://www.weekend.at/bundesland/oberoesterreich/neue-regenbogen-zebrastreifen-linz
|
||||
https://www.linzwiki.at/wiki/Datei:Regenbogen-Zebrastreifen_Mozartkreuzung.jpg/
|
||||
https://www.linz.at/medienservice/2022/202206_115655.php
|
||||
|
|
11
package-lock.json
generated
11
package-lock.json
generated
|
@ -13,6 +13,7 @@
|
|||
"axios": "^0.27.2",
|
||||
"hint.css": "^2.7.0",
|
||||
"micromodal": "^0.4.10",
|
||||
"navigo": "^8.11.1",
|
||||
"node-fetch": "^3.2.10",
|
||||
"ol": "^6.14.1",
|
||||
"ts-node": "^10.9.1"
|
||||
|
@ -1132,6 +1133,11 @@
|
|||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/navigo": {
|
||||
"version": "8.11.1",
|
||||
"resolved": "https://registry.npmjs.org/navigo/-/navigo-8.11.1.tgz",
|
||||
"integrity": "sha512-e3sc1UzakF+bWquC8/dbPCgo7LgPEW1ekgwb4pmEcl8tOc/I7lML8r7HBql+b0VRk7tJWTZqtkeObwJAVR1pxg=="
|
||||
},
|
||||
"node_modules/node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
|
@ -2320,6 +2326,11 @@
|
|||
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
|
||||
"dev": true
|
||||
},
|
||||
"navigo": {
|
||||
"version": "8.11.1",
|
||||
"resolved": "https://registry.npmjs.org/navigo/-/navigo-8.11.1.tgz",
|
||||
"integrity": "sha512-e3sc1UzakF+bWquC8/dbPCgo7LgPEW1ekgwb4pmEcl8tOc/I7lML8r7HBql+b0VRk7tJWTZqtkeObwJAVR1pxg=="
|
||||
},
|
||||
"node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
"dev": "vite",
|
||||
"build": "tsc --skipLibCheck && vite build",
|
||||
"preview": "vite preview",
|
||||
"validate": "ajv validate -s data/schema.json -d data/data.json"
|
||||
"validate": "ajv validate -s data/schema.json -d data/Wien.json"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/micromodal": "^0.3.3",
|
||||
|
@ -22,6 +22,7 @@
|
|||
"axios": "^0.27.2",
|
||||
"hint.css": "^2.7.0",
|
||||
"micromodal": "^0.4.10",
|
||||
"navigo": "^8.11.1",
|
||||
"node-fetch": "^3.2.10",
|
||||
"ol": "^6.14.1",
|
||||
"ts-node": "^10.9.1"
|
||||
|
|
41
src/areaData.ts
Normal file
41
src/areaData.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import {Coordinate} from "ol/coordinate";
|
||||
import {Extent} from "ol/extent";
|
||||
import {View} from "ol";
|
||||
import {fromLonLat, transformExtent} from "ol/proj";
|
||||
|
||||
interface Area {
|
||||
name: string
|
||||
center: Coordinate
|
||||
extent: Extent
|
||||
zoom: number
|
||||
}
|
||||
|
||||
|
||||
export const areas: { [name: string]: Area } = {
|
||||
Wien: {
|
||||
name: "Wien",
|
||||
zoom: 13,
|
||||
center: [16.3787, 48.2089],
|
||||
// https://www.wien.gv.at/statistik/lebensraum/tabellen/stadtgebiet-eckdaten.html
|
||||
extent: [16.18278, 48.11833, 16.58, 48.32306]
|
||||
},
|
||||
OOE: {
|
||||
name: "Oberösterreich",
|
||||
zoom: 9,
|
||||
// https://doris.ooe.gv.at/service/pdf/mittelpunkte/4.pdf
|
||||
center: [13.964417, 48.136583],
|
||||
// https://www.deine-berge.de/Region/Oesterreich/8/Bundesland-Oberoesterreich.html
|
||||
extent: [12.749244, 47.461112, 14.9921682, 48.7725637]
|
||||
}
|
||||
}
|
||||
|
||||
export const Wien = areas.Wien
|
||||
|
||||
export function viewFromArea(area: Area): View {
|
||||
return new View({
|
||||
center: fromLonLat(area.center),
|
||||
zoom: area.zoom,
|
||||
extent: transformExtent(area.extent, 'EPSG:4326', 'EPSG:3857'),
|
||||
constrainOnlyCenter: true
|
||||
})
|
||||
}
|
46
src/features.ts
Normal file
46
src/features.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
import {Crossing} from "../interfaces";
|
||||
import {Vector as VectorSource} from "ol/source";
|
||||
import {transform} from "ol/proj";
|
||||
import {Feature} from "ol";
|
||||
import {LineString, Point} from "ol/geom";
|
||||
import {averageCoords} from "../utils/geo";
|
||||
|
||||
export type MetaData = { [id: number]: Crossing }
|
||||
|
||||
export function loadData(data: Crossing[], vectorSource: VectorSource): MetaData {
|
||||
const metaData: MetaData = {}
|
||||
console.info(data)
|
||||
data.sort((a, b) => {
|
||||
/*
|
||||
put trans flag on top (so they are not covered,
|
||||
but apart from that keep the drawing order random
|
||||
*/
|
||||
if (a.type == "transFlag") {
|
||||
return 1
|
||||
}
|
||||
if (b.type == "transFlag") {
|
||||
return -1
|
||||
}
|
||||
return Math.random() - 0.5;
|
||||
})
|
||||
data.forEach(c => {
|
||||
if (typeof c.geo === "undefined") {
|
||||
return
|
||||
}
|
||||
const points = c.geo.coords.map(coord => transform(coord, 'EPSG:4326', 'EPSG:3857'));
|
||||
|
||||
const featureLine = new Feature({
|
||||
geometry: new LineString(points)
|
||||
});
|
||||
const featureDot = new Feature({
|
||||
geometry: new Point(averageCoords(points))
|
||||
});
|
||||
featureLine.setId(c.id)
|
||||
featureDot.setId(c.id + 10000)
|
||||
metaData[c.id] = c
|
||||
vectorSource.addFeature(featureLine);
|
||||
vectorSource.addFeature(featureDot);
|
||||
})
|
||||
return metaData
|
||||
|
||||
}
|
3
src/main.ts
Normal file
3
src/main.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
import "./style.scss"
|
||||
|
||||
import "./map"
|
96
src/map.ts
96
src/map.ts
|
@ -1,10 +1,6 @@
|
|||
import Map from "ol/Map";
|
||||
import {OSM, Vector as VectorSource} from "ol/source";
|
||||
import TileLayer from "ol/layer/Tile";
|
||||
import {Feature, View} from "ol";
|
||||
import {fromLonLat, transform, transformExtent} from "ol/proj";
|
||||
|
||||
import {LineString, Point} from "ol/geom";
|
||||
import {Vector as VectorLayer} from "ol/layer";
|
||||
import {Circle, Fill, Icon, Stroke, Style} from "ol/style";
|
||||
import {Coordinate} from "ol/coordinate";
|
||||
|
@ -12,21 +8,20 @@ import {State} from "ol/render";
|
|||
import {Line, Vector2d} from "./vectorUtils";
|
||||
import {drawZebraCrossing, zebraPatterns} from "./zebraUtils";
|
||||
// @ts-ignore
|
||||
import importdata from "../data/data.json?inline"
|
||||
// @ts-ignore
|
||||
import dataURL from "../data/data.json?url"
|
||||
import {Crossing} from "../interfaces";
|
||||
import dataURL from "../data/Wien.json?url"
|
||||
import prideFlag from "../assets/prideflag.svg"
|
||||
import transFlag from "../assets/transflag.svg"
|
||||
import {averageCoords} from "../utils/geo";
|
||||
import {loadData, MetaData} from "./features";
|
||||
// @ts-ignore
|
||||
import importdata from "../data/Wien.json?inline"
|
||||
import Navigo from "navigo";
|
||||
import {redirect} from "./router";
|
||||
import {areas, viewFromArea, Wien} from "./areaData";
|
||||
import {Crossing} from "../interfaces";
|
||||
|
||||
import "./style.scss"
|
||||
import "hint.css/hint.base.css"
|
||||
const root = import.meta.env.PROD ? "/s/tmp/rainbowroad/" : "/"
|
||||
export const router = new Navigo(root)
|
||||
|
||||
|
||||
|
||||
|
||||
const data = importdata as Crossing[]
|
||||
const map = new Map({
|
||||
target: 'map',
|
||||
layers: [
|
||||
|
@ -34,51 +29,30 @@ const map = new Map({
|
|||
source: new OSM({url: "https://maps.lw1.at/tiles/1.0.0/osm/GLOBAL_MERCATOR/{z}/{x}/{y}.png"})
|
||||
}),
|
||||
],
|
||||
view: new View({
|
||||
center: fromLonLat([16.3787, 48.2089]),
|
||||
zoom: 13,
|
||||
// https://www.wien.gv.at/statistik/lebensraum/tabellen/stadtgebiet-eckdaten.html
|
||||
extent: transformExtent([16.18278, 48.11833, 16.58, 48.32306], 'EPSG:4326', 'EPSG:3857'),
|
||||
constrainOnlyCenter: true
|
||||
})
|
||||
view: viewFromArea(Wien)
|
||||
});
|
||||
const vectorLine = new VectorSource({
|
||||
const vectorSource = new VectorSource({
|
||||
attributions: ["<a target='_blank' href='" + dataURL + "'>Rohdaten</a>"]
|
||||
});
|
||||
const metaData: { [id: number]: Crossing } = {}
|
||||
data.sort((a, b) => {
|
||||
/*
|
||||
put trans flag on top (so they are not covered,
|
||||
but apart from that keep the drawing order random
|
||||
*/
|
||||
if (a.type == "transFlag") {
|
||||
return 1
|
||||
}
|
||||
if (b.type == "transFlag") {
|
||||
return -1
|
||||
}
|
||||
return Math.random() - 0.5;
|
||||
let metaData: MetaData
|
||||
|
||||
router.on("/Wien", () => {
|
||||
map.setView(viewFromArea(Wien))
|
||||
// @ts-ignore
|
||||
import("../data/Wien.json?inline").then((data) => {
|
||||
metaData = loadData(data.default as unknown as Crossing[], vectorSource)
|
||||
})
|
||||
})
|
||||
data.forEach(c => {
|
||||
if (typeof c.geo === "undefined") {
|
||||
return
|
||||
}
|
||||
const points = c.geo.coords.map(coord => transform(coord, 'EPSG:4326', 'EPSG:3857'));
|
||||
router.on("/Ober%C3%B6sterreich", () => {
|
||||
map.setView(viewFromArea(areas.OOE))
|
||||
|
||||
const featureLine = new Feature({
|
||||
geometry: new LineString(points)
|
||||
});
|
||||
const featureDot = new Feature({
|
||||
geometry: new Point(averageCoords(points))
|
||||
});
|
||||
featureLine.setId(c.id)
|
||||
featureDot.setId(c.id + 10000)
|
||||
metaData[c.id] = c
|
||||
vectorLine.addFeature(featureLine);
|
||||
vectorLine.addFeature(featureDot);
|
||||
// @ts-ignore
|
||||
import("../data/Oberösterreich.json?inline").then((data) => {
|
||||
metaData = loadData(data.default as unknown as Crossing[], vectorSource)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
redirect(router, "/", "/Wien")
|
||||
router.resolve()
|
||||
const greenLine = new Style({
|
||||
fill: new Fill({color: '#00FF00'}),
|
||||
stroke: new Stroke({color: '#00FF00', width: 2})
|
||||
|
@ -128,7 +102,7 @@ const circleStyle = new Style({
|
|||
}),
|
||||
})
|
||||
const vectorLineLayer = new VectorLayer({
|
||||
source: vectorLine,
|
||||
source: vectorSource,
|
||||
style: function (feature, resolution) {
|
||||
const zoom = map.getView().getZoomForResolution(resolution);
|
||||
if (!zoom) {
|
||||
|
@ -153,6 +127,18 @@ const vectorLineLayer = new VectorLayer({
|
|||
map.addLayer(vectorLineLayer);
|
||||
|
||||
|
||||
// window.bla = function () {
|
||||
// const view = map.getView()
|
||||
// map.setView(
|
||||
// new View({
|
||||
// center: fromLonLat([15.3787, 47.2089]),
|
||||
// zoom: 13,
|
||||
// // https://www.wien.gv.at/statistik/lebensraum/tabellen/stadtgebiet-eckdaten.html
|
||||
// extent: transformExtent([15.18278, 47.11833, 15.58, 47.32306], 'EPSG:4326', 'EPSG:3857'),
|
||||
// constrainOnlyCenter: true
|
||||
// }))
|
||||
// }
|
||||
|
||||
import("./popups").then(popups => {
|
||||
popups.initPopups(map, metaData);
|
||||
})
|
||||
|
|
|
@ -3,6 +3,7 @@ import {createDateWithDisclaimer, displaySources} from "./text";
|
|||
import type Map from "ol/Map";
|
||||
import {Crossing} from "../interfaces";
|
||||
import {createElement} from "./domutils";
|
||||
import "hint.css/hint.base.css"
|
||||
|
||||
export function initPopups(map: Map, metaData: { [id: number]: Crossing }) {
|
||||
const container = document.getElementById('popup')!;
|
||||
|
@ -24,7 +25,7 @@ export function initPopups(map: Map, metaData: { [id: number]: Crossing }) {
|
|||
closer.blur();
|
||||
return false;
|
||||
};
|
||||
map.on('singleclick', function (event) {
|
||||
map.on('singleclick', event => {
|
||||
map.forEachFeatureAtPixel(event.pixel, feature => {
|
||||
const coordinate = event.coordinate;
|
||||
let id = Number(feature.getId())
|
||||
|
|
10
src/router.ts
Normal file
10
src/router.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import Navigo, {Route} from "navigo";
|
||||
|
||||
export function redirect(router:Navigo,from:string,to:string){
|
||||
router.on(from, () => {
|
||||
router.navigate(to, {
|
||||
historyAPIMethod: 'replaceState'
|
||||
})
|
||||
})
|
||||
|
||||
}
|
|
@ -26,9 +26,9 @@
|
|||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "commonjs", /* Specify what module code is generated. */
|
||||
"module": "ESNext", /* Specify what module code is generated. */
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
|
|
|
@ -21,3 +21,10 @@ export function lineLengthInM(start: number[], end: number[]) {
|
|||
const value = earthRadius * c * 1000
|
||||
return Math.round(value * 100) / 100
|
||||
}
|
||||
|
||||
export function averageCoords(coords: number[][]): number[] {
|
||||
return [
|
||||
(coords[0][0] + coords[1][0]) / 2,
|
||||
(coords[0][1] + coords[1][1]) / 2
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue