1
0
Fork 0
mirror of https://github.com/Findus23/RainbowRoad.git synced 2024-09-19 16:03:52 +02:00

allow multiple areas

This commit is contained in:
Lukas Winkler 2022-08-15 15:54:18 +02:00
parent 0c666a1d11
commit 80cbd705fe
Signed by: lukas
GPG key ID: 54DE4D798D244853
19 changed files with 221 additions and 70 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 B

View file

@ -3,8 +3,8 @@ import type {Crossing, OSMNodeSource, OSMWaySource, OverPassNode, OverPassRespon
import {nodeData, wayData} from "./overpass"; import {nodeData, wayData} from "./overpass";
import {lineLengthInM} from "../utils/geo"; import {lineLengthInM} from "../utils/geo";
async function runfetch() { async function runfetch(filename: string) {
const data: Crossing[] = JSON.parse(fs.readFileSync("../data/data.json", 'utf8')); const data: Crossing[] = JSON.parse(fs.readFileSync(filename, 'utf8'));
function firstLastNodeCoords(nodeMap: { [id: number]: OverPassNode }, nodeList: number[]) { function firstLastNodeCoords(nodeMap: { [id: number]: OverPassNode }, nodeList: number[]) {
const coords: number[][] = [] const coords: number[][] = []
@ -75,8 +75,14 @@ async function runfetch() {
length: lineLengthInM(coords[0], coords[1]) length: lineLengthInM(coords[0], coords[1])
} }
// crossings[i] = d // 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)
})

View file

@ -2,10 +2,10 @@ import * as fs from "fs";
import type {Crossing} from "../interfaces"; import type {Crossing} from "../interfaces";
function runstats() { 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 } = {}; const counts: { [key: number]: number } = {};
for (const num of bezirke) { for (const num of bezirke) {

2
custom.d.ts vendored
View file

@ -1,3 +1,5 @@
import "vite/client"
declare module "*.svg" { declare module "*.svg" {
const content: string; const content: string;
export default content; export default content;

31
data/Oberösterreich.json Normal file
View 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
}
}
]

View file

@ -68,6 +68,7 @@
"news", "news",
"official", "official",
"proposal", "proposal",
"photo",
"streetview", "streetview",
"in person" "in person"
] ]
@ -153,7 +154,6 @@
}, },
"required": [ "required": [
"id", "id",
"bezirk",
"name", "name",
"type", "type",
"sources", "sources",

View file

@ -19,7 +19,7 @@ export interface OSMNodeSource {
} }
export interface Source { export interface Source {
type: "news" | "official" | "proposal" | "streetview" | "in person" type: "news" | "official" | "proposal" | "photo" | "streetview" | "in person"
date: string date: string
url?: string url?: string
} }
@ -32,7 +32,7 @@ export interface GeoData {
export interface Crossing { export interface Crossing {
id: number id: number
name: string name: string
bezirk: number bezirk?: number
comment?: string comment?: string
set?: string set?: string
type: FlagType type: FlagType

View file

@ -5,3 +5,9 @@ Mariahilfer Straße
Unbekannter Trans-Pride-Streifen in Rudolfsheim-Fünfhaus Unbekannter Trans-Pride-Streifen in Rudolfsheim-Fünfhaus
https://www.wien.gv.at/bezirke/rudolfsheim-fuenfhaus/politik/sitzungen/pdf/20210701-antrag-pride-schutzweg.pdf 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
View file

@ -13,6 +13,7 @@
"axios": "^0.27.2", "axios": "^0.27.2",
"hint.css": "^2.7.0", "hint.css": "^2.7.0",
"micromodal": "^0.4.10", "micromodal": "^0.4.10",
"navigo": "^8.11.1",
"node-fetch": "^3.2.10", "node-fetch": "^3.2.10",
"ol": "^6.14.1", "ol": "^6.14.1",
"ts-node": "^10.9.1" "ts-node": "^10.9.1"
@ -1132,6 +1133,11 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" "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": { "node_modules/node-domexception": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
@ -2320,6 +2326,11 @@
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"dev": true "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": { "node-domexception": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",

View file

@ -8,7 +8,7 @@
"dev": "vite", "dev": "vite",
"build": "tsc --skipLibCheck && vite build", "build": "tsc --skipLibCheck && vite build",
"preview": "vite preview", "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": { "devDependencies": {
"@types/micromodal": "^0.3.3", "@types/micromodal": "^0.3.3",
@ -22,6 +22,7 @@
"axios": "^0.27.2", "axios": "^0.27.2",
"hint.css": "^2.7.0", "hint.css": "^2.7.0",
"micromodal": "^0.4.10", "micromodal": "^0.4.10",
"navigo": "^8.11.1",
"node-fetch": "^3.2.10", "node-fetch": "^3.2.10",
"ol": "^6.14.1", "ol": "^6.14.1",
"ts-node": "^10.9.1" "ts-node": "^10.9.1"

41
src/areaData.ts Normal file
View 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
View 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
View file

@ -0,0 +1,3 @@
import "./style.scss"
import "./map"

View file

@ -1,10 +1,6 @@
import Map from "ol/Map"; import Map from "ol/Map";
import {OSM, Vector as VectorSource} from "ol/source"; import {OSM, Vector as VectorSource} from "ol/source";
import TileLayer from "ol/layer/Tile"; 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 {Vector as VectorLayer} from "ol/layer";
import {Circle, Fill, Icon, Stroke, Style} from "ol/style"; import {Circle, Fill, Icon, Stroke, Style} from "ol/style";
import {Coordinate} from "ol/coordinate"; import {Coordinate} from "ol/coordinate";
@ -12,21 +8,20 @@ import {State} from "ol/render";
import {Line, Vector2d} from "./vectorUtils"; import {Line, Vector2d} from "./vectorUtils";
import {drawZebraCrossing, zebraPatterns} from "./zebraUtils"; import {drawZebraCrossing, zebraPatterns} from "./zebraUtils";
// @ts-ignore // @ts-ignore
import importdata from "../data/data.json?inline" import dataURL from "../data/Wien.json?url"
// @ts-ignore
import dataURL from "../data/data.json?url"
import {Crossing} from "../interfaces";
import prideFlag from "../assets/prideflag.svg" import prideFlag from "../assets/prideflag.svg"
import transFlag from "../assets/transflag.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" const root = import.meta.env.PROD ? "/s/tmp/rainbowroad/" : "/"
import "hint.css/hint.base.css" export const router = new Navigo(root)
const data = importdata as Crossing[]
const map = new Map({ const map = new Map({
target: 'map', target: 'map',
layers: [ 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"}) source: new OSM({url: "https://maps.lw1.at/tiles/1.0.0/osm/GLOBAL_MERCATOR/{z}/{x}/{y}.png"})
}), }),
], ],
view: new View({ view: viewFromArea(Wien)
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
})
}); });
const vectorLine = new VectorSource({ const vectorSource = new VectorSource({
attributions: ["<a target='_blank' href='" + dataURL + "'>Rohdaten</a>"] attributions: ["<a target='_blank' href='" + dataURL + "'>Rohdaten</a>"]
}); });
const metaData: { [id: number]: Crossing } = {} let metaData: MetaData
data.sort((a, b) => {
/* router.on("/Wien", () => {
put trans flag on top (so they are not covered, map.setView(viewFromArea(Wien))
but apart from that keep the drawing order random // @ts-ignore
*/ import("../data/Wien.json?inline").then((data) => {
if (a.type == "transFlag") { metaData = loadData(data.default as unknown as Crossing[], vectorSource)
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
vectorLine.addFeature(featureLine);
vectorLine.addFeature(featureDot);
}) })
router.on("/Ober%C3%B6sterreich", () => {
map.setView(viewFromArea(areas.OOE))
// @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({ const greenLine = new Style({
fill: new Fill({color: '#00FF00'}), fill: new Fill({color: '#00FF00'}),
stroke: new Stroke({color: '#00FF00', width: 2}) stroke: new Stroke({color: '#00FF00', width: 2})
@ -128,7 +102,7 @@ const circleStyle = new Style({
}), }),
}) })
const vectorLineLayer = new VectorLayer({ const vectorLineLayer = new VectorLayer({
source: vectorLine, source: vectorSource,
style: function (feature, resolution) { style: function (feature, resolution) {
const zoom = map.getView().getZoomForResolution(resolution); const zoom = map.getView().getZoomForResolution(resolution);
if (!zoom) { if (!zoom) {
@ -153,6 +127,18 @@ const vectorLineLayer = new VectorLayer({
map.addLayer(vectorLineLayer); 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 => { import("./popups").then(popups => {
popups.initPopups(map, metaData); popups.initPopups(map, metaData);
}) })

View file

@ -3,6 +3,7 @@ import {createDateWithDisclaimer, displaySources} from "./text";
import type Map from "ol/Map"; import type Map from "ol/Map";
import {Crossing} from "../interfaces"; import {Crossing} from "../interfaces";
import {createElement} from "./domutils"; import {createElement} from "./domutils";
import "hint.css/hint.base.css"
export function initPopups(map: Map, metaData: { [id: number]: Crossing }) { export function initPopups(map: Map, metaData: { [id: number]: Crossing }) {
const container = document.getElementById('popup')!; const container = document.getElementById('popup')!;
@ -24,7 +25,7 @@ export function initPopups(map: Map, metaData: { [id: number]: Crossing }) {
closer.blur(); closer.blur();
return false; return false;
}; };
map.on('singleclick', function (event) { map.on('singleclick', event => {
map.forEachFeatureAtPixel(event.pixel, feature => { map.forEachFeatureAtPixel(event.pixel, feature => {
const coordinate = event.coordinate; const coordinate = event.coordinate;
let id = Number(feature.getId()) let id = Number(feature.getId())

10
src/router.ts Normal file
View 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'
})
})
}

View file

@ -26,9 +26,9 @@
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */ /* 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. */ // "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. */ // "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. */ // "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. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */

View file

@ -21,3 +21,10 @@ export function lineLengthInM(start: number[], end: number[]) {
const value = earthRadius * c * 1000 const value = earthRadius * c * 1000
return Math.round(value * 100) / 100 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
]
}