1.サーバーサイド - Kazunori-Kimura/express-gis GitHub Wiki
Server side
2つの機能を提供します。
- ブラウザで表示するhtml,css,javascriptを返す
- 行政区域、小学校、校区の情報をJSON形式で返す REST API
データの参照のみ、更新機能は実装していません。
REST API
GET /areas
: 全ての行政区域情報を取得する。
GET /areas/:code
: code(JIS5)を元に行政区域情報を取得する。
GET /areas/:code/schools
: codeの行政区域内にある全ての小学校を取得する。
GET /areas/:code/districts
: codeの行政区域内にある全ての小学校区を取得する。
コード詳細
要点をかいつまんで、ソースコードの中身を解説します。
app.js
// app.js
var express = require('express'),
bodyParser = require('body-parser'),
app = express();
// load environment data
var env = require('./env.json');
// route
var area = require('./routes/area.js'),
school = require('./routes/school.js'),
district = require('./routes/district.js');
必要なモジュール、設定、REST APIから呼ばれるメソッドを読み込みます。
/
(ルート)へのリクエストの対応
// view
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
// serve static files
app.use(express.static(__dirname + '/bower_components'));
app.use(express.static(__dirname + '/public'));
app.get('/', function(req, res){
res.render('index', { title: 'GeoTest', key: env.api_key });
});
/
(ルート) へのリクエストがあった場合は views/index.ejs
を返します。
クライアントサイドの機能はすべて views/index.ejs
, public/js/index.js
にまとまっています。
REST APIへのリクエストの対応
// area 行政区域
app.get('/areas', area.findAll);
app.get('/areas/:code', area.find);
// school 小学校
app.get('/areas/:code/schools', school.find);
// district 校区
app.get('/areas/:code/districts', district.find);
リクエストされたurl
と route
のメソッドを紐付けています。
app.listen(3000);
Port:3000で待ち受けます。
routes/area.js
// routes/area.js
var pg = require('pg'),
here = require('here').here;
// load environment data
var env = require('../env.json');
var cs = env.connection_string;
モジュールと設定の読み込みです。
findAll
登録されている全ての行政区域情報を取得しています。
module.exports = {
// findAll
findAll: function(req, res){
// 市区町村を取得
var sql = here(/*
select
n03_007 as code
, n03_001 || coalesce(n03_003, '') || coalesce(n03_004, '') as city
from
"n03-13_27_130401"
union
select
n03_007 as code
, n03_001 || coalesce(n03_003, '') || coalesce(n03_004, '') as city
from
"n03-13_28_130401"
order by
code
*/).valueOf();
// postgres接続
pg.connect(cs, function(err, client){
if(err){
// connection error
}else{
// sql実行
client.query(sql, function(err, result){
console.log('row count= %d', result.rows.length);
client.end();
res.send(result.rows);
});
}
});
},
川や島などの関係で、ひとつの行政区域が複数のレコードで構成されている場合があるため、
union
で結合して重複をなくしています。
find
まず、リクエストから取得したcode
を元に、行政区域情報を取得します。
つづいて、該当の行政区域の空間データを結合し、GeoJSON
型に変換しています。
Google Maps APIはGeoJSON
が容易に表示出来ます。
GeoJSON
の詳細については http://geojson.org/ を参照してください。
find: function(req, res){
console.log('area#find( code= %s )', req.params.code);
// 市区町村を取得
var sqlCity = here(/*
select
n03_007 as code
, n03_001 || coalesce(n03_003, '') || coalesce(n03_004, '') as city
from
"n03-13_27_130401"
where
n03_007 = $1
union
select
n03_007 as code
, n03_001 || coalesce(n03_003, '') || coalesce(n03_004, '') as city
from
"n03-13_28_130401"
where
n03_007 = $1
limit
1
*/).valueOf();
// polygonを取得
var sqlPolygon = here(/*
select
n03_007 as code
, ST_AsGeoJSON(ST_Centroid(ST_Union(geom))) as center
, ST_AsGeoJSON(ST_Union(geom)) as geojson
from
"n03-13_27_130401"
where
n03_007 = $1
group by
n03_007
union all
select
n03_007 as code
, ST_AsGeoJSON(ST_Centroid(ST_Union(geom))) as center
, ST_AsGeoJSON(ST_Union(geom)) as geojson
from
"n03-13_28_130401"
where
n03_007 = $1
group by
n03_007
*/).valueOf();
var ret = {};
// postgres接続
pg.connect(cs, function(err, client){
if(err){
// connection error
}
// 市区町村取得
client.query(sqlCity, [req.params.code], function(err, result){
if(err){
// query error
}
if(result.rows.length == 0){
// データなし
}
// コード、市区町村名保持
ret.code = result.rows[0].code;
ret.city = result.rows[0].city;
// polygon取得
client.query(sqlPolygon, [req.params.code], function(err, result){
if(err){
// query error
}
if(result.rows.length == 0){
// データなし
}
// ポリゴンデータ
ret.center = result.rows[0].center;
ret.geojson = result.rows[0].geojson;
client.end();
// レスポンスを返す
res.send(ret);
});
});
});
}
};
ST_AsGeoJSON : geometryをGetJSONに変換します。
ST_Union : geometryを結合します。
ST_Centroid : geometryの重心を取得します。
routes/school.js
// routes/school.js
var pg = require('pg'),
here = require('here').here;
// load environment data
var env = require('../env.json');
var cs = env.connection_string;
module.exports = {
/**
* 指定された市区町村にある小学校を取得
*/
find: function(req, res){
console.log('school#find( code= %s )', req.params.code);
var sql = here(/*
select
coalesce(a27_002, '') || ' ' || coalesce(a27_003, '') as school
, a27_004 as address
, ST_AsGeoJSON(geom) as point
from
"a27-10_27-g_publicelementaryschool"
where
a27_001 = $1
UNION ALL
select
coalesce(a27_002, '') || ' ' || coalesce(a27_003, '') as school
, a27_004 as address
, ST_AsGeoJSON(geom) as point
from
"a27-10_28-g_publicelementaryschool"
where
a27_001 = $1
order by
school
*/).valueOf();
// postgres接続
pg.connect(cs, function(err, client){
if(err){
// connection error
}else{
// sql実行
client.query(sql, [req.params.code], function(err, result){
console.log('row count= %d', result.rows.length);
// 接続終了
client.end();
res.send(result.rows);
});
}
});
}
};
find
リクエストから取得したcode
を元に、小学校情報を取得します。
小学校の空間データは Point型 のようです。
routes/district.js
// routes/district.js
var pg = require('pg'),
here = require('here').here;
// load environment data
var env = require('../env.json');
var cs = env.connection_string;
module.exports = {
find: function(req, res){
console.log('district#find( code= %s )', req.params.code);
var sql = here(/*
select
coalesce(a27_006, '') || ' ' || coalesce(a27_007, '') as school
, ST_AsGeoJSON(ST_Union(geom)) as district
from
"a27-10_27-g_schooldistrict"
where
a27_005 = $1
group by
a27_006
, a27_007
UNION ALL
select
coalesce(a27_006, '') || ' ' || coalesce(a27_007, '') as school
, ST_AsGeoJSON(ST_Union(geom)) as district
from
"a27-10_28-g_schooldistrict"
where
a27_005 = $1
group by
a27_006
, a27_007
*/).valueOf();
// postgres接続
pg.connect(cs, function(err, client){
if(err){
// connection error
}else{
// sql実行
client.query(sql, [req.params.code], function(err, result){
console.log('row count= %d', result.rows.length);
client.end();
res.send(result.rows);
});
}
});
}
};
find
リクエストから取得したcode
を元に、校区情報を取得します。
行政区域情報と同様、複数のレコードでひとつの校区を表しているため、ST_Union
で空間データを結合します。