www.xbdev.net
xbdev - software development
Sunday June 1, 2025
Home | Contact | Support | GeoJSON File Format Spatial Geographic Data Structures ...
     
 

GeoJSON File Format

Spatial Geographic Data Structures ...

 

GeoJSON Format (3D Data)


The GeoJSON format is a json file which contains geographic informtion (e.g., lines, points and so on) and their properties and spatial extents.

Example of what the inside of a GeoJSON file looks like:

{
  
"type""Feature",
  
"geometry": {
    
"type""Point",
    
"coordinates": [125.610.1]
  },
  
"properties": {
    
"name""Dinagat Islands"
  
}
}


The great thing is - because the GeoJSON file is a `json` file - it means it acn be parsed easily using the builtin JavaScript json functions (e.g.,
JSON.parse(..) 
).


Interactive Map


Example of using the GeoJSON data to create an interactive map (viewing world data).


Example loading and using the GeoJSON data to create a 3d interactive visualization.
Example loading and using the GeoJSON data to create a 3d interactive visualization.


Looking Inside


We can start of by loading a GeoJSON file (one of the basic world map resource) - after loading - we'll parse the data then loop over and dump the name of all the top level objects:

// Load GeoJSON data (using a simplified world map)
const response await fetch('https://raw.githubusercontent.com/nvkelso/natural-earth-vector/master/geojson/ne_110m_admin_0_countries.geojson');
const 
geoDataRaw await response.text();
const 
geoData JSON.parsegeoDataRaw );

console.log('size file:'geoDataRaw.length );

for (
o in geoData
{
    
console.log);
}


The output written to the console is this:

log:["size file:",815562]
log:["type"]
log:["name"]
log:["crs"]
log:["features"]
log:["bbox"]


If we look at the official specification, we can get information for what these objects are:

• "type" (Standard GeoJSON Property) Indicates the type of GeoJSON object (e.g., feature collection, point, ...)
• "name" - metadata field for information (e.g., name of the file)
• "crs" (Coordinate Reference System, Optional in GeoJSON) - defines the spatial reference system (e.g., "EPSG:4326" for WGS84). Modern GeoJSON defaults to WGS84 (longitude/latitude), so "crs" is often omitted.
• "features" (Standard in FeatureCollection) - An array of GeoJSON Feature objects (each containing a geometry and properties). This is only present if "type": "FeatureCollection".

We can do a bit better and modify the code so it prints out the contents of each objects. We modify the loop:

for (o in geoData
{
    
console.log' : ' geoData] );
}


This outputs:

log:["size file:",815562]
log:["type : FeatureCollection"]
log:["name : ne_110m_admin_0_countries"]
log:["crs : [object Object]"]
log:["features : [object Object],[object Object],[object Object],........ .... ..."]
log:["bbox : -180,-90,180,83.64513"]


The `features` object contains 117 objects (
console.log( geoData[ 'features' ].length )
). We show this as '...'.

If we look at the first
feature
object - and dump the object names, we get:

for ( o in geoData'features' ][ ] )
{
      
console.log'  ' )
}


The output:

log:["  type"]
log:["  properties"]
log:["  bbox"]
log:["  geometry"]


As you can see we can have objects of objects (nested information).

If we print out the contents for these object as we did with the parent, we get:

for ( o in geoData'features' ][ ] )
{
      
console.log'  ' +  ' : ' geoData'features' ][ ][o] )
}


Get the output:

log:["  type : Feature"]
log:["  properties : [object Object]"]
log:["  bbox : -180,-18.28799,180,-16.020882"]
log:["  geometry : [object Object]"]


The geometry object is the data for the positions (shape). Let's take a look at what's inside a geometry object:

console.loggeoData'features' ][ ][ 'geometry'] )


The output is shown below:

