Skip to content

Commit 3887f67

Browse files
author
Martin Ždila
committed
initial import
0 parents  commit 3887f67

File tree

5 files changed

+235
-0
lines changed

5 files changed

+235
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

README.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# JsNik
2+
3+
JsNik is node library for generating Mapnik configuration in JS. This adds all the benefits of scripting like preventing repetition, programatic style generation, etc.
4+
5+
## Installation
6+
7+
```
8+
npm install jsnik
9+
```
10+
11+
## Example
12+
13+
TODO

package-lock.json

+13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "jsnik",
3+
"version": "1.0.0",
4+
"description": "Library for generating Mapnik configuration in JS",
5+
"main": "src/index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "TODO"
12+
},
13+
"keywords": [
14+
"mapnik"
15+
],
16+
"author": "Martin Ždila <[email protected]>",
17+
"license": "ISC",
18+
"dependencies": {
19+
"xmlbuilder": "10.1.1"
20+
}
21+
}

src/index.js

+187
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
const builder = require('xmlbuilder');
2+
3+
function sanitizeAtts(obj) {
4+
const res = {};
5+
Object.keys(obj).filter(key => obj[key] !== undefined).forEach((key) => {
6+
res[key.replace(/[A-Z]/g, (x) => '-' + x.toLowerCase())] = obj[key];
7+
});
8+
return res;
9+
}
10+
11+
function sanitizeLayerAtts(obj) {
12+
const atts = { ...obj };
13+
if ('minZoom' in atts) {
14+
atts.maximumScaleDenominator = zoomDenoms[atts.minZoom];
15+
delete atts.minZoom;
16+
}
17+
if ('maxZoom' in atts) {
18+
atts.minimumScaleDenominator = zoomDenoms[atts.maxZoom + 1];
19+
delete atts.maxZoom;
20+
}
21+
22+
return sanitizeAtts(atts);
23+
}
24+
25+
const zoomDenoms = [
26+
1000000000,
27+
500000000,
28+
200000000,
29+
100000000,
30+
50000000,
31+
25000000,
32+
12500000,
33+
6500000,
34+
3000000,
35+
1500000,
36+
750000, // 10
37+
400000,
38+
200000,
39+
100000,
40+
50000,
41+
25000,
42+
12500,
43+
5000,
44+
2500,
45+
1500,
46+
750, // 20
47+
500,
48+
250,
49+
100,
50+
50,
51+
25,
52+
12.5,
53+
];
54+
55+
function createMap(atts, { dbParams } = {}) {
56+
const mapEle = builder.begin().ele('Map', sanitizeAtts(atts));
57+
58+
if (dbParams) {
59+
const dsEle = mapEle.ele('Datasource', { name: 'db' });
60+
Object.keys(dbParams).forEach((name) => {
61+
dsEle.ele('Parameter', { name }, dbParams[name]);
62+
});
63+
}
64+
65+
const map = {
66+
doInMap(cb) {
67+
cb(map);
68+
return map;
69+
},
70+
style(name, atts = {}) {
71+
const styleEle = mapEle.ele('Style', { name, ...sanitizeAtts(atts) });
72+
const s = {
73+
doInStyle(cb) {
74+
cb(s);
75+
return s;
76+
},
77+
rule({ filter, maxZoom, minZoom } = {}) {
78+
const ruleEle = styleEle.ele('Rule');
79+
if (filter) {
80+
ruleEle.ele('Filter', {}, filter);
81+
}
82+
if (typeof maxZoom === 'number') {
83+
if (zoomDenoms[maxZoom + 1]) {
84+
ruleEle.ele('MinScaleDenominator', {}, zoomDenoms[maxZoom + 1]);
85+
} else {
86+
throw new Error(`Unsupported zoom ${maxZoom + 1}`);
87+
}
88+
}
89+
if (typeof minZoom === 'number') {
90+
if (zoomDenoms[minZoom]) {
91+
ruleEle.ele('MaxScaleDenominator', {}, zoomDenoms[minZoom]);
92+
} else {
93+
throw new Error(`Unsupported zoom ${minZoom}`);
94+
}
95+
}
96+
const ascendents = { style: map.style, map };
97+
const rule = {
98+
doInRule(cb) {
99+
cb(map);
100+
return map;
101+
},
102+
filter(filter) {
103+
const filterEle = ruleEle.ele('Filter', {}, filter);
104+
return { filterEle, ...rule, ...ascendents };
105+
},
106+
polygonSymbolizer(atts = {}) {
107+
const polygonSymbolizerEle = ruleEle.ele('PolygonSymbolizer', sanitizeAtts(atts));
108+
return { polygonSymbolizerEle, ...rule, ...ascendents };
109+
},
110+
polygonPatternSymbolizer(atts = {}) {
111+
const polygonPatternSymbolizerEle = ruleEle.ele('PolygonPatternSymbolizer', sanitizeAtts(atts));
112+
return { polygonPatternSymbolizerEle, ...rule, ...ascendents };
113+
},
114+
lineSymbolizer(atts = {}) {
115+
const lineSymbolizerEle = ruleEle.ele('LineSymbolizer', sanitizeAtts(atts));
116+
return { lineSymbolizerEle, ...rule, ...ascendents };
117+
},
118+
linePatternSymbolizer(atts = {}) {
119+
const linePatternSymbolizerEle = ruleEle.ele('LinePatternSymbolizer', sanitizeAtts(atts));
120+
return { linePatternSymbolizerEle, ...rule, ...ascendents };
121+
},
122+
markersSymbolizer(atts = {}) {
123+
const markersSymbolizerEle = ruleEle.ele('MarkersSymbolizer', sanitizeAtts(atts));
124+
return { markersSymbolizerEle, ...rule, ...ascendents };
125+
},
126+
textSymbolizer(atts = {}, text) {
127+
const textSymbolizerEle = ruleEle.ele('TextSymbolizer', sanitizeAtts(atts), text);
128+
return { textSymbolizerEle, ...rule, ...ascendents };
129+
},
130+
rasterSymbolizer(atts = {}) {
131+
const rasterSymbolizerEle = ruleEle.ele('RasterSymbolizer', sanitizeAtts(atts));
132+
return { rasterSymbolizerEle, ...rule, ...ascendents };
133+
},
134+
shieldSymbolizer(atts = {}) {
135+
const shieldSymbolizerEle = ruleEle.ele('ShieldSymbolizer', sanitizeAtts(atts));
136+
return { shieldSymbolizerEle, ...rule, ...ascendents };
137+
},
138+
139+
borderedPolygonSymbolizer(color) {
140+
const polygonSymbolizerEle = ruleEle.ele('PolygonSymbolizer', sanitizeAtts({ fill: color }));
141+
const lineSymbolizerEle = ruleEle.ele('LineSymbolizer', sanitizeAtts({ stroke: color, strokeWidth: 1 }));
142+
return { polygonSymbolizerEle, lineSymbolizerEle, ...rule, ...ascendents };
143+
},
144+
ruleEle,
145+
...s,
146+
};
147+
return rule;
148+
},
149+
styleEle,
150+
...map,
151+
};
152+
return s;
153+
},
154+
sqlLayer(styleName, sql, atts = {}) {
155+
const layerEle = mapEle.ele('Layer', sanitizeLayerAtts(atts));
156+
for (const sn of Array.isArray(styleName) ? styleName : [styleName]) {
157+
layerEle.ele('StyleName', {}, sn);
158+
}
159+
layerEle.ele('Datasource', { base: 'db' })
160+
.ele('Parameter', { name: 'table' }, `(${sql}) as foo`);
161+
return this;
162+
},
163+
layer(styleName, dsParams, atts = {}) {
164+
const layerEle = mapEle.ele('Layer', sanitizeLayerAtts(atts));
165+
for (const sn of Array.isArray(styleName) ? styleName : [styleName]) {
166+
layerEle.ele('StyleName', {}, sn);
167+
}
168+
const dsEle = layerEle.ele('Datasource');
169+
Object.keys(dsParams).forEach((name) => {
170+
dsEle.ele('Parameter', { name }, dsParams[name]);
171+
});
172+
return this;
173+
},
174+
mapEle,
175+
stringify(formattingOptions = { pretty: true }) {
176+
return mapEle.end(formattingOptions);
177+
},
178+
};
179+
180+
return map;
181+
}
182+
183+
module.exports = {
184+
sanitizeAtts,
185+
createMap,
186+
zoomDenoms,
187+
};

0 commit comments

Comments
 (0)