| // https://github.com/mbostock/shapefile Version 0.6.2. Copyright 2017 Mike Bostock. |
| (function (global, factory) { |
| typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : |
| typeof define === 'function' && define.amd ? define(['exports'], factory) : |
| (factory((global.shapefile = global.shapefile || {}))); |
| }(this, (function (exports) { 'use strict'; |
| |
| var array_cancel = function() { |
| this._array = null; |
| return Promise.resolve(); |
| }; |
| |
| var array_read = function() { |
| var array = this._array; |
| this._array = null; |
| return Promise.resolve(array ? {done: false, value: array} : {done: true, value: undefined}); |
| }; |
| |
| function array(array) { |
| return new ArraySource(array instanceof Uint8Array ? array : new Uint8Array(array)); |
| } |
| |
| function ArraySource(array) { |
| this._array = array; |
| } |
| |
| ArraySource.prototype.read = array_read; |
| ArraySource.prototype.cancel = array_cancel; |
| |
| var fetchPath = function(url) { |
| return fetch(url).then(function(response) { |
| return response.body && response.body.getReader |
| ? response.body.getReader() |
| : response.arrayBuffer().then(array); |
| }); |
| }; |
| |
| var requestPath = function(url) { |
| return new Promise(function(resolve, reject) { |
| var request = new XMLHttpRequest; |
| request.responseType = "arraybuffer"; |
| request.onload = function() { resolve(array(request.response)); }; |
| request.onerror = reject; |
| request.ontimeout = reject; |
| request.open("GET", url, true); |
| request.send(); |
| }); |
| }; |
| |
| function path(path) { |
| return (typeof fetch === "function" ? fetchPath : requestPath)(path); |
| } |
| |
| function stream(source) { |
| return typeof source.read === "function" ? source : source.getReader(); |
| } |
| |
| var empty = new Uint8Array(0); |
| |
| var slice_cancel = function() { |
| return this._source.cancel(); |
| }; |
| |
| function concat(a, b) { |
| if (!a.length) return b; |
| if (!b.length) return a; |
| var c = new Uint8Array(a.length + b.length); |
| c.set(a); |
| c.set(b, a.length); |
| return c; |
| } |
| |
| var slice_read = function() { |
| var that = this, array = that._array.subarray(that._index); |
| return that._source.read().then(function(result) { |
| that._array = empty; |
| that._index = 0; |
| return result.done ? (array.length > 0 |
| ? {done: false, value: array} |
| : {done: true, value: undefined}) |
| : {done: false, value: concat(array, result.value)}; |
| }); |
| }; |
| |
| var slice_slice = function(length) { |
| if ((length |= 0) < 0) throw new Error("invalid length"); |
| var that = this, index = this._array.length - this._index; |
| |
| // If the request fits within the remaining buffer, resolve it immediately. |
| if (this._index + length <= this._array.length) { |
| return Promise.resolve(this._array.subarray(this._index, this._index += length)); |
| } |
| |
| // Otherwise, read chunks repeatedly until the request is fulfilled. |
| var array = new Uint8Array(length); |
| array.set(this._array.subarray(this._index)); |
| return (function read() { |
| return that._source.read().then(function(result) { |
| |
| // When done, it鈥檚 possible the request wasn鈥檛 fully fullfilled! |
| // If so, the pre-allocated array is too big and needs slicing. |
| if (result.done) { |
| that._array = empty; |
| that._index = 0; |
| return index > 0 ? array.subarray(0, index) : null; |
| } |
| |
| // If this chunk fulfills the request, return the resulting array. |
| if (index + result.value.length >= length) { |
| that._array = result.value; |
| that._index = length - index; |
| array.set(result.value.subarray(0, length - index), index); |
| return array; |
| } |
| |
| // Otherwise copy this chunk into the array, then read the next chunk. |
| array.set(result.value, index); |
| index += result.value.length; |
| return read(); |
| }); |
| })(); |
| }; |
| |
| function slice(source) { |
| return typeof source.slice === "function" ? source : |
| new SliceSource(typeof source.read === "function" ? source |
| : source.getReader()); |
| } |
| |
| function SliceSource(source) { |
| this._source = source; |
| this._array = empty; |
| this._index = 0; |
| } |
| |
| SliceSource.prototype.read = slice_read; |
| SliceSource.prototype.slice = slice_slice; |
| SliceSource.prototype.cancel = slice_cancel; |
| |
| var dbf_cancel = function() { |
| return this._source.cancel(); |
| }; |
| |
| var readBoolean = function(value) { |
| return /^[nf]$/i.test(value) ? false |
| : /^[yt]$/i.test(value) ? true |
| : null; |
| }; |
| |
| var readDate = function(value) { |
| return new Date(+value.substring(0, 4), value.substring(4, 6) - 1, +value.substring(6, 8)); |
| }; |
| |
| var readNumber = function(value) { |
| return !(value = value.trim()) || isNaN(value = +value) ? null : value; |
| }; |
| |
| var readString = function(value) { |
| return value.trim() || null; |
| }; |
| |
| var types = { |
| B: readNumber, |
| C: readString, |
| D: readDate, |
| F: readNumber, |
| L: readBoolean, |
| M: readNumber, |
| N: readNumber |
| }; |
| |
| var dbf_read = function() { |
| var that = this, i = 1; |
| return that._source.slice(that._recordLength).then(function(value) { |
| return value && (value[0] !== 0x1a) ? {done: false, value: that._fields.reduce(function(p, f) { |
| p[f.name] = types[f.type](that._decode(value.subarray(i, i += f.length))); |
| return p; |
| }, {})} : {done: true, value: undefined}; |
| }); |
| }; |
| |
| var view = function(array) { |
| return new DataView(array.buffer, array.byteOffset, array.byteLength); |
| }; |
| |
| var dbf = function(source, decoder) { |
| source = slice(source); |
| return source.slice(32).then(function(array) { |
| var head = view(array); |
| return source.slice(head.getUint16(8, true) - 32).then(function(array) { |
| return new Dbf(source, decoder, head, view(array)); |
| }); |
| }); |
| }; |
| |
| function Dbf(source, decoder, head, body) { |
| this._source = source; |
| this._decode = decoder.decode.bind(decoder); |
| this._recordLength = head.getUint16(10, true); |
| this._fields = []; |
| for (var n = 0; body.getUint8(n) !== 0x0d; n += 32) { |
| for (var j = 0; j < 11; ++j) if (body.getUint8(n + j) === 0) break; |
| this._fields.push({ |
| name: this._decode(new Uint8Array(body.buffer, body.byteOffset + n, j)), |
| type: String.fromCharCode(body.getUint8(n + 11)), |
| length: body.getUint8(n + 16) |
| }); |
| } |
| } |
| |
| var prototype = Dbf.prototype; |
| prototype.read = dbf_read; |
| prototype.cancel = dbf_cancel; |
| |
| function cancel() { |
| return this._source.cancel(); |
| } |
| |
| var readMultiPoint = function(record) { |
| var i = 40, j, n = record.getInt32(36, true), coordinates = new Array(n); |
| for (j = 0; j < n; ++j, i += 16) coordinates[j] = [record.getFloat64(i, true), record.getFloat64(i + 8, true)]; |
| return {type: "MultiPoint", coordinates: coordinates}; |
| }; |
| |
| var readNull = function() { |
| return null; |
| }; |
| |
| var readPoint = function(record) { |
| return {type: "Point", coordinates: [record.getFloat64(4, true), record.getFloat64(12, true)]}; |
| }; |
| |
| var readPolygon = function(record) { |
| var i = 44, j, n = record.getInt32(36, true), m = record.getInt32(40, true), parts = new Array(n), points = new Array(m), polygons = [], holes = []; |
| for (j = 0; j < n; ++j, i += 4) parts[j] = record.getInt32(i, true); |
| for (j = 0; j < m; ++j, i += 16) points[j] = [record.getFloat64(i, true), record.getFloat64(i + 8, true)]; |
| |
| parts.forEach(function(i, j) { |
| var ring = points.slice(i, parts[j + 1]); |
| if (ringClockwise(ring)) polygons.push([ring]); |
| else holes.push(ring); |
| }); |
| |
| holes.forEach(function(hole) { |
| polygons.some(function(polygon) { |
| if (ringContainsSome(polygon[0], hole)) { |
| polygon.push(hole); |
| return true; |
| } |
| }) || polygons.push([hole]); |
| }); |
| |
| return polygons.length === 1 |
| ? {type: "Polygon", coordinates: polygons[0]} |
| : {type: "MultiPolygon", coordinates: polygons}; |
| }; |
| |
| function ringClockwise(ring) { |
| if ((n = ring.length) < 4) return false; |
| var i = 0, n, area = ring[n - 1][1] * ring[0][0] - ring[n - 1][0] * ring[0][1]; |
| while (++i < n) area += ring[i - 1][1] * ring[i][0] - ring[i - 1][0] * ring[i][1]; |
| return area >= 0; |
| } |
| |
| function ringContainsSome(ring, hole) { |
| var i = -1, n = hole.length, c; |
| while (++i < n) { |
| if (c = ringContains(ring, hole[i])) { |
| return c > 0; |
| } |
| } |
| return false; |
| } |
| |
| function ringContains(ring, point) { |
| var x = point[0], y = point[1], contains = -1; |
| for (var i = 0, n = ring.length, j = n - 1; i < n; j = i++) { |
| var pi = ring[i], xi = pi[0], yi = pi[1], |
| pj = ring[j], xj = pj[0], yj = pj[1]; |
| if (segmentContains(pi, pj, point)) { |
| return 0; |
| } |
| if (((yi > y) !== (yj > y)) && ((x < (xj - xi) * (y - yi) / (yj - yi) + xi))) { |
| contains = -contains; |
| } |
| } |
| return contains; |
| } |
| |
| function segmentContains(p0, p1, p2) { |
| var x20 = p2[0] - p0[0], y20 = p2[1] - p0[1]; |
| if (x20 === 0 && y20 === 0) return true; |
| var x10 = p1[0] - p0[0], y10 = p1[1] - p0[1]; |
| if (x10 === 0 && y10 === 0) return false; |
| var t = (x20 * x10 + y20 * y10) / (x10 * x10 + y10 * y10); |
| return t < 0 || t > 1 ? false : t === 0 || t === 1 ? true : t * x10 === x20 && t * y10 === y20; |
| } |
| |
| var readPolyLine = function(record) { |
| var i = 44, j, n = record.getInt32(36, true), m = record.getInt32(40, true), parts = new Array(n), points = new Array(m); |
| for (j = 0; j < n; ++j, i += 4) parts[j] = record.getInt32(i, true); |
| for (j = 0; j < m; ++j, i += 16) points[j] = [record.getFloat64(i, true), record.getFloat64(i + 8, true)]; |
| return n === 1 |
| ? {type: "LineString", coordinates: points} |
| : {type: "MultiLineString", coordinates: parts.map(function(i, j) { return points.slice(i, parts[j + 1]); })}; |
| }; |
| |
| var shp_read = function() { |
| var that = this; |
| return that._source.slice(8).then(function(array) { |
| if (array == null) return {done: true, value: undefined}; |
| var header = view(array); |
| return that._source.slice(header.getInt32(4, false) * 2).then(function(array) { |
| var record = view(array); |
| return {done: false, value: record.getInt32(0, true) ? that._type(record) : readNull()}; |
| }); |
| }); |
| }; |
| |
| var types$1 = { |
| 0: readNull, |
| 1: readPoint, |
| 3: readPolyLine, |
| 5: readPolygon, |
| 8: readMultiPoint, |
| 11: readPoint, |
| 13: readPolyLine, |
| 15: readPolygon, |
| 18: readMultiPoint |
| }; |
| |
| var shp = function(source) { |
| source = slice(source); |
| return source.slice(100).then(function(array) { |
| return new Shp(source, view(array)); |
| }); |
| }; |
| |
| function Shp(source, header) { |
| var type = header.getInt32(32, true); |
| if (!(type in types$1)) throw new Error("unsupported shape type: " + type); |
| this._source = source; |
| this._type = types$1[type]; |
| this.bbox = [header.getFloat64(36, true), header.getFloat64(44, true), header.getFloat64(52, true), header.getFloat64(60, true)]; |
| } |
| |
| var prototype$2 = Shp.prototype; |
| prototype$2.read = shp_read; |
| prototype$2.cancel = cancel; |
| |
| function noop() {} |
| |
| var shapefile_cancel = function() { |
| return Promise.all([ |
| this._dbf && this._dbf.cancel(), |
| this._shp.cancel() |
| ]).then(noop); |
| }; |
| |
| var shapefile_read = function() { |
| var that = this; |
| return Promise.all([ |
| that._dbf ? that._dbf.read() : {value: {}}, |
| that._shp.read() |
| ]).then(function(results) { |
| var dbf = results[0], shp = results[1]; |
| return shp.done ? shp : { |
| done: false, |
| value: { |
| type: "Feature", |
| properties: dbf.value, |
| geometry: shp.value |
| } |
| }; |
| }); |
| }; |
| |
| var shapefile = function(shpSource, dbfSource, decoder) { |
| return Promise.all([ |
| shp(shpSource), |
| dbfSource && dbf(dbfSource, decoder) |
| ]).then(function(sources) { |
| return new Shapefile(sources[0], sources[1]); |
| }); |
| }; |
| |
| function Shapefile(shp$$1, dbf$$1) { |
| this._shp = shp$$1; |
| this._dbf = dbf$$1; |
| this.bbox = shp$$1.bbox; |
| } |
| |
| var prototype$1 = Shapefile.prototype; |
| prototype$1.read = shapefile_read; |
| prototype$1.cancel = shapefile_cancel; |
| |
| function open(shp$$1, dbf$$1, options) { |
| if (typeof dbf$$1 === "string") { |
| if (!/\.dbf$/.test(dbf$$1)) dbf$$1 += ".dbf"; |
| dbf$$1 = path(dbf$$1, options); |
| } else if (dbf$$1 instanceof ArrayBuffer || dbf$$1 instanceof Uint8Array) { |
| dbf$$1 = array(dbf$$1); |
| } else if (dbf$$1 != null) { |
| dbf$$1 = stream(dbf$$1); |
| } |
| if (typeof shp$$1 === "string") { |
| if (!/\.shp$/.test(shp$$1)) shp$$1 += ".shp"; |
| if (dbf$$1 === undefined) dbf$$1 = path(shp$$1.substring(0, shp$$1.length - 4) + ".dbf", options).catch(function() {}); |
| shp$$1 = path(shp$$1, options); |
| } else if (shp$$1 instanceof ArrayBuffer || shp$$1 instanceof Uint8Array) { |
| shp$$1 = array(shp$$1); |
| } else { |
| shp$$1 = stream(shp$$1); |
| } |
| return Promise.all([shp$$1, dbf$$1]).then(function(sources) { |
| var shp$$1 = sources[0], dbf$$1 = sources[1], encoding = "windows-1252"; |
| if (options && options.encoding != null) encoding = options.encoding; |
| return shapefile(shp$$1, dbf$$1, dbf$$1 && new TextDecoder(encoding)); |
| }); |
| } |
| |
| function openShp(source, options) { |
| if (typeof source === "string") { |
| if (!/\.shp$/.test(source)) source += ".shp"; |
| source = path(source, options); |
| } else if (source instanceof ArrayBuffer || source instanceof Uint8Array) { |
| source = array(source); |
| } else { |
| source = stream(source); |
| } |
| return Promise.resolve(source).then(shp); |
| } |
| |
| function openDbf(source, options) { |
| var encoding = "windows-1252"; |
| if (options && options.encoding != null) encoding = options.encoding; |
| encoding = new TextDecoder(encoding); |
| if (typeof source === "string") { |
| if (!/\.dbf$/.test(source)) source += ".dbf"; |
| source = path(source, options); |
| } else if (source instanceof ArrayBuffer || source instanceof Uint8Array) { |
| source = array(source); |
| } else { |
| source = stream(source); |
| } |
| return Promise.resolve(source).then(function(source) { |
| return dbf(source, encoding); |
| }); |
| } |
| |
| function read(shp$$1, dbf$$1, options) { |
| return open(shp$$1, dbf$$1, options).then(function(source) { |
| var features = [], collection = {type: "FeatureCollection", features: features, bbox: source.bbox}; |
| return source.read().then(function read(result) { |
| if (result.done) return collection; |
| features.push(result.value); |
| return source.read().then(read); |
| }); |
| }); |
| } |
| |
| exports.open = open; |
| exports.openShp = openShp; |
| exports.openDbf = openDbf; |
| exports.read = read; |
| |
| Object.defineProperty(exports, '__esModule', { value: true }); |
| |
| }))); |