Skip to content

Commit bb56983

Browse files
committed
init to new repo
0 parents  commit bb56983

File tree

79 files changed

+284365
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+284365
-0
lines changed

.gitignore

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

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2016 Keith Collins, Quartz
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+224
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
# Mapquery by Quartz
2+
Mapquery 0.0.1 is a proof-of-concept prototype release. All of the work on the project leading to this initial release was funded by the [Knight Foundation's Prototype Fund](http://www.knightfoundation.org/funding-initiatives/knight-prototype-fund/).
3+
4+
Mapquery is a map data storage and retrieval API build on [Express](https://github.com/expressjs/express) and [PostGIS](http://postgis.net/).
5+
6+
## Installation
7+
8+
- Install node modules `$ npm install`
9+
- Install Postgres `$ brew install postgresql`
10+
- Install PostGIS `$ brew install postgis`
11+
- Start Postgres server `$ pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start`
12+
- Create a new local Postgres database called `mapquery`. You can run `createdb mapquery` on the command line, or download [pgadmin](http://www.pgadmin.org/download/) and use the GUI. Set your local username as the owner.
13+
- Run this on the command line to enable PostGIS:
14+
```
15+
psql -q map_library -c "
16+
-- Enable PostGIS (includes raster)
17+
CREATE EXTENSION postgis;
18+
-- Enable Topology
19+
CREATE EXTENSION postgis_topology;
20+
-- fuzzy matching needed for Tiger
21+
CREATE EXTENSION fuzzystrmatch;
22+
-- Enable US Tiger Geocoder
23+
CREATE EXTENSION postgis_tiger_geocoder;
24+
"
25+
```
26+
Or if you prefer to use pgAdmin: Click on the SQL button at the top of pgAdmin. That'll open a SQL query window. Pate in the above code, excluding the top line, and click the green Run button.
27+
28+
- Download the Mapquery starter pack database dump from [here](https://s3.amazonaws.com/qz-files/mapquery.dump)
29+
- Restore the dump file to your database `$ pg_restore --verbose --clean --no-acl --no-owner -h localhost -U YOUR_LOCAL_USERNAME -d mapquery /PATH/TO/mapquery.dump`
30+
- In `mapquery/settings.js`, update the database connection settings to match your own:
31+
```js
32+
module.exports = {
33+
'd': 'mapquery', // database name
34+
'u': 'username', //username
35+
'p': '', //password
36+
'h': 'localhost', //host
37+
'port': '5432' // port
38+
};
39+
```
40+
- Start the app with `npm start`
41+
- [localhost:3000](http://localhost:3000/) will load the view from `views/index.jade`
42+
43+
Note: When you make changes to your database that you want to sync on other computers, dump it with this command:
44+
45+
`pg_dump -Fc --no-acl --no-owner -h localhost -U YOUR_LOCAL_USERNAME mapquery > mapquery.dump`
46+
47+
Then restore with `pg_restore`, as shown above.
48+
49+
## Running Mapquery
50+
51+
To run Mapquery:
52+
53+
- Start Postgres server `$ pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start`
54+
- Start the app with `npm start`
55+
- Go to [localhost:3000](http://localhost:3000/) in your web browser to use the Mapquery interface.
56+
57+
We are not yet running Mapquery in production. We'll be updating this readme with information as we begin to implement a production version of the app. If you do your own production implementation, please let us know how it goes!
58+
59+
### A note on importing
60+
61+
Importing is currently handled through the Mapquery interface. The routes `/import/import-map` and `/import/save-map-data` import a shapefile to the database and save metadata to `mqmeta`, respectively, but they do not send a json response. Instead, they render information to `views/import.jade`. Our current plan is to implement `POST` endpoints for importing shapefile data if we find that we need that functionality.
62+
63+
## API endpoint reference
64+
65+
Route definitions can be found in `routes/index.js`; handlers are in `/queries.js`.
66+
67+
### /api/feature-collection
68+
69+
Returns a Geojson or Topojson representation of a `FeatureCollection`, along with metadata about the map. This endpoint is currently the most fully-featured, because the `FeatureCollection` format allows for simple dynamic sizing and positioning.
70+
71+
| Parameter | Required | Description |
72+
| -------------------- |:------------------------:|:-------------|
73+
| `table` | Yes | Must be the valid name of a table in your Postgres database
74+
| `field_value` | No (Default: All units) | Table field and value separated by a `:`. Must be a valid field name and value from the selected table. Example: "continent:Europe".
75+
| `width` | Yes | The width of the viewport of the resulting map
76+
| `height` | Yes | The height of the viewport of the resulting map
77+
| `proj` | Yes | Must be the valid name of any projection supported by [d3.geo](https://github.com/mbostock/d3/wiki/Geo-Projections) or d3's [extended projections plugin](https://github.com/d3/d3-geo-projection/). Example: "albersUsa".
78+
| `datatype` | No (Default: "topojson") | "topojson" or "geojson"
79+
80+
**Example result**
81+
82+
Request: `/api/feature-collection?table=ne_50m_admin_0_countries&proj=kavrayskiy7&width=940&height=500`
83+
84+
Result:
85+
86+
```
87+
{
88+
"status":"success",
89+
"message":"Retrieved FeatureCollection with projection data",
90+
"data":{
91+
"table_metadata":
92+
{
93+
"table_id":20,
94+
"table_last_updated":"2016-04-01T16:36:11.983Z",
95+
"table_name":"ne_50m_admin_0_countries",
96+
"table_name_readable":"Countries",
97+
"table_description":null,
98+
"table_category":"Countries",
99+
"table_resolution":"1:50m",
100+
"table_source":"Natural Earth",
101+
"table_source_url":"http://www.naturalearthdata.com/downloads/50m-cultural-vectors/",
102+
"fld_iso_alpha_3":"iso_a3",
103+
"fld_name":"name",
104+
"fld_groupby1":"continent",
105+
"fld_groupby2":"subregion",
106+
"fld_groupby3":null,
107+
"fld_groupby4":null,
108+
"fld_groupby5":null,
109+
"fld_identifier":"iso_a3"
110+
},
111+
"bounds":[[-2.68763343988672,-1.4590884304298841],[2.68763343988672,1.5707775819587302]],
112+
"scale":148.52141915187846,
113+
"translate":[470,241.7058843555333],
114+
"projection":"kavrayskiy7",
115+
"map":{
116+
"type":"Topology",
117+
"objects":{
118+
"type":"FeatureCollection",
119+
"features": [ARRAY OF FEATURES...]
120+
}
121+
}
122+
}
123+
}
124+
```
125+
126+
### /api/geometry-collection
127+
128+
Returns a Geojson or Topojson representation of the specified geometry. This endpoint is currently fairly limited, as it does not provide any dynamic sizing or positioning, and we recommend using `api/feature-collection` instead.
129+
130+
| Parameter | Required | Description |
131+
| -------------------- |:------------------------:|:-------------|
132+
| `table` | Yes | Must be the valid name of a table in your Postgres database
133+
| `field_value` | No (Default: All units) | Table field and value separated by a `:`. Must be a valid field name and value from the selected table. Example: "continent:Europe".
134+
| `datatype` | No (Default: "topojson") | "topojson" or "geojson"
135+
136+
**Example result**
137+
138+
Request: `/api/geometry-collection?table=ne_50m_admin_0_countries&field_value=continent:Europe&proj=mercator&datatype=topojson`
139+
140+
Result:
141+
142+
```
143+
{
144+
"status":"success",
145+
"message":"Retrieved geometry",
146+
"data":{
147+
"type":"Topology",
148+
"objects":[
149+
{
150+
"name":"Andorra",
151+
"gid":7,
152+
"geometry":"{
153+
"type":"MultiPolygon",
154+
"coordinates":[ARRAY OF COORDINATES...]
155+
}
156+
},
157+
{
158+
MORE OBJECTS...
159+
}
160+
]
161+
}
162+
}
163+
```
164+
165+
### /api/table-data
166+
167+
Returns all of the data from the `mqmeta` table, which is metadata about all of the maps you've imported into Mapquery.
168+
169+
_No parameters are required (or accepted)._
170+
171+
**Example result**
172+
173+
Request: `/api/table-data`
174+
175+
Result:
176+
177+
```
178+
{
179+
"data":[
180+
{
181+
"table_id":10,
182+
"table_last_updated":"2016-02-16T22:11:10.929Z",
183+
"table_name":"ne_10m_admin_0_countries",
184+
"table_name_readable":"Countries",
185+
"table_description":"There are 247 countries in the world. Greenland as separate from Denmark. Most users will want this file instead of sovereign states.",
186+
"table_category":"Countries",
187+
"table_resolution":"1:10m",
188+
"table_source":"Natural Earth",
189+
"table_source_url":"http://www.naturalearthdata.com/downloads/10m-cultural-vectors/10m-admin-0-countries/",
190+
"fld_iso_alpha_3":"iso_a3",
191+
"fld_name":"name",
192+
"fld_groupby1":"continent",
193+
"fld_groupby2":"subregion",
194+
"fld_groupby3":null,
195+
"fld_groupby4":null,
196+
"fld_groupby5":null,
197+
"fld_identifier":"iso_a3"
198+
},
199+
{ETC...}
200+
]
201+
}
202+
```
203+
204+
### /api/units-by-table
205+
206+
When you import a shapefile to Mapquery through its front-end interface, you're asked which fields in the map data you'd like to group by. Those field names are recorded in the `mqmeta` table (see above). For example, if you're importing countries from a Natural Earth shapefile, you may select the `continent` and `subregion` columns as your group-by fields. You can then see all of the unique values in those fields by calling this endpoint, as well as all of the values in the table's `name` field.
207+
208+
| Parameter | Required | Description |
209+
| -------------------- |:------------------------:|:-------------|
210+
| `table` | Yes | Must be the valid name of a table in your Postgres database
211+
212+
**Example result**
213+
214+
Request: `/api/units-by-table?table=ne_50m_admin_0_countries`
215+
216+
Result:
217+
218+
```
219+
{
220+
"continent":["North America","Asia","Europe","Africa","South America","Oceania","Antarctica","Seven seas (open ocean)"],
221+
"subregion":["Caribbean","Southern Asia","Southern Europe","Western Asia","Middle Africa","Northern Europe","South America","Polynesia","Antarctica","Australia and New Zealand","Seven seas (open ocean)","Western Europe","Eastern Africa","Western Africa","Eastern Europe","Central America","Northern America","Southern Africa","South-Eastern Asia","Eastern Asia","Central Asia","Northern Africa","Melanesia","Micronesia"],
222+
"name":[ALL COUNTRIES...]
223+
}
224+
```

app.js

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
var express = require('express');
2+
var path = require('path');
3+
var favicon = require('serve-favicon');
4+
var logger = require('morgan');
5+
var cookieParser = require('cookie-parser');
6+
var bodyParser = require('body-parser');
7+
8+
var routes = require('./routes/index');
9+
10+
var app = express();
11+
12+
// view engine setup
13+
app.set('views', path.join(__dirname, 'views'));
14+
app.set('view engine', 'jade');
15+
16+
// uncomment after placing your favicon in /public
17+
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
18+
app.use(logger('dev'));
19+
app.use(bodyParser.json());
20+
app.use(bodyParser.urlencoded({ extended: false }));
21+
app.use(cookieParser());
22+
app.use(express.static(path.join(__dirname, 'public')));
23+
24+
app.use('/', routes);
25+
26+
// catch 404 and forward to error handler
27+
app.use(function(req, res, next) {
28+
var err = new Error('Not Found');
29+
err.status = 404;
30+
next(err);
31+
});
32+
33+
// error handlers
34+
35+
// development error handler
36+
// will print stacktrace
37+
if (app.get('env') === 'development') {
38+
app.use(function(err, req, res, next) {
39+
res.status( err.code || 500 )
40+
.json({
41+
status: 'error',
42+
message: err.message,
43+
error: err
44+
});
45+
});
46+
}
47+
48+
// production error handler
49+
// no stacktraces leaked to user
50+
app.use(function(err, req, res, next) {
51+
res.status(err.status || 500)
52+
.json({
53+
status: 'error',
54+
message: err.message,
55+
error: {}
56+
});
57+
});
58+
59+
// // development error handler
60+
// // will print stacktrace
61+
// if (app.get('env') === 'development') {
62+
// app.use(function(err, req, res, next) {
63+
// res.status(err.status || 500);
64+
// res.render('error', {
65+
// message: err.message,
66+
// error: err
67+
// });
68+
// });
69+
// }
70+
71+
// // production error handler
72+
// // no stacktraces leaked to user
73+
// app.use(function(err, req, res, next) {
74+
// res.status(err.status || 500);
75+
// res.render('error', {
76+
// message: err.message,
77+
// error: {}
78+
// });
79+
// });
80+
81+
module.exports = app;

bin/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.DS_Store

0 commit comments

Comments
 (0)