This repository has been archived by the owner on Dec 15, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 133
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
mmarks
committed
Dec 14, 2012
1 parent
f300478
commit b361960
Showing
9 changed files
with
716 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/** | ||
* @fileoverview Parses a .dbf file based on the xbase standards as documented | ||
* here: http://www.clicketyclick.dk/databases/xbase/format/dbf.html | ||
* @author Mano Marks | ||
*/ | ||
|
||
// Creates global namespace. | ||
DBF = {}; | ||
|
||
DBFParser = function() {}; | ||
|
||
/** | ||
* Executes a binary XHR to load a .dbf file and then creates a callback to | ||
* handle the result. | ||
* @param {string} url URL to the .dbf file. | ||
* @param {function(Object)} callback the function to be called when finished. | ||
* @param {Function} onerror the function to be called in case of an error | ||
* loading the file. | ||
*/ | ||
DBFParser.load = function(url, callback, onerror) { | ||
var xhr = new XMLHttpRequest(); | ||
xhr.responseType = 'arraybuffer'; | ||
xhr.onload = function() { | ||
var d = new DBFParser().parse(xhr.response); | ||
callback(d); | ||
}; | ||
xhr.onerror = onerror; | ||
xhr.open('GET', url); | ||
xhr.send(null); | ||
}; | ||
|
||
/** | ||
* Parses through the .dbf file byte by byte | ||
* @param {arraybuffer} arrayBuffer the ArrayBuffer created by loading the file | ||
* in XHR. | ||
* @return {object} o An object representing the .dbf file. | ||
*/ | ||
DBFParser.prototype.parse = function(arrayBuffer) { | ||
var o = {}; | ||
var dv = new DataView(arrayBuffer); | ||
var idx = 0; | ||
o.version = dv.getInt8(idx, false); | ||
|
||
idx += 1; | ||
o.year = dv.getUint8(idx) + 1900; | ||
idx += 1; | ||
o.month = dv.getUint8(idx); | ||
idx += 1; | ||
o.day = dv.getUint8(idx); | ||
idx += 1; | ||
|
||
o.numberOfRecords = dv.getInt32(idx, true); | ||
idx += 4; | ||
o.bytesInHeader = dv.getInt16(idx, true); | ||
idx += 2; | ||
o.bytesInRecord = dv.getInt16(idx, true); | ||
idx += 2; | ||
//reserved bytes | ||
idx += 2; | ||
o.incompleteTransation = dv.getUint8(idx); | ||
idx += 1; | ||
o.encryptionFlag = dv.getUint8(idx); | ||
idx += 1; | ||
// skip free record thread for LAN only | ||
idx += 4; | ||
// reserved for multi-user dBASE in dBASE III+ | ||
idx += 8; | ||
o.mdxFlag = dv.getUint8(idx); | ||
idx += 1; | ||
o.languageDriverId = dv.getUint8(idx); | ||
idx += 1; | ||
// reserved bytes | ||
idx += 2; | ||
|
||
o.fields = []; | ||
while (true) { | ||
var field = {}; | ||
var nameArray = []; | ||
for (var i = 0; i < 10; i++) { | ||
var letter = dv.getUint8(idx); | ||
if (letter != 0) nameArray.push(String.fromCharCode(letter)); | ||
idx += 1; | ||
} | ||
field.name = nameArray.join(''); | ||
idx += 1; | ||
field.type = String.fromCharCode(dv.getUint8(idx)); | ||
idx += 1; | ||
// Skip field data address | ||
idx += 4; | ||
field.fieldLength = dv.getUint8(idx); | ||
idx += 1; | ||
//field.decimalCount = dv.getUint8(idx); | ||
idx += 1; | ||
// Skip reserved bytes multi-user dBASE. | ||
idx += 2; | ||
field.workAreaId = dv.getUint8(idx); | ||
idx += 1; | ||
// Skip reserved bytes multi-user dBASE. | ||
idx += 2; | ||
field.setFieldFlag = dv.getUint8(idx); | ||
idx += 1; | ||
// Skip reserved bytes. | ||
idx += 7; | ||
field.indexFieldFlag = dv.getUint8(idx); | ||
idx += 1; | ||
o.fields.push(field); | ||
var test = dv.getUint8(idx); | ||
// Checks for end of field descriptor array. Valid .dbf files will have this | ||
// flag. | ||
if (dv.getUint8(idx) == 0x0D) break; | ||
} | ||
|
||
idx += 1; | ||
o.records = []; | ||
|
||
for (var i = 0; i < o.numberOfRecords; i++) { | ||
var record = {}; | ||
// Skip record deleted flag. | ||
//record["recordDeleted"] = String.fromCharCode(dv.getUint8(idx)); | ||
idx += 1; | ||
for (var j = 0; j < o.fields.length; j++) { | ||
var charString = []; | ||
for (var h = 0; h < o.fields[j].fieldLength; h++) { | ||
charString.push(String.fromCharCode(dv.getUint8(idx))); | ||
idx += 1; | ||
} | ||
record[o.fields[j].name] = charString.join('').trim(); | ||
|
||
} | ||
o.records.push(record); | ||
} | ||
|
||
return o; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title></title> | ||
<link rel="stylesheet" href="style.css"> | ||
<script src="lib/dbf.js"></script> | ||
<script src="https://raw.github.com/kig/shp.js/master/shp.js"></script> | ||
<script src="https://maps.googleapis.com/maps/api/js?sensor=false"> | ||
</script> | ||
<script src="shploadsample.js"></script> | ||
</head> | ||
<body> | ||
<div id="map"></div><div id="side"></div> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
/* | ||
* @fileoverview Demonstrates how to load a shapefile and parse it using | ||
* JavaScript. | ||
* @author Mano Marks | ||
*/ | ||
|
||
var map; | ||
var dbf; | ||
var shp; | ||
var infowindow; | ||
|
||
// Creates the map, loads in the SHP and DBF files. | ||
function init() { | ||
map = new google.maps.Map(document.getElementById('map'), { | ||
zoom: 4, | ||
center: new google.maps.LatLng(39.3, -95.8), | ||
mapTypeId: google.maps.MapTypeId.ROADMAP, | ||
styles: [ | ||
{ | ||
featureType: 'water', | ||
stylers: [{ color: '#c3cfdd'}] | ||
}, | ||
{ | ||
featureType: 'poi', | ||
stylers: [{visibility: 'off'}] | ||
} | ||
] | ||
}); | ||
|
||
SHPParser.load('tl_2010_06_tract10/tl_2010_06_tract10.shp', shpLoad, | ||
shpLoadError); | ||
DBFParser.load('tl_2010_06_tract10/tl_2010_06_tract10.dbf', dbfLoad, | ||
dbfLoadError); | ||
} | ||
|
||
// Handles the callback from loading DBFParser by assigning the dbf to a global. | ||
function dbfLoad(db) { | ||
dbf = db; | ||
if (dbf && shp) { | ||
render(); | ||
} | ||
} | ||
|
||
/* Handles the callback from loading the shp file. | ||
* @param {SHPParser} shp The results of parsing the shp file. | ||
*/ | ||
function shpLoad(sh) { | ||
shp = sh; | ||
if (dbf && shp) { | ||
render(); | ||
} | ||
} | ||
|
||
/** | ||
* Takes the geometries from the shp file and the data from the dbf file by | ||
* creating a polygon for each shp record with an InfoWindow and right panel | ||
* for the data from the dbf file. | ||
*/ | ||
function render() { | ||
var points; | ||
var type; | ||
var ne = new google.maps.LatLng(shp.maxY, shp.maxX); | ||
var sw = new google.maps.LatLng(shp.minY, shp.minX); | ||
var bounds = new google.maps.LatLngBounds(sw, ne); | ||
map.fitBounds(bounds); | ||
for (var i = 0; i < shp.records.length; i++) { | ||
var shape = shp.records[i].shape; | ||
switch (shape.type) { | ||
case 1: | ||
var marker = new google.maps.Marker({ | ||
position: new google.maps.LatLng(shape.content.y,shape.content.x), | ||
map: map | ||
}); | ||
break; | ||
|
||
case 3: | ||
points = pathToMVCArray(shape.content.points); | ||
break; | ||
|
||
case 5: | ||
|
||
// split into rings | ||
var polygonPoints = new google.maps.MVCArray(); | ||
var parts = shape.content.parts; | ||
if (parts.length === 1) { | ||
polygonPoints.push(pathToMVCArray(shape.content.points)); | ||
} else { | ||
var j; | ||
for (j = 0; j < parts.length - 1; j++) { | ||
polygonPoints.push(pathToMVCArray(shape.content.points.subarray( | ||
2 * parts[j], 2 * parts[j + 1]))); | ||
if (2 * parts[j + 1] > shape.content.points.length) { | ||
throw new Error('part index beyond points array end'); | ||
} | ||
} | ||
} | ||
// create a polygon. | ||
var polygon = new google.maps.Polygon({ | ||
strokeWeight: .3, | ||
fillOpacity: .2, | ||
paths: polygonPoints, | ||
map: map | ||
}); | ||
polygon.tractId = i; | ||
|
||
// Create InfoWindow at click point and put data in side panel. | ||
google.maps.event.addListener(polygon, 'click', function(e) { | ||
if (typeof infowindow != 'undefined') { | ||
infowindow.close(); | ||
} | ||
var htmlContent = recordHtmlContent(dbf.records[this.tractId]); | ||
infowindow = new google.maps.InfoWindow({ | ||
content: htmlContent, | ||
position: e.latLng, | ||
map: map | ||
}); | ||
document.getElementById('side').innerHTML = htmlContent; | ||
}); | ||
} | ||
} | ||
} | ||
|
||
/* Create a nice presentation for the attribute data. | ||
* @param {object} record An object representing the individual record. | ||
*/ | ||
function recordHtmlContent(record) { | ||
var content = ''; | ||
for (var key in record) { | ||
content += '<b>' + key + '</b>: ' + record[key] + '<br>'; | ||
} | ||
return content; | ||
} | ||
|
||
/* Create an MVCArray out of a set of points ordered longitude/latitude | ||
* @param {array} path an array of points. | ||
*/ | ||
function pathToMVCArray(path) { | ||
var polygonPoints = new google.maps.MVCArray(); | ||
for (var i = 0; i < path.length; i += 2) { | ||
polygonPoints.push(new google.maps.LatLng(path[i + 1], path[i])); | ||
} | ||
return polygonPoints; | ||
} | ||
|
||
// error handler for shploader. | ||
function shpLoadError() { | ||
window.console.log('shp file failed to load'); | ||
} | ||
|
||
// error handler for dbfloader. | ||
function dbfLoadError() { | ||
console.log('dbf file failed to load'); | ||
} | ||
document.addEventListener('DOMContentLoaded', init, false); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#map { | ||
margin: 0; | ||
padding: 0; | ||
height: 600px; | ||
width: 800px; | ||
float: left; | ||
} | ||
#side { | ||
width: 300px; | ||
height: 600px; | ||
float: right; | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] |
Binary file not shown.
Oops, something went wrong.