1
0
Fork 0
mirror of https://github.com/Findus23/RainbowRoad.git synced 2024-09-16 12:33:51 +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 {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)
})

View 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
View file

@ -1,3 +1,5 @@
import "vite/client"
declare module "*.svg" {
const content: string;
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",
"official",
"proposal",
"photo",
"streetview",
"in person"
]
@ -153,7 +154,6 @@
},
"required": [
"id",
"bezirk",
"name",
"type",
"sources",

View file

@ -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,

View file

@ -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
View file

@ -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",

View file

@ -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
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 {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);
})

View file

@ -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
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. */
/* 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. */

View file

@ -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
]
}