Skip to content

Instantly share code, notes, and snippets.

@bmcminn
Created March 26, 2019 22:54

Revisions

  1. bmcminn created this gist Mar 26, 2019.
    127 changes: 127 additions & 0 deletions zip-distance.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,127 @@

    const ZIPCODES = require('./zipcodes.js')
    const sqlite = require('sqlite')
    const Promise = require('bluebird')


    // http://www.zipcodeapi.com/API

    /**
    * Calculates distance between two ZIPCODES
    * @sauce: https://www.movable-type.co.uk/scripts/latlong.html
    * @param {object} zip1 Object containing zip, lat, lng
    * @param {object} zip2 Object containing zip, lat, lng
    * @param {integer} PRECISION Flag to return the result in kilometers or miles
    * @return {double} A double representing the distance between the two points
    */
    function zipDistance(zip1, zip2, PRECISION=3) {
    const R = 6371
    // const R = 6371e3 // meters
    // const M = R / 1.609

    const φ1 = degressToRadians(zip1.lat)
    const φ2 = degressToRadians(zip2.lat)
    const Δφ = degressToRadians((zip2.lat-zip1.lat))
    const Δλ = degressToRadians((zip2.lng-zip1.lng))

    let a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
    Math.cos(φ1) * Math.cos(φ2) *
    Math.sin(Δλ/2) * Math.sin(Δλ/2)

    let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))

    return (R * c).toFixed(PRECISION)
    }


    /**
    * Calculate the lat and lng ranges for a given "radius"
    * @param {[type]} zip1 [description]
    * @param {[type]} radius [description]
    * @return {[type]} [description]
    */
    function getZipRadius(zip1, radius) {

    let DIST = 0.01035 * radius

    return {
    latMin: zip1.lat - DIST,
    latMax: zip1.lat + DIST,
    lngMin: zip1.lng - DIST,
    lngMax: zip1.lng + DIST,
    }
    }


    /**
    * [degressToRadians description]
    * @param {[type]} degrees [description]
    * @return {[type]} [description]
    */
    function degressToRadians(degrees) {
    return degrees * (Math.PI/180)
    }


    /**
    * Converts Km to miles
    * @param {float} km distance in kilometers
    * @return {double} miles distance in miles
    */
    function kmToMiles(km, PRECISION=3) {
    return (km / 1.609).toFixed(PRECISION)
    }


    /**
    * [getZipsInRadius description]
    * @param {[type]} zip [description]
    * @param {[type]} zips [description]
    * @param {[type]} radius [description]
    * @return {[type]} [description]
    */
    function getZipsInRadius(zip, zips, radius) {

    const RADIUS = getZipRadius(zip, radius)

    return zips.filter(el => {
    if (RADIUS.latMin <= el.lat && el.lat <= RADIUS.latMax
    && RADIUS.lngMin <= el.lng && el.lng <= RADIUS.lngMax
    ) {

    let distance = zipDistance(zip, el)

    if (distance <= radius) {
    return el
    }
    }
    })
    }





    // const TARGET = ZIPCODES[0]
    const RADIUS = 100


    const TARGET = {
    lat: 30.3,
    lng: -97.6,
    zip_code: '???',
    }


    // let res = getZipsInRadius(TARGET, ZIPCODES, RADIUS)

    // res.map(el => {
    // console.log(`distance from ${TARGET.zip_code} to ${el.zip_code} is`, kmToMiles(zipDistance(TARGET, el)), 'miles')
    // })


    getZipsInRadius(TARGET, ZIPCODES, RADIUS)
    .map(el => {
    console.log(`distance from ${TARGET.zip_code} to ${el.zip_code} is`, kmToMiles(zipDistance(TARGET, el)), 'miles')
    })