From d45891d34cf16a7dafcb4ce456dc23793ad69d16 Mon Sep 17 00:00:00 2001 From: Lukas Winkler Date: Sun, 20 Dec 2020 19:53:58 +0100 Subject: [PATCH] port conversion script to typescript --- convert.js | 78 ---------------------------------- convert/index.ts | 71 +++++++++++++++++++++++++++++++ convert/tsconfig.json | 6 +++ geojson-precision/LICENSE | 8 ++++ geojson-precision/README.md | 2 + geojson-precision/index.ts | 83 +++++++++++++++++++++++++++++++++++++ package.json | 8 +++- src/interfaces.ts | 21 +++++++++- src/topoJsonLayer.ts | 8 ++-- tsconfig.json | 17 +++++--- yarn.lock | 50 +++++++++++----------- 11 files changed, 236 insertions(+), 116 deletions(-) delete mode 100644 convert.js create mode 100644 convert/index.ts create mode 100644 convert/tsconfig.json create mode 100644 geojson-precision/LICENSE create mode 100644 geojson-precision/README.md create mode 100644 geojson-precision/index.ts diff --git a/convert.js b/convert.js deleted file mode 100644 index 46b5707..0000000 --- a/convert.js +++ /dev/null @@ -1,78 +0,0 @@ -const fs = require("fs"); -const path = require("path"); -const topojson = require("topojson"); -const simplify = require("simplify-geojson"); -const geojsonPrecision = require("geojson-precision"); -const dataDir = "data/"; -const processedDir = "processed/"; -const dataFiles = fs.readdirSync(dataDir); - -const zeitraum = []; - - -function totopojson(geojson) { - const tpj = topojson.topology({foo: geojson}, 1e5); - const presimplified = topojson.presimplify(tpj); - const finished = topojson.simplify(presimplified); - return topojson.filter(finished, topojson.filterWeight); -} - - -dataFiles.forEach((filename) => { - if (filename === ".gitkeep" || filename === "checksums.sha256" || filename.includes("formatted")) { - return false; - } - const contents = fs.readFileSync(dataDir + filename); - const geojson = JSON.parse(contents); - const nametype = path.parse(filename).name; - - delete geojson.totalFeatures; - delete geojson.crs; - geojson.meta = {}; - geojson.features.forEach((feature) => { - delete feature.properties.SE_ANNO_CAD_DATA; - geojson.meta.WEITERE_INF = feature.properties.WEITERE_INF; - geojson.meta.WEBLINK1 = feature.properties.WEBLINK1; - geojson.meta.WEBLINK2 = feature.properties.WEBLINK2; - delete feature.properties.WEITERE_INF; - delete feature.properties.WEBLINK1; - delete feature.properties.WEBLINK_1; - delete feature.properties.WEBLINK2; - delete feature.properties.BEZIRK2; - delete feature.properties.OBJECTID; - delete feature.properties.PRB_ID; - delete feature.properties.FK_PRB; - delete feature.id; - delete feature.properties.SE_SDO_ROWID; - }); - let result; - if (filename === "Behindertenparkplätze.json") { - geojson.features = geojson.features.filter((feature) => feature.properties.KATEGORIE === 1); - - geojson.features.forEach((feature) => { - delete feature.properties.KATEGORIE; - delete feature.properties.KATEGORIE_TXT; - }); - - } - if (filename.includes("zone") || filename.includes("Geltungsbereiche")) { - result = totopojson(geojson); - result = topojson.presimplify(result); - result = topojson.simplify(result, 1e-9); - result = topojson.quantize(result, 1e4); - fs.writeFileSync(processedDir + nametype + ".structure.json", JSON.stringify(result.objects.foo.geometries[0], null, 2)); - - } else { - result = simplify(geojson, 0.01); - result = geojsonPrecision.parse(result,5); - fs.writeFileSync(processedDir + nametype + ".structure.json", JSON.stringify(result.features[0], null, 2)); - - } - - fs.writeFileSync(processedDir + filename, JSON.stringify(result)); - // fs.writeFileSync("zeitraum.txt", zeitraum.join("\n")); - - -}); - - diff --git a/convert/index.ts b/convert/index.ts new file mode 100644 index 0000000..a75767d --- /dev/null +++ b/convert/index.ts @@ -0,0 +1,71 @@ +import {Feature} from "../src/interfaces"; + +import {presimplify, simplify} from "topojson-simplify" +import {quantize} from "topojson-client"; +import {topology} from "topojson-server"; + +import {reduce_precision} from "../geojson-precision" +import {readdirSync, readFileSync, writeFileSync} from "fs"; + +const dataDir = "../data/"; +const processedDir = "../processed/"; +const dataFiles = readdirSync(dataDir); + + +dataFiles.forEach((filename: string) => { + if (filename === ".gitkeep" || filename === "checksums.sha256" || filename.includes("formatted")) { + return false; + } + const contents = readFileSync(dataDir + filename).toString(); + const geojson = JSON.parse(contents); + // const nametype = path.parse(filename).name; + + delete geojson.totalFeatures; + delete geojson.crs; + geojson.meta = {}; + geojson.features.forEach((feature: Feature) => { + delete feature.properties.SE_ANNO_CAD_DATA; + geojson.meta.WEITERE_INF = feature.properties.WEITERE_INF; + geojson.meta.WEBLINK1 = feature.properties.WEBLINK1; + geojson.meta.WEBLINK2 = feature.properties.WEBLINK2; + delete feature.properties.WEITERE_INF; + delete feature.properties.WEBLINK1; + delete feature.properties.WEBLINK_1; + delete feature.properties.WEBLINK2; + delete feature.properties.BEZIRK2; + delete feature.properties.OBJECTID; + delete feature.properties.PRB_ID; + delete feature.properties.FK_PRB; + delete feature.id; + delete feature.properties.SE_SDO_ROWID; + }); + let result; + if (filename === "Behindertenparkplätze.json") { + geojson.features = geojson.features.filter((feature: Feature) => feature.properties.KATEGORIE === 1); + + geojson.features.forEach((feature: Feature) => { + delete feature.properties.KATEGORIE; + delete feature.properties.KATEGORIE_TXT; + }); + + } + if (filename.includes("zone") || filename.includes("Geltungsbereiche")) { + result = topology({foo: geojson}, 1e5); + // @ts-ignore + result = presimplify(result); + result = simplify(result, 1e-9); + result = quantize(result, 1e4); + // fs.writeFileSync(processedDir + nametype + ".structure.json", JSON.stringify(result.objects.foo.geometries[0], null, 2)); + + } else { + result = reduce_precision(geojson, 5); + // fs.writeFileSync(processedDir + nametype + ".structure.json", JSON.stringify(result.features[0], null, 2)); + + } + + writeFileSync(processedDir + filename, JSON.stringify(result)); + + +}); + + diff --git a/convert/tsconfig.json b/convert/tsconfig.json new file mode 100644 index 0000000..c8d8421 --- /dev/null +++ b/convert/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "module": "CommonJS" + } +} diff --git a/geojson-precision/LICENSE b/geojson-precision/LICENSE new file mode 100644 index 0000000..4602ed3 --- /dev/null +++ b/geojson-precision/LICENSE @@ -0,0 +1,8 @@ +Copyright 2020 Lukas Winkler +Copyright 2019 John J Czaplewski + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/geojson-precision/README.md b/geojson-precision/README.md new file mode 100644 index 0000000..9911903 --- /dev/null +++ b/geojson-precision/README.md @@ -0,0 +1,2 @@ +typescript port of +https://github.com/jczaplew/geojson-precision diff --git a/geojson-precision/index.ts b/geojson-precision/index.ts new file mode 100644 index 0000000..ad2574e --- /dev/null +++ b/geojson-precision/index.ts @@ -0,0 +1,83 @@ +/** + * A typescript port of https://github.com/jczaplew/geojson-precision/blob/master/index.js + * by John J Czaplewski (@jczaplew) + */ +import {Feature, FeatureCollection, GeoJSON, Geometry, GeometryCollection, Position} from "geojson"; + + +export function reduce_precision(t: GeoJSON, precision: number) { + function point(p: Position): Position { + return p.map(function (e, index) { + const exp = Math.pow(10, precision) + return Math.round((e + Number.EPSILON) * exp) / exp + }); + } + + function multi(l: Position[]): Position[] { + return l.map(point); + } + + function poly(p: Position[][]): Position[][] { + return p.map(multi); + } + + function multiPoly(m: Position[][][]): Position[][][] { + return m.map(poly); + } + + function geometry(obj: Geometry): Geometry { + switch (obj.type) { + case "Point": + obj.coordinates = point(obj.coordinates); + return obj; + case "LineString": + case "MultiPoint": + obj.coordinates = multi(obj.coordinates); + return obj; + case "Polygon": + case "MultiLineString": + obj.coordinates = poly(obj.coordinates); + return obj; + case "MultiPolygon": + obj.coordinates = multiPoly(obj.coordinates); + return obj; + case "GeometryCollection": + obj.geometries = obj.geometries.map(geometry); + return obj; + } + } + + function feature(obj: Feature): Feature { + obj.geometry = geometry(obj.geometry); + return obj + } + + function featureCollection(f: FeatureCollection): FeatureCollection { + f.features = f.features.map(feature); + return f; + } + + function geometryCollection(g: GeometryCollection): GeometryCollection { + g.geometries = g.geometries.map(geometry); + return g; + } + + switch (t.type) { + case "Feature": + return feature(t); + case "GeometryCollection" : + return geometryCollection(t); + case "FeatureCollection" : + return featureCollection(t); + case "Point": + case "LineString": + case "Polygon": + case "MultiPoint": + case "MultiPolygon": + case "MultiLineString": + return geometry(t); + default : + return t; + } +} + diff --git a/package.json b/package.json index 4e5c38b..abf006f 100644 --- a/package.json +++ b/package.json @@ -12,18 +12,22 @@ "leaflet": "^1.3.1", "leaflet.locatecontrol": "^0.72.0", "simplify-geojson": "^1.0.3", - "topojson": "^3.0.2", - "topojson-client": "^3.0.0" + "topojson-client": "^3.0.0", + "topojson-server": "^3.0.1", + "topojson-simplify": "^3.0.3" }, "devDependencies": { "@babel/core": "^7.0.0-beta.38", "@babel/preset-env": "^7.0.0-beta.38", "@types/copy-webpack-plugin": "^6.3.0", + "@types/geojson": "^7946.0.7", "@types/leaflet": "^1.4.4", "@types/leaflet.locatecontrol": "^0.60.7", "@types/mini-css-extract-plugin": "^1.2.2", "@types/node": "^14.14.14", "@types/topojson-client": "^3.0.0", + "@types/topojson-server": "^3.0.0", + "@types/topojson-simplify": "^3.0.0", "@types/webpack": "^4.41.25", "@types/webpack-dev-server": "^3.11.1", "@types/webpack-merge": "^4.1.5", diff --git a/src/interfaces.ts b/src/interfaces.ts index 204e21e..7e68cd4 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -1,5 +1,22 @@ -export interface Feature { +import {GeoJSON} from "leaflet"; + +export interface Feature extends GeoJSON.Feature { properties: { ZEITRAUM: string + + KATEGORIE?: number + KATEGORIE_TXT?: number + SE_ANNO_CAD_DATA?: string + WEITERE_INF?: string + WEBLINK1?: string + WEBLINK_1?: string + WEBLINK2?: string + BEZIRK2?: string + PRB_ID?: string + FK_PRB?: string + OBJECTID?: string + SE_SDO_ROWID?: string } -} \ No newline at end of file +} + + diff --git a/src/topoJsonLayer.ts b/src/topoJsonLayer.ts index 4655f46..c070bc7 100644 --- a/src/topoJsonLayer.ts +++ b/src/topoJsonLayer.ts @@ -1,13 +1,13 @@ import L from "leaflet"; -import * as topojson from "topojson-client"; +import {feature} from "topojson-client"; export const TopoJsonLayer = L.GeoJSON.extend({ // @ts-ignore - addData: function (jsonData) { + addData: function (jsonData: TopoJSON) { if (jsonData.type === "Topology") { for (const key in jsonData.objects) { if (Object.prototype.hasOwnProperty.call(jsonData.objects, key)) { - const geojson = topojson.feature(jsonData, jsonData.objects[key]); + const geojson = feature(jsonData, jsonData.objects[key]); L.GeoJSON.prototype.addData.call(this, geojson); } } @@ -16,4 +16,4 @@ export const TopoJsonLayer = L.GeoJSON.extend({ } return this; } -}); \ No newline at end of file +}); diff --git a/tsconfig.json b/tsconfig.json index de89798..604dace 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,10 +1,15 @@ { "compilerOptions": { /* Basic Options */ - "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ - "module": "esnext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + "target": "es5", + /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ + "module": "esnext", + /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ "moduleResolution": "node", - "lib": ["dom"], + "lib": [ + "dom", + "es5" + ], // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ @@ -25,7 +30,8 @@ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ + "strict": true, + /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ @@ -48,7 +54,8 @@ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + "esModuleInterop": true + /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ /* Source Map Options */ diff --git a/yarn.lock b/yarn.lock index d3a3bf4..713a7fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -995,7 +995,7 @@ "@types/qs" "*" "@types/serve-static" "*" -"@types/geojson@*": +"@types/geojson@*", "@types/geojson@^7946.0.7": version "7946.0.7" resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.7.tgz#c8fa532b60a0042219cdf173ca21a975ef0666ad" integrity sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ== @@ -1116,6 +1116,22 @@ "@types/geojson" "*" "@types/topojson-specification" "*" +"@types/topojson-server@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/topojson-server/-/topojson-server-3.0.0.tgz#b668fc808831763320db8f3b339ee168c2e2e5dc" + integrity sha512-OdIgHf+9hbEOdrZEoIaE6staRbCyssznjtggIySUqvWOk9xWK0lodLnn7ks3l8H+wgMTgelEXqyBmAtlyn0fvA== + dependencies: + "@types/geojson" "*" + "@types/topojson-specification" "*" + +"@types/topojson-simplify@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/topojson-simplify/-/topojson-simplify-3.0.0.tgz#54ad7e2f172c662c07ad390e5cf965c147093e65" + integrity sha512-hfrvjZ/KbdAFBgJzdPfkixHgMNbhRvvFSCIOga1rAeluksFV9sSTWx+N4vZymqcfz1J+yMZfP2SCRt+/DHsJCQ== + dependencies: + "@types/geojson" "*" + "@types/topojson-specification" "*" + "@types/topojson-specification@*": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/topojson-specification/-/topojson-specification-1.0.1.tgz#a80cb294290b79f2d674d3f5938c544ed2bd9d80" @@ -6449,37 +6465,21 @@ topojson-client@3, topojson-client@^3.0.0: dependencies: commander "2" -topojson-client@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/topojson-client/-/topojson-client-3.0.0.tgz#1f99293a77ef42a448d032a81aa982b73f360d2f" - integrity sha1-H5kpOnfvQqRI0DKoGqmCtz82DS8= +topojson-server@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/topojson-server/-/topojson-server-3.0.1.tgz#d2b3ec095b6732299be76a48406111b3201a34f5" + integrity sha512-/VS9j/ffKr2XAOjlZ9CgyyeLmgJ9dMwq6Y0YEON8O7p/tGGk+dCWnrE03zEdu7i4L7YsFZLEPZPzCvcB7lEEXw== dependencies: commander "2" -topojson-server@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/topojson-server/-/topojson-server-3.0.0.tgz#378e78e87c3972a7b5be2c5d604369b6bae69c5e" - integrity sha1-N4546Hw5cqe1vixdYENptrrmnF4= - dependencies: - commander "2" - -topojson-simplify@3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/topojson-simplify/-/topojson-simplify-3.0.2.tgz#8a2403e639531500fafa0c6594e8b0fadebc2c02" - integrity sha512-gyYSVRt4jO/0RJXKZQPzTDQRWV+D/nOfiljNUv0HBXslFLtq3yxRHrl7jbrjdbda5Ytdr7M8BZUI4OxU7tnbRQ== +topojson-simplify@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/topojson-simplify/-/topojson-simplify-3.0.3.tgz#668de0ca7ab36797002087190c2222f938af2ab2" + integrity sha512-V+pBjLVzSQ3+hSOxBiV01OVXgFiCmMO8ia3huxKEyIMTC1ApQHBcdXdOqcQ6U2JJJD31TZduwY6KyF15R8sUgg== dependencies: commander "2" topojson-client "3" -topojson@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/topojson/-/topojson-3.0.2.tgz#fcb927306c3e0fa76656fa58deed4555d2346fb4" - integrity sha512-u3zeuL6WEVL0dmsRn7uHZKc4Ao4gpW3sORUv+N3ezLTvY3JdCuyg0hvpWiIfFw8p/JwVN++SvAsFgcFEeR15rQ== - dependencies: - topojson-client "3.0.0" - topojson-server "3.0.0" - topojson-simplify "3.0.2" - tough-cookie@~2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"