log:[{"type":"MultiPolygon","coordinates":[[[[180,-16.067133],[180,-16.555217],[179.364143,-16.801354],[178.725059,-17.012042],[178.596839,-16.63915],[179.096609,-16.433984],[179.413509,-16.379054],[180,-16.067133]]],[[[178.12557,-17.50481],[178.3736,-17.33992],[178.71806,-17.62846],[178.55271,-18.15059],[177.93266,-18.28799],[177.38146,-18.16432],[177.28504,-17.72465],[177.67087,-17.38114],[178.12557,-17.50481]]],[[[-179.79332,-16.020882],[-179.917369,-16.501783],[-180,-16.555217],[-180,-16.067133],[-179.79332,-16.020882]]]]}]


All geometry objects must have a type and a coordinates array.

• "type": Specifies the geometry type (e.g., "Point", "LineString", "Polygon", "MultiPolygon", etc.).

• "coordinates": An array defining the vertices of the geometry. The structure varies by type.


As you can see - our example is a MultiPolygon - which represents multiple distinct polygons (e.g., islands, disjoint regions). Its coordinates are a 3D array structured as:

{
  
"type""MultiPolygon",
  
"coordinates": [
    [ 
/* Polygon 1 */ ],  
    [ 
/* Polygon 2 */ ],
    [ 
/* ... */ ]
  ]
}

Each Polygon follows these rules:

• The first ring is the exterior boundary.
• Subsequent rings (if any) are holes inside the exterior.
• Each ring must be closed (first and last points are identical).

Now we can write a simple canvas to draw the polygon data. If it's a
MultiPolygon
we only draw the first Polygon for the exterior boundary. If it's just a
Polygon
we just draw it. The data inside a Polygon is just an array of points which we can conenct together using a line drawing function.


Draw a line for the polygon object points - connect together the points.
Draw a line for the polygon object points - connect together the points.


We also need to create a
project
function which converts geographic coordinates (longitude and latitude) into canvas pixel coordinates so they can be drawn on an HTML5
<canvas>
.

// Set up canvas
let canvas document.createElement('canvas');
canvas.width canvas.height 512;
document.body.appendChild(canvas);
const 
ctx canvas.getContext('2d');

// Normalize coordinates to fit canvas
function project(lonlat) {
  
// Mercator-like projection (simplified)
  
const = (lon 180) * (canvas.width 360);
  const 
= (90 lat) * (canvas.height 180);
  return { 
x};
}

// Draw the exterior ring of the first polygon
function drawPolygonExteriorpolygon ) {
  
ctx.beginPath();

  
// Start from the first point
  
const start project(polygon[0][0], polygon[0][1]);
  
ctx.moveTo(start.xstart.y);

  
// Draw lines to subsequent points
  
for (let i 1polygon.lengthi++) {
    const [
lonlat] = polygon[i];
    const { 
x} = project(lonlat);
    
ctx.lineTo(xy);
  }

  
// Style
  
ctx.strokeStyle '#FF0000';
  
ctx.lineWidth 2;
  
ctx.stroke();
  
ctx.closePath();
}

for (
let i=0i<geoData'features' ].lengthi++)
{
      
let geometryobject geoData'features' ][ ][ 'geometry' ];
  
    
console.log('geometryobject.type:'geometryobject.type );
    if ( 
geometryobject.type == 'MultiPolygon' )
    {
        const 
polygon geometryobject.coordinates[0][0]; // First polygon's exterior ring
        
drawPolygonExteriorpolygon );
    }
    if ( 
geometryobject.type == 'Polygon' )
    {
        
drawPolygonExteriorgeometryobject.coordinates[0] );
    }
}


We're drawing the geometric data as lines - if we want to draw the polygons as solid shapes - we need to trianglulate the shape. As the shape is not convex this can be a bit more complex (do more than a convex hull wrapping algorithm).

Loading Data (Triangles)


The following gives you a working eample of loading in the map data from a geojson file (parsing and converting it into triangles) which can be rendered using WebGL or WebGPU.

// Load GeoJSON data (using a simplified world map)
const response await fetch('https://raw.githubusercontent.com/nvkelso/natural-earth-vector/master/geojson/ne_110m_admin_0_countries.geojson');
const 
geoData await response.json();

