From 8da264ae24045a4094e88760f332370912ee5fa1 Mon Sep 17 00:00:00 2001 From: Chad Burt Date: Mon, 9 Sep 2013 17:01:36 -0700 Subject: [PATCH] Add support for loading via File API Shapefile and DBF constructors now support referencing files via both url and a HTML 5 File API handle. This can be used to load and map content added to file input(s) and processed on the client browser. FileReader and FileReaderSync are both used depending upon availability to make this functionality work in both Gecko and Webkit inside Web Workers. --- dbf.js | 70 +++++++++++++++++++++++++++++---------- files.html | 65 ++++++++++++++++++++++++++++++++++++ shapefile.js | 93 ++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 187 insertions(+), 41 deletions(-) create mode 100644 files.html diff --git a/dbf.js b/dbf.js index 5e69d47..afc294f 100644 --- a/dbf.js +++ b/dbf.js @@ -56,27 +56,63 @@ } var DBF = function(url, callback){ - var xhr = new XMLHttpRequest(); - - xhr.open("GET", url, false) - xhr.overrideMimeType("text/plain; charset=x-user-defined") - xhr.send() - - if(200 != xhr.status) - throw "Unable to load " + url + " status: " + xhr.status - - this.stream = new Gordon.Stream(xhr.responseText) - this.callback = callback - - this.readFileHeader() - this.readFieldDescriptions() - this.readRecords() - - this._postMessage() + if (!!url.lastModifiedDate) + this.handleFile(url, callback); + else + this.handleUri(url, callback); } DBF.prototype = { constructor: DBF, + handleFile: function(file, callback) { + this.callback = callback; + + if (!!window.FileReader) { + var reader = new FileReader(); + } else { + var reader = new FileReaderSync(); + } + + reader.onload = (function(that){ + return function(e){ + that.onFileLoad(e.target.result) + } + })(this); + + if (!!window.FileReader) { + reader.readAsBinaryString(file); + } else { + this.onFileLoad(reader.readAsBinaryString(file)); + } + }, + onFileLoad: function(data) { + this.stream = new Gordon.Stream(data) + + this.readFileHeader() + this.readFieldDescriptions() + this.readRecords() + + this._postMessage() + }, + handleUri: function(url, callback) { + var xhr = new XMLHttpRequest(); + + xhr.open("GET", url, false) + xhr.overrideMimeType("text/plain; charset=x-user-defined") + xhr.send() + + if(200 != xhr.status) + throw "Unable to load " + url + " status: " + xhr.status + + this.stream = new Gordon.Stream(xhr.responseText) + this.callback = callback + + this.readFileHeader() + this.readFieldDescriptions() + this.readRecords() + + this._postMessage() + }, _postMessage: function() { var data = { header: this.header, diff --git a/files.html b/files.html new file mode 100644 index 0000000..a393249 --- /dev/null +++ b/files.html @@ -0,0 +1,65 @@ + + + + js-shapefile-to-geojson Demo Page + + + + Fork me on GitHub +

js-shapefile-to-geojson Demo Page

+

Pure client-side JavaScript (no server side code) parsing of shapefiles and dbase files to GeoJSON format displayed using OpenLayers.

+
+

View project at http://github.com/wavded/js-shapefile-to-geojson. + + + + + +
+
+ .shp + .dbf + + + diff --git a/shapefile.js b/shapefile.js index 9be3bb6..976e8dc 100644 --- a/shapefile.js +++ b/shapefile.js @@ -11,6 +11,8 @@ if (!worker) { var path = (o.jsRoot || "") + "shapefile.js" var w = worker = this.worker = new Worker(path) + } else { + var w = worker } w.onmessage = function(e){ @@ -64,36 +66,79 @@ } var Shapefile = function(o,callback){ - var xhr = new XMLHttpRequest(), - that = this, - o = typeof o == "string" ? {shp: o} : o - - xhr.open("GET", o.shp, false) - xhr.overrideMimeType("text/plain; charset=x-user-defined") - xhr.send() - - if(200 != xhr.status) - throw "Unable to load " + o.shp + " status: " + xhr.status - - this.url = o.shp - this.stream = new Gordon.Stream(xhr.responseText) + var o = typeof o == "string" ? {shp: o} : o this.callback = callback - this.readFileHeader() - this.readRecords() - this.formatIntoGeoJson() - - if(o.dbf) this.dbf = IN_WORKER ? - null : - new DBF(o.dbf,function(data){ - that.addDBFDataToGeoJSON(data) - that._postMessage() - }) - else this._postMessage + if (!!o.shp.lastModifiedDate) + this.handleFile(o); + else + this.handleUri(o); } Shapefile.prototype = { constructor: Shapefile, + handleUri: function(o) { + var xhr = new XMLHttpRequest(), + that = this + + xhr.open("GET", o.shp, false) + xhr.overrideMimeType("text/plain; charset=x-user-defined") + xhr.send() + + if(200 != xhr.status) + throw "Unable to load " + o.shp + " status: " + xhr.status + + this.url = o.shp + this.stream = new Gordon.Stream(xhr.responseText) + + this.readFileHeader() + this.readRecords() + this.formatIntoGeoJson() + + if(o.dbf) this.dbf = IN_WORKER ? + null : + new DBF(o.dbf,function(data){ + that.addDBFDataToGeoJSON(data) + that._postMessage() + }) + else this._postMessage() + + }, + handleFile: function(o) { + this.options = o + if (!!window.FileReader) { + var reader = new FileReader(); + } else { + var reader = new FileReaderSync(); + } + + reader.onload = (function(that){ + return function(e){ + that.onFileLoad(e.target.result) + } + })(this); + + if (!!window.FileReader) { + reader.readAsBinaryString(o.shp); + } else { + this.onFileLoad(reader.readAsBinaryString(o.shp)); + } + }, + onFileLoad: function(data) { + this.stream = new Gordon.Stream(data) + + this.readFileHeader() + this.readRecords() + this.formatIntoGeoJson() + + if(this.options.dbf) this.dbf = IN_WORKER ? + null : + new DBF(this.options.dbf,function(data){ + that.addDBFDataToGeoJSON(data) + that._postMessage() + }) + else this._postMessage() + }, _postMessage: function() { var data = { header: this.header,