Using the GeoJSON format for Geolocation

Last edit: Aug 21, 2019
  • Contributors:
  • Slashek
  • diana-lakatos
  • pavelloz

This guide will help you build a working site on which one can find models in a maximum distance of X km's from given geo point coordinates.

GeoJSON is a geospatial data interchange format based on JSON for encoding a variety of geographic data structures. It defines several types of JSON objects and the manner in which they are combined to represent data about geographic features, their properties, and their spatial extents.

The following geometry types are supported:

  • Point [long, lan]

    {
      "type": "Point",
      "coordinates": [100.0, 0.0]
    }
    
  • LineString [[long, lan], [long, lan]]

    {
      "type": "LineString",
      "coordinates": [ [100.0, 0.0], [10.0, 10.0] ]
    }
    
  • Polygon [[[long, lan], [long, lan]]]

    {
      "type": "Polygon",
      "coordinates": [
        [[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]
       ]
    }
    
  • MultiPoint [[long, lan], [long, lan]]

    {
      "type": "MultiPoint",
      "coordinates": [ [100.0, 0.0], [10.0, 10.0] ]
    }
    

To learn more, read the official GeoJSON documentation.

Requirements

To follow the steps in this tutorial, you should be familiar with Model Schemas, data imports, and Form.

Steps

Using the GeoJSON format to find all models in a maximum distance from geopoint coordinates is a four-step process:

Step 1: Prepare Model Schema definition

Create model_schemas/company.yaml:

name: company
properties:
  - name: name
    type: string
  - name: timezone
    type: string
  - name: city
    type: string
  - name: location
    type: geojson

Step 2: Import data using GraphQL mutation

Create a GraphQL mutation createCompany.graphql:

mutation createCompany($location: JSONPayload, $city: String, $timezone: String, $name: String){
  customization_create(
    customization: {
      model_schema_name: "company"
      properties: [
        { name: "name" value: $name }
        { name: "city" value: $city }
        { name: "timezone" value: $timezone }
        { name: "location" value_json: $location }
      ]
    }
  ) {
    id
  }
}

Create a payload:

{
  "name": "Company Name",
    "city": "Boston",
    "timezone": "Timezone",
    "location": {
      "type": "Point",
      "coordinates": [-111.89903, 33.50921]
  }
}

Alternatively, you can create the record using a Form:

---
name: create_company
fields:
  properties:
    name:
      validation: { presence: true }
    city:
      validation: { presence: true }
    timezone:
      validation: { presence: true }
    location:
      validation: { geometry: true }

The HTML field snippet for geometry JSON is just a textarea:

<div class="form-group">
  <label for="location">Location</label>
  <textarea required="true" id="location" type="text" class="form-control" name="">
  </textarea>
</div>


Note


This example is for presentation only. In a real scenario, no one would provide a raw JSON as a location address — there would be a JavaScript function using external geolocation services for getting coordinates and then building the required GeometryJSON structure.

Step 3: Prepare GraphQL query

Create the GraphQL query graphql/search.graphql:

query search($point: GeometryJSON, $distance: Int) {
  companies: models(
    per_page: 20
    name: { value: "modules/geo_models/company" }
    filter: {
      properties: [
        { name: "location", distance_sphere: {center: $point, distance_in_km: $distance}}
      ]
    }) {
    results {
      properties
    }
  }
}

Step 4: Create page

To wrap it up, create a page views/pages/search.liquid:


---
slug: search
---
{% parse_json location %}
{
  "type": "Point",
  "coordinates": [
    -111.89903,
    33.50921
  ]
}
{% endparse_json %}
{% assign distance = context.params.distance | default: 100 | plus: 0 %}

{% graphql g = 'search', point: location, distance: distance %}

{% for company in g.companies.results %}
[...]
{% endfor %}


Note


Since the distance argument has to be an Integer and context.params.distance is a String, we have to cast this value to Integer.
You can do this by appending a plus filter with a 0 argument - literally adding a 0 converts a string into a number.

Live example and source code

Examples

Code samples

Questions?

We are always happy to help with any questions you may have.