shapefile.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. // https://github.com/mbostock/shapefile Version 0.6.2. Copyright 2017 Mike Bostock.
  2. (function (global, factory) {
  3. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  4. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  5. (factory((global.shapefile = global.shapefile || {})));
  6. }(this, (function (exports) { 'use strict';
  7. var array_cancel = function() {
  8. this._array = null;
  9. return Promise.resolve();
  10. };
  11. var array_read = function() {
  12. var array = this._array;
  13. this._array = null;
  14. return Promise.resolve(array ? {done: false, value: array} : {done: true, value: undefined});
  15. };
  16. function array(array) {
  17. return new ArraySource(array instanceof Uint8Array ? array : new Uint8Array(array));
  18. }
  19. function ArraySource(array) {
  20. this._array = array;
  21. }
  22. ArraySource.prototype.read = array_read;
  23. ArraySource.prototype.cancel = array_cancel;
  24. var fetchPath = function(url) {
  25. return fetch(url).then(function(response) {
  26. if(!response.ok){//xzw add
  27. return false
  28. }
  29. return response.body && response.body.getReader
  30. ? response.body.getReader()
  31. : response.arrayBuffer().then(array);
  32. });
  33. };
  34. var requestPath = function(url) {
  35. return new Promise(function(resolve, reject) {
  36. var request = new XMLHttpRequest;
  37. request.responseType = "arraybuffer";
  38. request.onload = function() { resolve(array(request.response)); };
  39. request.onerror = reject;
  40. request.ontimeout = reject;
  41. request.open("GET", url, true);
  42. request.send();
  43. });
  44. };
  45. function path(path) {
  46. return (typeof fetch === "function" ? fetchPath : requestPath)(path);
  47. }
  48. function stream(source) {
  49. return typeof source.read === "function" ? source : source.getReader();
  50. }
  51. var empty = new Uint8Array(0);
  52. var slice_cancel = function() {
  53. return this._source.cancel();
  54. };
  55. function concat(a, b) {
  56. if (!a.length) return b;
  57. if (!b.length) return a;
  58. var c = new Uint8Array(a.length + b.length);
  59. c.set(a);
  60. c.set(b, a.length);
  61. return c;
  62. }
  63. var slice_read = function() {
  64. var that = this, array = that._array.subarray(that._index);
  65. return that._source.read().then(function(result) {
  66. that._array = empty;
  67. that._index = 0;
  68. return result.done ? (array.length > 0
  69. ? {done: false, value: array}
  70. : {done: true, value: undefined})
  71. : {done: false, value: concat(array, result.value)};
  72. });
  73. };
  74. var slice_slice = function(length) {
  75. if ((length |= 0) < 0) throw new Error("invalid length");
  76. var that = this, index = this._array.length - this._index;
  77. // If the request fits within the remaining buffer, resolve it immediately.
  78. if (this._index + length <= this._array.length) {
  79. return Promise.resolve(this._array.subarray(this._index, this._index += length));
  80. }
  81. // Otherwise, read chunks repeatedly until the request is fulfilled.
  82. var array = new Uint8Array(length);
  83. array.set(this._array.subarray(this._index));
  84. return (function read() {
  85. return that._source.read().then(function(result) {
  86. // When done, it’s possible the request wasn’t fully fullfilled!
  87. // If so, the pre-allocated array is too big and needs slicing.
  88. if (result.done) {
  89. that._array = empty;
  90. that._index = 0;
  91. return index > 0 ? array.subarray(0, index) : null;
  92. }
  93. // If this chunk fulfills the request, return the resulting array.
  94. if (index + result.value.length >= length) {
  95. that._array = result.value;
  96. that._index = length - index;
  97. array.set(result.value.subarray(0, length - index), index);
  98. return array;
  99. }
  100. // Otherwise copy this chunk into the array, then read the next chunk.
  101. array.set(result.value, index);
  102. index += result.value.length;
  103. return read();
  104. });
  105. })();
  106. };
  107. function slice(source) {
  108. return typeof source.slice === "function" ? source :
  109. new SliceSource(typeof source.read === "function" ? source
  110. : source.getReader());
  111. }
  112. function SliceSource(source) {
  113. this._source = source;
  114. this._array = empty;
  115. this._index = 0;
  116. }
  117. SliceSource.prototype.read = slice_read;
  118. SliceSource.prototype.slice = slice_slice;
  119. SliceSource.prototype.cancel = slice_cancel;
  120. var dbf_cancel = function() {
  121. return this._source.cancel();
  122. };
  123. var readBoolean = function(value) {
  124. return /^[nf]$/i.test(value) ? false
  125. : /^[yt]$/i.test(value) ? true
  126. : null;
  127. };
  128. var readDate = function(value) {
  129. return new Date(+value.substring(0, 4), value.substring(4, 6) - 1, +value.substring(6, 8));
  130. };
  131. var readNumber = function(value) {
  132. return !(value = value.trim()) || isNaN(value = +value) ? null : value;
  133. };
  134. var readString = function(value) {
  135. return value.trim() || null;
  136. };
  137. var types = {
  138. B: readNumber,
  139. C: readString,
  140. D: readDate,
  141. F: readNumber,
  142. L: readBoolean,
  143. M: readNumber,
  144. N: readNumber
  145. };
  146. var dbf_read = function() {
  147. var that = this, i = 1;
  148. return that._source.slice(that._recordLength).then(function(value) {
  149. return value && (value[0] !== 0x1a) ? {done: false, value: that._fields.reduce(function(p, f) {
  150. p[f.name] = types[f.type](that._decode(value.subarray(i, i += f.length)));
  151. return p;
  152. }, {})} : {done: true, value: undefined};
  153. });
  154. };
  155. var view = function(array) {
  156. return new DataView(array.buffer, array.byteOffset, array.byteLength);
  157. };
  158. var dbf = function(source, decoder) {
  159. source = slice(source);
  160. return source.slice(32).then(function(array) {
  161. var head = view(array);
  162. return source.slice(head.getUint16(8, true) - 32).then(function(array) {
  163. return new Dbf(source, decoder, head, view(array));
  164. });
  165. });
  166. };
  167. function Dbf(source, decoder, head, body) {
  168. this._source = source;
  169. this._decode = decoder.decode.bind(decoder);
  170. this._recordLength = head.getUint16(10, true);
  171. this._fields = [];
  172. for (var n = 0; body.getUint8(n) !== 0x0d; n += 32) {
  173. for (var j = 0; j < 11; ++j) if (body.getUint8(n + j) === 0) break;
  174. this._fields.push({
  175. name: this._decode(new Uint8Array(body.buffer, body.byteOffset + n, j)),
  176. type: String.fromCharCode(body.getUint8(n + 11)),
  177. length: body.getUint8(n + 16)
  178. });
  179. }
  180. }
  181. var prototype = Dbf.prototype;
  182. prototype.read = dbf_read;
  183. prototype.cancel = dbf_cancel;
  184. function cancel() {
  185. return this._source.cancel();
  186. }
  187. var readMultiPoint = function(record) {
  188. var i = 40, j, n = record.getInt32(36, true), coordinates = new Array(n);
  189. for (j = 0; j < n; ++j, i += 16) coordinates[j] = [record.getFloat64(i, true), record.getFloat64(i + 8, true)];
  190. return {type: "MultiPoint", coordinates: coordinates};
  191. };
  192. var readNull = function() {
  193. return null;
  194. };
  195. var readPoint = function(record) {
  196. return {type: "Point", coordinates: [record.getFloat64(4, true), record.getFloat64(12, true)]};
  197. };
  198. var readPolygon = function(record) {
  199. var i = 44, j, n = record.getInt32(36, true), m = record.getInt32(40, true), parts = new Array(n), points = new Array(m), polygons = [], holes = [];
  200. for (j = 0; j < n; ++j, i += 4) parts[j] = record.getInt32(i, true);
  201. for (j = 0; j < m; ++j, i += 16) points[j] = [record.getFloat64(i, true), record.getFloat64(i + 8, true)];
  202. parts.forEach(function(i, j) {
  203. var ring = points.slice(i, parts[j + 1]);
  204. if (ringClockwise(ring)) polygons.push([ring]);
  205. else holes.push(ring);
  206. });
  207. holes.forEach(function(hole) {
  208. polygons.some(function(polygon) {
  209. if (ringContainsSome(polygon[0], hole)) {
  210. polygon.push(hole);
  211. return true;
  212. }
  213. }) || polygons.push([hole]);
  214. });
  215. return polygons.length === 1
  216. ? {type: "Polygon", coordinates: polygons[0]}
  217. : {type: "MultiPolygon", coordinates: polygons};
  218. };
  219. function ringClockwise(ring) {
  220. if ((n = ring.length) < 4) return false;
  221. var i = 0, n, area = ring[n - 1][1] * ring[0][0] - ring[n - 1][0] * ring[0][1];
  222. while (++i < n) area += ring[i - 1][1] * ring[i][0] - ring[i - 1][0] * ring[i][1];
  223. return area >= 0;
  224. }
  225. function ringContainsSome(ring, hole) {
  226. var i = -1, n = hole.length, c;
  227. while (++i < n) {
  228. if (c = ringContains(ring, hole[i])) {
  229. return c > 0;
  230. }
  231. }
  232. return false;
  233. }
  234. function ringContains(ring, point) {
  235. var x = point[0], y = point[1], contains = -1;
  236. for (var i = 0, n = ring.length, j = n - 1; i < n; j = i++) {
  237. var pi = ring[i], xi = pi[0], yi = pi[1],
  238. pj = ring[j], xj = pj[0], yj = pj[1];
  239. if (segmentContains(pi, pj, point)) {
  240. return 0;
  241. }
  242. if (((yi > y) !== (yj > y)) && ((x < (xj - xi) * (y - yi) / (yj - yi) + xi))) {
  243. contains = -contains;
  244. }
  245. }
  246. return contains;
  247. }
  248. function segmentContains(p0, p1, p2) {
  249. var x20 = p2[0] - p0[0], y20 = p2[1] - p0[1];
  250. if (x20 === 0 && y20 === 0) return true;
  251. var x10 = p1[0] - p0[0], y10 = p1[1] - p0[1];
  252. if (x10 === 0 && y10 === 0) return false;
  253. var t = (x20 * x10 + y20 * y10) / (x10 * x10 + y10 * y10);
  254. return t < 0 || t > 1 ? false : t === 0 || t === 1 ? true : t * x10 === x20 && t * y10 === y20;
  255. }
  256. var readPolyLine = function(record) {
  257. var i = 44, j, n = record.getInt32(36, true), m = record.getInt32(40, true), parts = new Array(n), points = new Array(m);
  258. for (j = 0; j < n; ++j, i += 4) parts[j] = record.getInt32(i, true);
  259. for (j = 0; j < m; ++j, i += 16) points[j] = [record.getFloat64(i, true), record.getFloat64(i + 8, true)];
  260. return n === 1
  261. ? {type: "LineString", coordinates: points}
  262. : {type: "MultiLineString", coordinates: parts.map(function(i, j) { return points.slice(i, parts[j + 1]); })};
  263. };
  264. var readPolyLineZ = function(record) {
  265. var i = 44, j, n = record.getInt32(36, true), m = record.getInt32(40, true), parts = new Array(n), points = new Array(m);
  266. for (j = 0; j < n; ++j, i += 4) parts[j] = record.getInt32(i, true);
  267. for (j = 0; j < m; ++j, i += 16) points[j] = [record.getFloat64(i, true), record.getFloat64(i + 8, true)];
  268. // Advance two doubles (z min, z max)
  269. i += 16;
  270. for (j = 0; j < m; ++j, i += 8) points[j].push(record.getFloat64(i, true));
  271. return n === 1
  272. ? {type: "LineStringZ", coordinates: points}
  273. : {type: "MultiLineStringZ", coordinates: parts.map(function(i, j) { return points.slice(i, parts[j + 1]); })};
  274. };
  275. var shp_read = function() {
  276. var that = this;
  277. return that._source.slice(8).then(function(array) {
  278. if (array == null) return {done: true, value: undefined};
  279. var header = view(array);
  280. return that._source.slice(header.getInt32(4, false) * 2).then(function(array) {
  281. var record = view(array);
  282. return {done: false, value: record.getInt32(0, true) ? that._type(record) : readNull()};
  283. });
  284. });
  285. };
  286. var types$1 = {
  287. 0: readNull,
  288. 1: readPoint,
  289. 3: readPolyLine,
  290. 5: readPolygon,
  291. 8: readMultiPoint,
  292. 11: readPoint,
  293. 13: readPolyLineZ,
  294. 15: readPolygon,
  295. 18: readMultiPoint
  296. };
  297. var shp = function(source) {
  298. source = slice(source);
  299. return source.slice(100).then(function(array) {
  300. return new Shp(source, view(array));
  301. });
  302. };
  303. function Shp(source, header) {
  304. var type = header.getInt32(32, true);
  305. if (!(type in types$1)) throw new Error("unsupported shape type: " + type);
  306. this._source = source;
  307. this._type = types$1[type];
  308. this.bbox = [header.getFloat64(36, true), header.getFloat64(44, true), header.getFloat64(52, true), header.getFloat64(60, true)];
  309. }
  310. var prototype$2 = Shp.prototype;
  311. prototype$2.read = shp_read;
  312. prototype$2.cancel = cancel;
  313. function noop() {}
  314. var shapefile_cancel = function() {
  315. return Promise.all([
  316. this._dbf && this._dbf.cancel(),
  317. this._shp.cancel()
  318. ]).then(noop);
  319. };
  320. var shapefile_read = function() {
  321. var that = this;
  322. return Promise.all([
  323. that._dbf ? that._dbf.read() : {value: {}},
  324. that._shp.read()
  325. ]).then(function(results) {
  326. var dbf = results[0], shp = results[1];
  327. return shp.done ? shp : {
  328. done: false,
  329. value: {
  330. type: "Feature",
  331. properties: dbf.value,
  332. geometry: shp.value
  333. }
  334. };
  335. });
  336. };
  337. var shapefile = function(shpSource, dbfSource, decoder) {
  338. return Promise.all([
  339. shp(shpSource),
  340. dbfSource && dbf(dbfSource, decoder)
  341. ]).then(function(sources) {
  342. return new Shapefile(sources[0], sources[1]);
  343. });
  344. };
  345. function Shapefile(shp$$1, dbf$$1) {
  346. this._shp = shp$$1;
  347. this._dbf = dbf$$1;
  348. this.bbox = shp$$1.bbox;
  349. }
  350. var prototype$1 = Shapefile.prototype;
  351. prototype$1.read = shapefile_read;
  352. prototype$1.cancel = shapefile_cancel;
  353. function open(shp$$1, dbf$$1, options) {
  354. if (typeof dbf$$1 === "string") {
  355. if (!/\.dbf$/.test(dbf$$1)) dbf$$1 += ".dbf";
  356. dbf$$1 = path(dbf$$1, options);
  357. } else if (dbf$$1 instanceof ArrayBuffer || dbf$$1 instanceof Uint8Array) {
  358. dbf$$1 = array(dbf$$1);
  359. } else if (dbf$$1 != null) {
  360. dbf$$1 = stream(dbf$$1);
  361. }
  362. if (typeof shp$$1 === "string") {
  363. if (!/\.shp$/.test(shp$$1)) shp$$1 += ".shp";
  364. if (dbf$$1 === undefined) dbf$$1 = path(shp$$1.substring(0, shp$$1.length - 4) + ".dbf", options).catch(function() {});
  365. shp$$1 = path(shp$$1, options);
  366. } else if (shp$$1 instanceof ArrayBuffer || shp$$1 instanceof Uint8Array) {
  367. shp$$1 = array(shp$$1);
  368. } else {
  369. shp$$1 = stream(shp$$1);
  370. }
  371. return Promise.all([shp$$1, dbf$$1]).then(function(sources) {
  372. var shp$$1 = sources[0], dbf$$1 = sources[1], encoding = "windows-1252";
  373. if (options && options.encoding != null) encoding = options.encoding;
  374. return shapefile(shp$$1, dbf$$1, dbf$$1 && new TextDecoder(encoding));
  375. });
  376. }
  377. function openShp(source, options) {
  378. if (typeof source === "string") {
  379. if (!/\.shp$/.test(source)) source += ".shp";
  380. source = path(source, options);
  381. } else if (source instanceof ArrayBuffer || source instanceof Uint8Array) {
  382. source = array(source);
  383. } else {
  384. source = stream(source);
  385. }
  386. return Promise.resolve(source).then(shp);
  387. }
  388. function openDbf(source, options) {
  389. var encoding = "windows-1252";
  390. if (options && options.encoding != null) encoding = options.encoding;
  391. encoding = new TextDecoder(encoding);
  392. if (typeof source === "string") {
  393. if (!/\.dbf$/.test(source)) source += ".dbf";
  394. source = path(source, options);
  395. } else if (source instanceof ArrayBuffer || source instanceof Uint8Array) {
  396. source = array(source);
  397. } else {
  398. source = stream(source);
  399. }
  400. return Promise.resolve(source).then(function(source) {
  401. return dbf(source, encoding);
  402. });
  403. }
  404. function read(shp$$1, dbf$$1, options) {
  405. return open(shp$$1, dbf$$1, options).then(function(source) {
  406. var features = [], collection = {type: "FeatureCollection", features: features, bbox: source.bbox};
  407. return source.read().then(function read(result) {
  408. if (result.done) return collection;
  409. features.push(result.value);
  410. return source.read().then(read);
  411. });
  412. });
  413. }
  414. exports.open = open;
  415. exports.openShp = openShp;
  416. exports.openDbf = openDbf;
  417. exports.read = read;
  418. Object.defineProperty(exports, '__esModule', { value: true });
  419. })));