├── .gitignore
├── README.md
├── app.js
├── public
├── google_point_8.png
├── index.html
└── map.js
├── run.sh
└── server
├── app.js
├── settings.js
└── styles
├── line.xml
├── point.png
├── point.xml
├── point_fast.xml
├── polygon.xml
└── text.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | .notes.txt
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Coalition
2 |
3 | An illustrative web server that combines nodejs, mapnik, and postgis.
4 |
5 |
6 | ## Depends
7 |
8 | NodeJS > 0.2.4
9 |
10 | Mapnik (latest trunk >r2397)
11 |
12 | Node-mapnik
13 |
14 | Npm / Spark
15 |
16 |
17 | ## Installation
18 |
19 | Install node:
20 |
21 | $ wget http://nodejs.org/dist/node-v0.4.0.tar.gz
22 | $ tar xvf node-v0.4.0.tar.gz
23 | $ ./configure
24 | $ make
25 | $ make install
26 |
27 | Install node-mapnik:
28 |
29 | $ git clone git://github.com/mapnik/node-mapnik.git
30 | $ cd node-mapnik
31 | $ ./configure
32 | $ make
33 | $ make install
34 |
35 | Install npm (node package manager)
36 |
37 | $ curl http://npmjs.org/install.sh | sh
38 |
39 | Install spark via npm:
40 |
41 | $ npm install spark
42 |
43 |
44 | ## Configuration
45 |
46 | Edit the postgis settings in 'server/settings.js' to match your system.
47 |
48 | Also, fixup the few hardcoded sample queries in 'public/index.html' to match your postgis tables.
49 |
50 |
51 | ## Usage
52 |
53 |
54 | Start the server by typing:
55 |
56 | $ ./run.sh
57 |
58 | Or:
59 |
60 | $ spark
61 |
62 | Then visit http://localhost:3000/. Choose a style type and a postgis subquery.
63 |
64 |
65 | ## A note on styles
66 |
67 | Mapnik supports applying arbitrary styles to layers, but for the results
68 | to be reasonable you have to apply reasonable styles. For example a PointSymbolizer
69 | will work against either point geometries or polygon geometries, but a PolygonSymbolizer
70 | will not render anything if applied to point geometries.
71 |
72 |
73 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./server/app').server;
2 |
--------------------------------------------------------------------------------
/public/google_point_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/springmeyer/coalition/c4bdcf228b8732382e80f90e160f4aec1b3b5e30/public/google_point_8.png
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
26 |
27 |
28 |
29 |
30 |
31 |
Demo of sending arbitrary SQL and Styles to Mapnik for dynamic tile generation
32 |
33 |
34 |
35 | Style:
36 |
41 |
42 |
43 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/public/map.js:
--------------------------------------------------------------------------------
1 | var po = org.polymaps;
2 |
3 | var map = po.map()
4 | .container(document.getElementById('map').appendChild(po.svg('svg')))
5 | .center({lat: 0, lon: 0})
6 | .zoom(1)
7 | .zoomRange([1, 20])
8 | .add(po.drag())
9 | .add(po.wheel())
10 | .add(po.dblclick())
11 | .add(po.hash());
12 |
13 | // mapquest's mapnik tiles
14 |
15 | map.add(po.image()
16 | .url(po.url('http://otile{S}.mqcdn.com/tiles/1.0.0/osm/'
17 | + '{Z}/{X}/{Y}.png')
18 | .hosts(['1', '2', '3', '4'])));
19 |
20 |
21 | var tile_url = '?x={X}&y={Y}&z={Z}';
22 |
23 | // local tile server
24 | var layer = po.image()
25 | .url(po.url(tile_url + '&sql=points9&style=point'));
26 |
27 | map.add(layer);
28 |
29 |
30 | var setVal = function(value)
31 | {
32 | document.getElementById('q').value = value;
33 | update_tiles();
34 | }
35 |
36 | var update_tiles = function() {
37 | var style = 'point';
38 | var sql = document.getElementById('q').value;
39 | if (!sql)
40 | sql = 'points9';
41 | if (document.forms[0][0].checked)
42 | style = 'point';
43 | if (document.forms[0][1].checked)
44 | style = 'polygon';
45 | if (document.forms[0][2].checked)
46 | style = 'line';
47 | layer.url(po.url(tile_url + '&sql=' + escape(sql) + '&style=' + style))
48 | .reload();
49 | console.log(sql);
50 | };
51 |
--------------------------------------------------------------------------------
/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # https://github.com/senchalabs/spark
4 | spark -p 3000 -n `sysctl hw.ncpu | awk '{print $2}'`
--------------------------------------------------------------------------------
/server/app.js:
--------------------------------------------------------------------------------
1 | var mapnik = require('mapnik')
2 | , mercator = require('mapnik/sphericalmercator')
3 | , http = require('http')
4 | , url = require('url')
5 | , fs = require('fs')
6 | , path = require('path')
7 | , settings = require('./settings');
8 |
9 | function isEmpty(obj) {
10 | for(var prop in obj) {
11 | if(obj.hasOwnProperty(prop))
12 | return false;
13 | }
14 | return true;
15 | }
16 |
17 | module.exports.server = http.createServer(function(req, res) {
18 |
19 | var query = url.parse(req.url.toLowerCase(), true).query;
20 |
21 | res.writeHead(500, {
22 | 'Content-Type': 'text/plain'
23 | });
24 |
25 | if (!query || isEmpty(query)) {
26 | try {
27 | res.writeHead(200, {
28 | 'Content-Type': 'text/html'
29 | });
30 | if (req.url == '/') {
31 | res.end(fs.readFileSync('./public/index.html'));
32 | } else {
33 | res.end(fs.readFileSync('./public/' + req.url));
34 | }
35 | } catch (err) {
36 | res.end('Not found: ' + req.url);
37 | }
38 | } else {
39 |
40 | if (query &&
41 | query.x !== undefined &&
42 | query.y !== undefined &&
43 | query.z !== undefined &&
44 | query.sql !== undefined &&
45 | query.style !== undefined
46 | ) {
47 |
48 | var bbox = mercator.xyz_to_envelope(parseInt(query.x),
49 | parseInt(query.y),
50 | parseInt(query.z), false);
51 | var map = new mapnik.Map(256, 256, mercator.srs);
52 | map.buffer_size(50);
53 | var layer = new mapnik.Layer('tile', mercator.srs);
54 | try {
55 | settings.postgis.table = unescape(query.sql);
56 | var postgis = new mapnik.Datasource(settings.postgis);
57 | layer.datasource = postgis;
58 | styles = [query.style];
59 | map.load(path.join(settings.styles, query.style + '.xml'));
60 | // labels
61 | styles.push('text');
62 | map.load(path.join(settings.styles, 'text.xml'));
63 | layer.styles = styles;
64 | map.add_layer(layer);
65 | // show map in terminal with toString()
66 | //console.log(map.toString());
67 | }
68 | catch (err) {
69 | res.end(err.message);
70 | }
71 |
72 | map.render(bbox, 'png', function(err, buffer) {
73 | if (err) {
74 | res.end(err.message);
75 | } else {
76 | //console.log(map.scaleDenominator());
77 | res.writeHead(200, {
78 | 'Content-Type': 'image/png'
79 | });
80 | res.end(buffer);
81 | }
82 | });
83 | } else {
84 | res.end('missing x, y, z, sql, or style parameter');
85 | }
86 | }
87 | });
88 |
--------------------------------------------------------------------------------
/server/settings.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | module.exports.styles = path.join(__dirname,'styles');
4 |
5 | module.exports.postgis = {
6 | 'dbname' : 'tiledb',
7 | 'extent' : '-20005048.4188,-9039211.13765,19907487.2779,17096598.5401',
8 | 'geometry_field' : 'the_geom',
9 | 'srid' : 900913,
10 | 'user' : 'postgres',
11 | 'max_size' : 1,
12 | 'type' : 'postgis'
13 | };
14 |
15 |
16 |
--------------------------------------------------------------------------------
/server/styles/line.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/styles/point.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/springmeyer/coalition/c4bdcf228b8732382e80f90e160f4aec1b3b5e30/server/styles/point.png
--------------------------------------------------------------------------------
/server/styles/point.xml:
--------------------------------------------------------------------------------
1 |
2 | 250000000000">
4 | 500000000">
5 | 200000000">
6 | 200000000">
7 | 100000000">
8 | 100000000">
9 | 50000000">
10 | 50000000">
11 | 25000000">
12 | 25000000">
13 | 12500000">
14 | 12500000">
15 | 6500000">
16 | 6500000">
17 | 3000000">
18 | 3000000">
19 | 1500000">
20 | 1500000">
21 | 750000">
22 | 750000">
23 | 400000">
24 | 400000">
25 | 200000">
26 | 200000">
27 | 100000">
28 | 100000">
29 | 50000">
30 | 50000">
31 | 25000">
32 | 25000">
33 | 12500">
34 | 12500">
35 | 5000">
36 | 5000">
37 | 2500">
38 | 2500">
39 | 1000">
40 | 1">
41 | ]>
42 |
--------------------------------------------------------------------------------
/server/styles/point_fast.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/styles/polygon.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/styles/text.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------