A performant binary encoding for geospatial graphs, extending FlatGeobuf with adjacency list support
npm install flatgeographbufA performant binary encoding for geospatial graphs, extending FlatGeobuf with adjacency list support.
- Full FlatGeobuf compatibility for vertex/feature data
- Efficient binary encoding for graph edges with arbitrary properties
- TypeScript implementation optimized for decode performance
- Streaming support for large graphs
- Backward compatible - new properties don't break old readers
- Compatible with NPM graph libraries (graphology, ngraph, cytoscape, etc.)
``bash`
npm install flatgeographbuf
`typescript
import { serialize } from 'flatgeographbuf/geojson';
const geojson = {
type: 'FeatureCollection',
features: [
{ type: 'Feature', geometry: { type: 'Point', coordinates: [0, 0] }, properties: { name: 'A' } },
{ type: 'Feature', geometry: { type: 'Point', coordinates: [1, 1] }, properties: { name: 'B' } },
{ type: 'Feature', geometry: { type: 'Point', coordinates: [2, 2] }, properties: { name: 'C' } },
]
};
const adjacencyList = {
edges: [
{ from: 0, to: 1, properties: { weight: 1.5, road_type: 'highway' } },
{ from: 1, to: 2, properties: { weight: 2.0, road_type: 'local' } },
]
};
const bytes = serialize(geojson, adjacencyList);
`
`typescript
import { deserialize } from 'flatgeographbuf/geojson';
const result = await deserialize(bytes);
console.log(result.features); // GeoJSON features (vertices)
console.log(result.adjacencyList); // { edges: [...] }
`
`typescript
import { deserializeGraphEdges } from 'flatgeographbuf/geojson';
for await (const edge of deserializeGraphEdges(bytes)) {
console.log(Edge from ${edge.from} to ${edge.to});`
}
`typescript
interface EdgeInput {
from: number;
to: number;
properties?: EdgeProperties; // Optional on input
}
interface Edge {
from: number;
to: number;
properties: EdgeProperties; // Always present on output (empty {} if none)
}
interface EdgeProperties {
[key: string]: boolean | number | string | object | Uint8Array;
}
interface AdjacencyListInput {
edges: EdgeInput[];
}
interface AdjacencyList {
edges: Edge[];
}
interface DeserializeGraphResult
features: T[];
adjacencyList: AdjacencyList;
}
interface FeaturesHeaderMeta {
featuresCount: number;
columns: ColumnMeta[] | null;
geometryType: GeometryType;
envelope: Float64Array | null;
indexNodeSize: number;
crs: CrsMeta | null;
title: string | null;
description: string | null;
metadata: string | null;
}
interface GraphHeaderMeta {
edgeCount: number;
edgeColumns: ColumnMeta[] | null;
}
interface FlatGeoGraphBufMeta {
features: FeaturesHeaderMeta;
graph: GraphHeaderMeta | null;
}
type FlatGeoGraphBufMetaFn = (meta: FlatGeoGraphBufMeta) => void;
`
#### serialize(geojson, adjacencyList?, crsCode?): Uint8Array
Serialize GeoJSON features and optional graph edges to FlatGeoGraphBuf format.
- geojson - GeoJSON FeatureCollection (vertices)adjacencyList
- - Optional graph edges with propertiescrsCode
- - Optional CRS code (default: 0)
#### deserialize(bytes, metaFn?): Promise
Deserialize FlatGeoGraphBuf to features and adjacency list.
- bytes - FlatGeoGraphBuf binary datametaFn
- - Optional callback receiving combined feature and graph metadata
`typescript`
await deserialize(bytes, (meta) => {
// Feature metadata (nested under 'features')
console.log(meta.features.featuresCount); // number of features
console.log(meta.features.columns); // ColumnMeta[] - feature property schema
// Graph metadata (null if no graph section)
if (meta.graph) {
console.log(meta.graph.edgeCount); // number of edges
console.log(meta.graph.edgeColumns); // ColumnMeta[] - edge property schema
}
});
#### deserializeStream(input, rect?, headerMetaFn?): AsyncGenerator
Streaming deserialize features only.
- input - Uint8Array or ReadableStreamrect
- - Optional bounding box filterheaderMetaFn
- - Optional callback for header metadata
#### deserializeGraphEdges(bytes): AsyncGenerator
Streaming deserialize graph edges only.
FlatGeoGraphBuf uses FlatGeobuf's encoding for features and appends an optional graph section:
``
[FGG Magic: 8B] [Header: 4B+var] [Index?] [Features...] [Graph Section?]
- FGG Magic: 0x6667670166676700 ("fgg\x01fgg\x00")[Header Size: 4B] [Graph Header] [Edges...]
- Header/Features: Same encoding as FlatGeobuf
- Graph Section: [from: 4B][to: 4B][properties...]`
- Graph Header: Edge count + edge column schema
- Edges: Size-prefixed records with
Edge properties use the same encoding as FlatGeobuf feature properties, supporting:
- Boolean, integers (8/16/32/64 bit signed/unsigned)
- Float, Double
- String, DateTime, JSON, Binary
See doc/format-spec.md for detailed specification.
FlatGeoGraphBuf inherits FlatGeobuf's performance characteristics:
- Zero-copy deserialization where possible
- Size-prefixed records for efficient streaming
- No compression overhead (can be compressed externally)
The graph section is optimized for decode performance:
- Fixed-size edge header (from/to indices)
- Same property encoding as features (proven efficient)
- Sequential edge reading
- Road networks with intersection/segment topology
- Utility networks (power, water, telecom)
- Transportation graphs (routes, connections)
- Any geospatial graph where features represent nodes and edges represent relationships
BSD-3-Clause
Based on FlatGeobuf by Bjorn Harrtell.