-
Notifications
You must be signed in to change notification settings - Fork 19
/
shape.js
142 lines (118 loc) · 3.59 KB
/
shape.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
var fs = require('fs');
var mapnik = require('mapnik');
var invalid = require('./invalid');
var path = require('path');
var srs = require('srs');
var utils = require('./utils');
module.exports = Shape;
function Shape(filepath) {
this.filepath = filepath;
this.basename = path.basename(this.filepath, path.extname(this.filepath));
this.datasource = new mapnik.Datasource({
type: 'shape',
file: filepath,
layer: this.basename
});
}
Shape.validFileType = ['shp'];
Shape.prototype.detailsName = 'json';
Shape.prototype.dstype = 'shape';
Shape.prototype.getProjection = function(callback) {
if (this._projection) return callback(null, this._projection);
var fileDir = path.dirname(this.filepath);
var projFile = fileDir + '/' + this.basename + '.prj';
var _this = this;
fs.readFile(projFile, function(err, data) {
if (err) return callback(invalid('Invalid shapefile: missing projection file'));
// srs and mapnik must be able to parse the projection file
var result;
try {
result = srs.parse(data);
new mapnik.Projection(result.proj4);
}
catch (error) {
return callback(invalid('Invalid shapefile: invalid projection file'));
}
// handle ESRI-specific projections
if (result.proj4 === undefined) {
try { result = srs.parse('ESRI::' + data.toString()); }
catch (error) {
return callback(
invalid('Invalid shapefile: invalid projection file')
);
}
if (result.proj4 !== undefined) {
_this._projection = result.proj4;
return callback(null, _this._projection);
} else return callback(invalid('Invalid shapefile: undefined proj4 string'));
}
else {
_this._projection = result.proj4;
return callback(null, _this._projection);
}
});
};
Shape.prototype.getCenter = function(callback) {
this.getExtent(function(err, extent) {
if (err) return callback(err);
return callback(null, [
0.5 * (extent[0] + extent[2]),
0.5 * (extent[1] + extent[3])
]);
});
};
Shape.prototype.getExtent = function(callback) {
if (this._extent) return callback(null, this._extent);
var _this = this;
var extent;
try {
extent = this.datasource.extent();
}
catch (err) {
return callback(invalid('Invalid shapefile: could not read extent'));
}
this.getProjection(function(err, projection) {
if (err) return callback(err);
var current = new mapnik.Projection(projection);
var wgs84 = new mapnik.Projection('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs');
var transform;
if (current !== wgs84) {
transform = new mapnik.ProjTransform(current, wgs84);
try {
extent = transform.forward(extent);
} catch (err) {
return callback(invalid('Unable to get extent. Failed to forward project to WGS84 coordinates.'));
}
}
_this._extent = extent;
return callback(null, _this._extent);
});
};
Shape.prototype.getDetails = function(callback) {
// Setup vector layers json
var actual = this.datasource.describe();
var fields = actual.fields;
var json = {
vector_layers: [
{
id: this.basename,
description: '',
minzoom: 0,
maxzoom: 22,
fields: fields
}
]
};
return callback(null, json);
};
Shape.prototype.getLayers = function(callback) {
return callback(null, [this.basename]);
};
Shape.prototype.getZooms = function(callback) {
var filepath = this.filepath;
var ds = this.datasource;
this.getExtent(function(err, extent) {
if (err) return callback(err);
utils.zoomsBySize(filepath, extent, ds, callback);
});
};