osm2geojson-lite 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -17
- package/package.json +10 -5
- package/dist/node/index.d.ts +0 -12
- package/dist/node/index.js +0 -199
- package/dist/node/osmobjs.d.ts +0 -73
- package/dist/node/osmobjs.js +0 -377
- package/dist/node/polytags.json +0 -84
- package/dist/node/utils.d.ts +0 -60
- package/dist/node/utils.js +0 -222
- package/dist/node/xmlparser.d.ts +0 -32
- package/dist/node/xmlparser.js +0 -160
- package/dist/web/osm2geojson-lite.js +0 -1
package/README.md
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
osm2geojson-lite
|
|
2
2
|
============
|
|
3
3
|
|
|
4
|
+
[](https://www.npmjs.com/package/osm2geojson-lite) [](https://codecov.io/gh/tibetty/osm2geojson-lite/)
|
|
5
|
+
|
|
6
|
+
|
|
4
7
|
A lightweight (not as lightweight as xml2geojson though) yet faster convertor for [OSM](http://openstreetmap.org) [data](http://wiki.openstreetmap.org/wiki/OSM_XML) whatever in XML or JSON formats to [GeoJSON](http://www.geojson.org/) - much faster (the more complex the data source is, the more performance advantages it posesses) than osmtogeojson in most situations - implemented in pure JavaScript without any 3rd party dependency.
|
|
5
8
|
|
|
6
9
|
History
|
|
7
10
|
-----
|
|
8
11
|
An internal function inside [query-geo-boundary](https://www.npmjs.com/package/query-geo-boundary) → stripped out to handle OSM XML only [xml2geojson-lite](https://www.npmjs.com/package/xml2geojson-lite) → this library that supports both OSM XML and OSM/Overpass JSON
|
|
9
12
|
|
|
10
|
-
Changelog:
|
|
11
|
-
-----
|
|
12
|
-
* Late 2018: this repository was created and the initial version was pushed to github - almost around specific usages for myself.
|
|
13
|
-
* 2019-2025: quite a few contributors had fixed quite a few bugs and also contributed some good ideas - thanks for their efforts!
|
|
14
|
-
* 2025-03-03: fixed a few bugs around non-*Polygon features processing and convert it to a pure TypeScript project (codes published to [NPM](https://npmjs.org/) have become TSC compiled from now on).
|
|
15
|
-
|
|
16
13
|
Usage
|
|
17
14
|
-----
|
|
18
15
|
|
|
@@ -25,7 +22,7 @@ Installation:
|
|
|
25
22
|
Usage:
|
|
26
23
|
|
|
27
24
|
```js
|
|
28
|
-
|
|
25
|
+
import osm2geojson from 'osm2geojson-lite';
|
|
29
26
|
let geojson = osm2geojson(osm, opts);
|
|
30
27
|
```
|
|
31
28
|
|
|
@@ -46,9 +43,9 @@ Converts OSM data (XML/JSON) to GeoJSON.
|
|
|
46
43
|
|
|
47
44
|
* `osm`: the OSM XML data in String, or OSM/Overpass JSON as object or in String
|
|
48
45
|
* `opts?`: optional, the options object, right now supports below properties/fields:
|
|
49
|
-
- `completeFeature
|
|
50
|
-
- `renderTagged`: the default value is `false`. When it's set to `true`, the returned geojson will include all elements with tags (i.e., tagged) until `
|
|
51
|
-
- `
|
|
46
|
+
- `completeFeature`: the default value is `false`. When it's set to `true`, the returned geojson will include all elements that meet the specified conditions in `FeatureCollection` format; otherwise, only the bare geometry of the first `relation` element will be returned.
|
|
47
|
+
- `renderTagged`: the default value is `false`. When it's set to `true`, the returned geojson will include all elements with tags (i.e., tagged) until `excludeWay` changes its behavior a bit; otherwise only the unreferenced ones get returned.
|
|
48
|
+
- `excludeWay`: the default value is `true`. When it's set to `true`, the returned `FeatureCollection` will exclude all referenced `way`s even though they are tagged; otherwise the features of those `way`s will be included in the resulted result as well.
|
|
52
49
|
|
|
53
50
|
|
|
54
51
|
Performance
|
|
@@ -58,9 +55,8 @@ Performance
|
|
|
58
55
|
3. For each script, run as many as times seperately and then calculate the average cost time (ACT for short)
|
|
59
56
|
4. The # listed in the table below are coarse lowest values of dividing the ACT of `osmtogeojson` by the one of this library
|
|
60
57
|
```
|
|
61
|
-
$ cd
|
|
62
|
-
$
|
|
63
|
-
$ node otg-bench.js
|
|
58
|
+
$ cd test
|
|
59
|
+
$ npm run bench
|
|
64
60
|
```
|
|
65
61
|
1. XML
|
|
66
62
|
|
|
@@ -79,7 +75,7 @@ Correctness
|
|
|
79
75
|
---
|
|
80
76
|
You can copy the converted results to [geojsonlint](http://geojsonlint.com) for the correctness validation. Up until now, `osm2geojson-lite` behaves pretty well with all the samples (also quite representative) in the `data` subfolers under `test` and `bench` directories, which also outperforms `osmtogeojson`.
|
|
81
77
|
|
|
82
|
-
The client side example shipped along with this package, `test/index.html`
|
|
78
|
+
The client side example shipped along with this package, `test/index.html` - due to CORS limitation, the direct post to geojsonlint is blocked, so there's a "copy to clipboard" button for you to ease the validation.
|
|
83
79
|
|
|
84
80
|
Node.JS version
|
|
85
81
|
---
|
|
@@ -91,10 +87,10 @@ Dependencies
|
|
|
91
87
|
|
|
92
88
|
License
|
|
93
89
|
---
|
|
94
|
-
|
|
90
|
+
MIT
|
|
95
91
|
|
|
96
92
|
Collaborators
|
|
97
93
|
---
|
|
98
|
-
* tibetty
|
|
99
|
-
* HarelM
|
|
94
|
+
* [tibetty](https://github.com/tibetty/)
|
|
95
|
+
* [HarelM](https://github.com/HarelM)
|
|
100
96
|
|
package/package.json
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"bugs": {
|
|
26
26
|
"url": "https://github.com/tibetty/osm2geojson-lite/issues"
|
|
27
27
|
},
|
|
28
|
-
"bundleDependencies":
|
|
28
|
+
"bundleDependencies": [],
|
|
29
29
|
"deprecated": false,
|
|
30
30
|
"description": "a lightweight yet faster osm (either in xml or in json formats) to geojson convertor - 4x faster than xmldom + osmtogeojson in most situations - implemented in pure JavaScript without any 3rd party dependency",
|
|
31
31
|
"homepage": "https://github.com/tibetty/osm2geojson-lite#readme",
|
|
@@ -53,20 +53,25 @@
|
|
|
53
53
|
"url": "git+https://github.com/tibetty/osm2geojson-lite.git"
|
|
54
54
|
},
|
|
55
55
|
"scripts": {
|
|
56
|
-
"build": "
|
|
57
|
-
"
|
|
56
|
+
"build-node": "tsc --declaration && cp src/polytags.json dist/node",
|
|
57
|
+
"build-web": "mkdir -p dist/web && browserify -s osm2geojson dist/node/index.js | uglifyjs -c -m -o dist/web/osm2geojson-lite.js",
|
|
58
|
+
"build": "npm run build-node && npm run build-web",
|
|
59
|
+
"test": "vitest test/e2e.test.ts --coverage"
|
|
58
60
|
},
|
|
59
61
|
"optionalDependencies": {
|
|
60
62
|
"@types/geojson": "^7946.0.16"
|
|
61
63
|
},
|
|
62
|
-
"version": "1.0
|
|
64
|
+
"version": "1.1.0",
|
|
63
65
|
"directories": {
|
|
64
66
|
"lib": "lib",
|
|
65
67
|
"test": "test"
|
|
66
68
|
},
|
|
67
69
|
"devDependencies": {
|
|
70
|
+
"@vitest/coverage-v8": "^3.1.3",
|
|
68
71
|
"browserify": "^17.0.1",
|
|
69
|
-
"
|
|
72
|
+
"typescript": "^5.8.3",
|
|
73
|
+
"uglify-js": "^3.19.3",
|
|
74
|
+
"vitest": "^3.1.3"
|
|
70
75
|
},
|
|
71
76
|
"files": [
|
|
72
77
|
"dist/**/*.js",
|
package/dist/node/index.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { FeatureCollection, GeometryObject } from 'geojson';
|
|
2
|
-
interface IOptions {
|
|
3
|
-
completeFeature?: boolean;
|
|
4
|
-
allFeatures?: boolean;
|
|
5
|
-
renderTagged?: boolean;
|
|
6
|
-
excludeWay?: boolean;
|
|
7
|
-
suppressWay?: boolean;
|
|
8
|
-
}
|
|
9
|
-
declare function osm2geojson(osm: string | {
|
|
10
|
-
[k: string]: any;
|
|
11
|
-
}, opts?: IOptions): FeatureCollection<GeometryObject>;
|
|
12
|
-
export = osm2geojson;
|
package/dist/node/index.js
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
const osmobjs_1 = require("./osmobjs");
|
|
6
|
-
const utils_1 = require("./utils");
|
|
7
|
-
const xmlparser_1 = __importDefault(require("./xmlparser"));
|
|
8
|
-
function osm2geojson(osm, opts) {
|
|
9
|
-
let completeFeature = false;
|
|
10
|
-
let renderTagged = false;
|
|
11
|
-
let excludeWay = true;
|
|
12
|
-
const parseOpts = (os) => {
|
|
13
|
-
if (os) {
|
|
14
|
-
completeFeature = os.completeFeature || os.allFeatures ? true : false;
|
|
15
|
-
renderTagged = os.renderTagged ? true : false;
|
|
16
|
-
const wayOpt = os.suppressWay || os.excludeWay;
|
|
17
|
-
if (wayOpt !== undefined && !wayOpt) {
|
|
18
|
-
excludeWay = false;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
if (opts) {
|
|
23
|
-
parseOpts(opts);
|
|
24
|
-
}
|
|
25
|
-
const detectFormat = (o) => {
|
|
26
|
-
if (o.elements) {
|
|
27
|
-
return 'json';
|
|
28
|
-
}
|
|
29
|
-
if (o.indexOf('<osm') >= 0) {
|
|
30
|
-
return 'xml';
|
|
31
|
-
}
|
|
32
|
-
if (o.trim().startsWith('{')) {
|
|
33
|
-
return 'json-raw';
|
|
34
|
-
}
|
|
35
|
-
return 'invalid';
|
|
36
|
-
};
|
|
37
|
-
let format = detectFormat(osm);
|
|
38
|
-
const refElements = new utils_1.RefElements();
|
|
39
|
-
let featureArray = [];
|
|
40
|
-
const analyzeFeaturesFromJson = (o) => {
|
|
41
|
-
for (const elem of osm.elements) {
|
|
42
|
-
switch (elem.type) {
|
|
43
|
-
case 'node':
|
|
44
|
-
const node = new osmobjs_1.Node(elem.id, refElements);
|
|
45
|
-
if (elem.tags) {
|
|
46
|
-
node.addTags(elem.tags);
|
|
47
|
-
}
|
|
48
|
-
node.addProps((0, utils_1.purgeProps)(elem, ['id', 'type', 'tags', 'lat', 'lon']));
|
|
49
|
-
node.setLatLng(elem);
|
|
50
|
-
break;
|
|
51
|
-
case 'way':
|
|
52
|
-
const way = new osmobjs_1.Way(elem.id, refElements);
|
|
53
|
-
if (elem.tags) {
|
|
54
|
-
way.addTags(elem.tags);
|
|
55
|
-
}
|
|
56
|
-
way.addProps((0, utils_1.purgeProps)(elem, ['id', 'type', 'tags', 'nodes', 'geometry']));
|
|
57
|
-
if (elem.geometry) {
|
|
58
|
-
way.setLatLngArray(elem.geometry);
|
|
59
|
-
}
|
|
60
|
-
else if (elem.nodes) {
|
|
61
|
-
for (const n of elem.nodes) {
|
|
62
|
-
way.addNodeRef(n);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
break;
|
|
66
|
-
case 'relation':
|
|
67
|
-
const relation = new osmobjs_1.Relation(elem.id, refElements);
|
|
68
|
-
if (elem.bounds) {
|
|
69
|
-
relation.setBounds([parseFloat(elem.bounds.minlon), parseFloat(elem.bounds.minlat), parseFloat(elem.bounds.maxlon), parseFloat(elem.bounds.maxlat)]);
|
|
70
|
-
}
|
|
71
|
-
if (elem.tags) {
|
|
72
|
-
relation.addTags(elem.tags);
|
|
73
|
-
}
|
|
74
|
-
relation.addProps((0, utils_1.purgeProps)(elem, ['id', 'type', 'tags', 'bounds', 'members']));
|
|
75
|
-
if (elem.members) {
|
|
76
|
-
for (const member of elem.members) {
|
|
77
|
-
relation.addMember(member);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
default:
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
const analyzeFeaturesFromXml = (o) => {
|
|
86
|
-
const xmlParser = new xmlparser_1.default({ progressive: true });
|
|
87
|
-
xmlParser.on('</osm.node>', (node) => {
|
|
88
|
-
const nd = new osmobjs_1.Node(node.id, refElements);
|
|
89
|
-
for (const [k, v] of Object.entries(node)) {
|
|
90
|
-
if (!k.startsWith('$') && ['id', 'lon', 'lat'].indexOf(k) < 0) {
|
|
91
|
-
nd.addProp(k, v);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
nd.setLatLng(node);
|
|
95
|
-
if (node.$innerNodes) {
|
|
96
|
-
for (const ind of node.$innerNodes) {
|
|
97
|
-
if (ind.$tag === 'tag') {
|
|
98
|
-
nd.addTag(ind.k, ind.v);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
xmlParser.on('</osm.way>', (node) => {
|
|
104
|
-
const way = new osmobjs_1.Way(node.id, refElements);
|
|
105
|
-
for (const [k, v] of Object.entries(node)) {
|
|
106
|
-
if (!k.startsWith('$') && ['id'].indexOf(k) < 0) {
|
|
107
|
-
way.addProp(k, v);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
if (node.$innerNodes) {
|
|
111
|
-
for (const ind of node.$innerNodes) {
|
|
112
|
-
if (ind.$tag === 'nd') {
|
|
113
|
-
if (ind.lon && ind.lat) {
|
|
114
|
-
way.addLatLng(ind);
|
|
115
|
-
}
|
|
116
|
-
else if (ind.ref) {
|
|
117
|
-
way.addNodeRef(ind.ref);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
else if (ind.$tag === 'tag') {
|
|
121
|
-
way.addTag(ind.k, ind.v);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
xmlParser.on('<osm.relation>', (node) => new osmobjs_1.Relation(node.id, refElements));
|
|
127
|
-
xmlParser.on('</osm.relation.member>', (node, parent) => {
|
|
128
|
-
const relation = refElements.get(`relation/${parent === null || parent === void 0 ? void 0 : parent.id}`);
|
|
129
|
-
const member = {
|
|
130
|
-
type: node.type,
|
|
131
|
-
role: node.role ? node.role : '',
|
|
132
|
-
ref: node.ref,
|
|
133
|
-
};
|
|
134
|
-
if (node.lat && node.lon) {
|
|
135
|
-
member.lat = node.lat, member.lon = node.lon, member.tags = {};
|
|
136
|
-
for (const [k, v] of Object.entries(node)) {
|
|
137
|
-
if (!k.startsWith('$') && ['type', 'lat', 'lon'].indexOf(k) < 0) {
|
|
138
|
-
member[k] = v;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
if (node.$innerNodes) {
|
|
143
|
-
const geometry = [];
|
|
144
|
-
const nodes = [];
|
|
145
|
-
for (const ind of node.$innerNodes) {
|
|
146
|
-
if (ind.lat && ind.lon) {
|
|
147
|
-
geometry.push(ind);
|
|
148
|
-
}
|
|
149
|
-
else if (ind.ref) {
|
|
150
|
-
nodes.push(ind.ref);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
if (geometry.length > 0) {
|
|
154
|
-
member.geometry = geometry;
|
|
155
|
-
}
|
|
156
|
-
else if (nodes.length > 0) {
|
|
157
|
-
member.nodes = nodes;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
relation.addMember(member);
|
|
161
|
-
});
|
|
162
|
-
xmlParser.on('</osm.relation.bounds>', (node, parent) => {
|
|
163
|
-
refElements.get(`relation/${parent === null || parent === void 0 ? void 0 : parent.id}`).setBounds([parseFloat(node.minlon), parseFloat(node.minlat), parseFloat(node.maxlon), parseFloat(node.maxlat)]);
|
|
164
|
-
});
|
|
165
|
-
xmlParser.on('</osm.relation.tag>', (node, parent) => {
|
|
166
|
-
refElements.get(`relation/${parent === null || parent === void 0 ? void 0 : parent.id}`).addTag(node.k, node.v);
|
|
167
|
-
});
|
|
168
|
-
xmlParser.parse(o);
|
|
169
|
-
};
|
|
170
|
-
if (format === 'json-raw') {
|
|
171
|
-
osm = JSON.parse(osm);
|
|
172
|
-
if (osm.elements) {
|
|
173
|
-
format = 'json';
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
format = 'invalid';
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
if (format === 'json') {
|
|
180
|
-
analyzeFeaturesFromJson(osm);
|
|
181
|
-
}
|
|
182
|
-
else if (format === 'xml') {
|
|
183
|
-
analyzeFeaturesFromXml(osm);
|
|
184
|
-
}
|
|
185
|
-
refElements.bindAll();
|
|
186
|
-
for (const v of refElements.values()) {
|
|
187
|
-
if (v.refCount <= 0 || (v.hasTag && renderTagged && !(v instanceof osmobjs_1.Way && excludeWay))) {
|
|
188
|
-
const features = v.toFeatureArray();
|
|
189
|
-
// return the first geometry of the first relation element
|
|
190
|
-
if (v instanceof osmobjs_1.Relation && !completeFeature && features.length > 0) {
|
|
191
|
-
return features[0].geometry;
|
|
192
|
-
}
|
|
193
|
-
featureArray = featureArray.concat(features);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return { type: 'FeatureCollection', features: featureArray };
|
|
197
|
-
}
|
|
198
|
-
;
|
|
199
|
-
module.exports = osm2geojson;
|
package/dist/node/osmobjs.d.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { Feature } from 'geojson';
|
|
2
|
-
import { RefElements } from './utils';
|
|
3
|
-
declare class OsmObject {
|
|
4
|
-
refCount: number;
|
|
5
|
-
protected refElems: RefElements;
|
|
6
|
-
private type;
|
|
7
|
-
private id;
|
|
8
|
-
private tags;
|
|
9
|
-
private props;
|
|
10
|
-
private hasTag;
|
|
11
|
-
constructor(type: string, id: string, refElems: RefElements);
|
|
12
|
-
addTags(tags: {
|
|
13
|
-
[k: string]: string;
|
|
14
|
-
}): void;
|
|
15
|
-
addTag(k: string, v: string): void;
|
|
16
|
-
addProp(k: string, v: any): void;
|
|
17
|
-
addProps(props: {
|
|
18
|
-
[k: string]: string;
|
|
19
|
-
}): void;
|
|
20
|
-
getCompositeId(): string;
|
|
21
|
-
getProps(): {
|
|
22
|
-
[k: string]: string;
|
|
23
|
-
};
|
|
24
|
-
toFeatureArray(): Array<Feature<any, any>>;
|
|
25
|
-
}
|
|
26
|
-
export declare class Node extends OsmObject {
|
|
27
|
-
private latLng;
|
|
28
|
-
constructor(id: string, refElems: RefElements);
|
|
29
|
-
setLatLng(latLng: {
|
|
30
|
-
lat: string;
|
|
31
|
-
lon: string;
|
|
32
|
-
}): void;
|
|
33
|
-
toFeatureArray(): Array<Feature<any, any>>;
|
|
34
|
-
getLatLng(): {
|
|
35
|
-
lat: string;
|
|
36
|
-
lon: string;
|
|
37
|
-
} | null;
|
|
38
|
-
}
|
|
39
|
-
export declare class Way extends OsmObject {
|
|
40
|
-
private latLngArray;
|
|
41
|
-
private isPolygon;
|
|
42
|
-
constructor(id: string, refElems: RefElements);
|
|
43
|
-
addLatLng(latLng: {
|
|
44
|
-
lat: string;
|
|
45
|
-
lon: string;
|
|
46
|
-
}): void;
|
|
47
|
-
setLatLngArray(latLngArray: Array<{
|
|
48
|
-
lat: string;
|
|
49
|
-
lon: string;
|
|
50
|
-
[k: string]: any;
|
|
51
|
-
}>): void;
|
|
52
|
-
addNodeRef(ref: string): void;
|
|
53
|
-
addTags(tags: {
|
|
54
|
-
[k: string]: string;
|
|
55
|
-
}): void;
|
|
56
|
-
addTag(k: string, v: string): void;
|
|
57
|
-
toCoordsArray(): string[][];
|
|
58
|
-
toFeatureArray(): Array<Feature<any, any>>;
|
|
59
|
-
private analyzeTag;
|
|
60
|
-
}
|
|
61
|
-
export declare class Relation extends OsmObject {
|
|
62
|
-
private relations;
|
|
63
|
-
private nodes;
|
|
64
|
-
private bounds;
|
|
65
|
-
[k: string]: any;
|
|
66
|
-
constructor(id: string, refElems: RefElements);
|
|
67
|
-
setBounds(bounds: any[]): void;
|
|
68
|
-
addMember(member: {
|
|
69
|
-
[k: string]: any;
|
|
70
|
-
}): void;
|
|
71
|
-
toFeatureArray(): Array<Feature<any, any>>;
|
|
72
|
-
}
|
|
73
|
-
export {};
|