// Process GeoJSON into triangle data
const positions = []; // flattened array of triangle vertices
const countryIds = []; // country index per vertex
const countryInfo = []; // metadata for each country

let countryIndex 0;
for (const 
feature of geoData.features) {
    const 
properties feature.properties;
    
    
// Store country info
    
countryInfo.push({
        
nameproperties.NAME || properties.NAME_LONG || 'Unnamed',
        
isoproperties.ISO_A2 || '',
        
populationproperties.POP_EST || 0,
        
gdpproperties.GDP_MD_EST || 0
    
});

    
// Handle different geometry types
    
const geometry feature.geometry;
    if (
geometry.type === 'Polygon') {
        
processPolygon(geometry.coordinatescountryIndex);
    } else if (
geometry.type === 'MultiPolygon') {
        for (const 
polygon of geometry.coordinates) {
            
processPolygon(polygoncountryIndex);
        }
    }

    
countryIndex++;
}

// Helper function to process a single polygon (with possible holes)
function processPolygon(coordinatescountryIdx) {
    
// The first ring is the exterior, others are holes
    
const exteriorRing coordinates[0];
    
    
// Convert polygon to triangles using ear clipping algorithm
    
const triangles earClip(exteriorRing);
    
    
// Add the triangles to our buffers
    
for (const triangle of triangles) {
        for (const [
xyof triangle) {
            
positions.push(xy);
            
countryIds.push(countryIdx);
        }
    }
    
    
// TODO: Handle holes - would need to clip them from the exterior
}

// Simple ear-clipping triangulation for convex polygons
function earClip(polygon) {
    const 
triangles = [];
    const 
vertices polygon.slice();
    
    
// Remove duplicate last point if it exists
    
if (vertices.length && 
        
vertices[0][0] === vertices[vertices.length-1][0] && 
        
vertices[0][1] === vertices[vertices.length-1][1]) {
        
vertices.pop();
    }
    
    
// For convex polygons, we can just fan triangulate
    
if (vertices.length >= 3) {
        for (
let i 1vertices.length 1i++) {
            
triangles.push([
                
vertices[0],
                
vertices[i],
                
vertices[1]
            ]);
        }
    }
    
    return 
triangles;
}

console.log({ positionscountryIdscountryInfo });






Resource & Links


GeoJSON Specification Details

* Interactive World Map





Ray-Tracing with WebGPU kenwright WebGPU Development Cookbook - coding recipes for all your webgpu needs! WebGPU by Example: Fractals, Image Effects, Ray-Tracing, Procedural Geometry, 2D/3D, Particles, Simulations WebGPU Games WGSL 2d 3d interactive web-based fun learning WebGPU Compute WebGPU API - Owners WebGPU & WGSL Essentials: A Hands-On Approach to Interactive Graphics, Games, 2D Interfaces, 3D Meshes, Animation, Security and Production Kenwright graphics and animations using the webgpu api 12 week course kenwright learn webgpu api kenwright programming compute and graphics applications with html5 and webgpu api kenwright real-time 3d graphics with webgpu kenwright webgpu for dummies kenwright webgpu api develompent a quick start guide kenwright webgpu by example 2022 kenwright webgpu gems kenwright webgpu interactive compute and graphics visualization cookbook kenwright wgsl webgpu shading language cookbook kenwright WebGPU Shader Language Development: Vertex, Fragment, Compute Shaders for Programmers Kenwright wgsl webgpugems shading language cookbook kenwright WGSL Fundamentals book kenwright WebGPU Data Visualization Cookbook kenwright Special Effects Programming with WebGPU kenwright WebGPU Programming Guide: Interactive Graphics and Compute Programming with WebGPU & WGSL kenwright



 
Advert (Support Website)

 
 Visitor:
Copyright (c) 2002-2025 xbdev.net - All rights reserved.
Designated articles, tutorials and software are the property of their respective owners.