UNPKG

terriajs

Version:

Geospatial data visualization platform.

151 lines (140 loc) 6.01 kB
'use strict'; /*global require*/ var VarType = require('../Map/VarType'); var AddressGeocoder = require('../Map/AddressGeocoder'); var BulkAddressGeocoderResult = require('../Map/BulkAddressGeocoderResult'); var DeveloperError = require('terriajs-cesium/Source/Core/DeveloperError'); var GnafApi = require('../Models/GnafApi'); var defined = require('terriajs-cesium/Source/Core/defined'); var JulianDate = require('terriajs-cesium/Source/Core/JulianDate'); /** * Australia-only address converter, which uses the GNAF api to determine lat and long coordinates for a given address. * If TableStructure has address column, adds two new columns: lat and long. * * @alias GnafAddressGeocoder * @constructor * @extends AddressGeocoder * */ var GnafAddressGeocoder = function() { AddressGeocoder.call(this); }; /** * Convert addresses in miniumum number of calls to the server. When the promise fulfills, the tableStructure has been * updated with new lat and lon columns. * * @param {TableStructure} [tableStructure] A tableStructure that contains an address column. * @param {CorsProxy} [corsProxy] Proxy for cross origin resource sharing * @return {Promise} Promise that resolves to an BulkAddressGeocoderResult object. */ GnafAddressGeocoder.prototype.bulkConvertAddresses = function(tableStructure, corsProxy) { this.startTime = JulianDate.now(); this.tableStructure = tableStructure; if (!tableStructure.hasAddress) { throw new DeveloperError('This tableStructure has no addresses!'); } var addressesCol = tableStructure.columnsByType[VarType.ADDR][0]; if (addressesCol.length === 0) { throw new DeveloperError('Even though the tableStructure reports it has an address column, ' + 'it has no addresses!'); } var suburbs = tableStructure.getColumnWithName("Suburb"); smooshColumn(addressesCol, suburbs); var state = tableStructure.getColumnWithName("State"); smooshColumn(addressesCol, state); var postCodeCol = tableStructure.getColumnWithName("Postcode"); smooshColumn(addressesCol, postCodeCol); var gnafApi = new GnafApi(corsProxy); var addressesPlusInd = prefilterAddresses(addressesCol.values); this.skipIndices = addressesPlusInd.skipIndices; this.addressesCol = addressesCol; this.numberOfAddressesConverted = addressesPlusInd.addresses.length; var that = this; return gnafApi.bulkGeoCode(addressesPlusInd.addresses, undefined).then(function(info) { var longValues = []; var latValues = []; var matchedAddresses = []; var resultScores = []; var missingAddresses = []; var j = 0; for (var i=0; i<that.addressesCol.values.length; i++) { if (that.skipIndices.indexOf(i) !== -1 || !defined(info[j]) || !defined(info[j].location) || isNaN(info[j].location.longitude) || isNaN(info[j].location.latitude)) { if (that.addressesCol.values[i] !== null) { missingAddresses.push(that.addressesCol.values[i]); } longValues.push(null); latValues.push(null); resultScores.push(null); matchedAddresses.push(null); continue; } longValues.push(info[j].location.longitude); latValues.push(info[j].location.latitude); resultScores.push(info[j].score); matchedAddresses.push(info[j].name); j++; } that.tableStructure.addColumn("Matched Address", matchedAddresses); that.tableStructure.addColumn("Lon", longValues); that.tableStructure.addColumn("Lat", latValues); that.tableStructure.addColumn("Score", resultScores); var addressGeocoderData = new BulkAddressGeocoderResult(that.startTime, that.numberOfAddressesConverted, addressesPlusInd.nullAddresses, missingAddresses); return addressGeocoderData; }); }; /** * Add info to address, comma separated. * @param {TableColumn} [addressesCol] Table column with addresses to be added to * @param {TableColumn} [newCol] Table column with extra info to be added to addresses column * * @private */ function smooshColumn(addressesCol, newCol) { if (!defined(newCol)) { return; } if (newCol.values.length === addressesCol.values.length) { for (var i=0; i<addressesCol.values.length; i++) { if (addressesCol.values[i] !== null && newCol.values[i] !== null) { addressesCol.values[i] = addressesCol.values[i] + " " + newCol.values[i]; } } } } /** * Do not try to geocode addresses that don't look valid. * * @param {Array} addressList List of addresses that will be considered for geocoding * @return {Object} Probably shorter list of addresses that should be geocoded, as well as indices of addresses that * were removed. * @private */ function prefilterAddresses(addressList) { var addressesPlusInd = {skipIndices: [], nullAddresses: 0, addresses: []}; for (var i=0; i<addressList.length; i++) { var address = addressList[i]; if (address === null) { addressesPlusInd.skipIndices.push(i); addressesPlusInd.nullAddresses++; continue; } if (address.toLowerCase().indexOf("po box") !== -1 || address.toLowerCase().indexOf("post office box") !== -1) { addressesPlusInd.skipIndices.push(i); continue; } addressesPlusInd.addresses.push(address); } return addressesPlusInd; } module.exports = GnafAddressGeocoder;