ngageoint / geopackage-js

GeoPackage JavaScript Library
http://ngageoint.github.io/geopackage-js/
MIT License
304 stars 78 forks source link

Example: Create a new GeoPackage #185

Open bertday opened 1 year ago

bertday commented 1 year ago

Hello — thank you for this awesome library!

I am a new user and would like to know how to create a new, empty GeoPackage. I'm having some trouble hunting down an example of how to do this. I see there a method GeoPackageAPI.create(), but it's not entirely clear to me how to use it. When I run this code:

import { GeoPackageAPI } from '@ngageoint/geopackage';

(async () => {
  const gpkg = await GeoPackageAPI.create('/Users/me/test.gpkg');
})(); 

I get Error: Unable to initialize canvas.

Having a minimal example of this would be super helpful — thank you!

danbritt commented 1 year ago

In the docs for using it with node, it says you have to import setCanvasKitWasmLocateFile and then use it and return the path to the file like this

setCanvasKitWasmLocateFile(file => 'path/to/geopackage/dist/canvaskit/' + file);

Your example would change to:

import { GeoPackageAPI, setCanvasKitWasmLocateFile } from '@ngageoint/geopackage';

(async () => {
  setCanvasKitWasmLocateFile(file => 'path/to/geopackage/dist/canvaskit/' + file);
  const gpkg = await GeoPackageAPI.create('/Users/me/test.gpkg');
})();

However, I have done this and it still doesn't work. I still get Error: Unable to initialize canvas. So I'm not sure if something is broken or what. I have even returned the full absolute path to the canvaskit.wasm file and it still says it can't initialize.

danbritt commented 1 year ago

So it looks like you don't need the canvas stuff if all you want is to create a geopackage with geojson features in it, which is what I needed to do. You can just make it think it's initialized by using CanvasKitCanvasAdapter.initialized = true;. Here is an example:

index.mjs

import geoJson from './geoJson.json' assert { type: 'json' };
import {
    GeoPackageAPI,
    FeatureColumn,
    GeometryColumns,
    GeoPackageDataType,
    BoundingBox,
    GeometryType,
    CanvasKitCanvasAdapter,
} from '@ngageoint/geopackage';

(async () => {
    // Fake that the canvas is initialized, since it doesn't seem to initialize in a node environment
    CanvasKitCanvasAdapter.initialized = true;

    const gpkg = await GeoPackageAPI.create('./test.gpkg');

    // Check GeoPackageDataType enum for these values
    let fields = [
        { name: 'ID', typeName: 'TEXT' },
        { name: 'Count', typeName: 'INT' },
        { name: 'ItemNumber', typeName: 'TEXT' }
    ];

    let geomTypeName = 'POINT'; // Check GeometryType enum for these values 
    let tableName = 'MyLayer';
    let srId = 4326;
    let geomColName = 'SHAPE';
    let geomTypeId = GeometryType.fromName(geomTypeName);

    let geometryColumns = new GeometryColumns();
    geometryColumns.table_name = tableName;
    geometryColumns.column_name = geomColName;
    geometryColumns.geometry_type_name = geomTypeName;
    geometryColumns.z = 2;
    geometryColumns.m = 2;

    let columns = [];
    // Need to create an int auto increment ID for the sqlite db. Not sure if it can use guids
    columns.push(FeatureColumn.createPrimaryKeyColumn(0, 'NID', true));
    columns.push(
        FeatureColumn.createGeometryColumn(
            1,
            'SHAPE',
            geomTypeId,
            true,
            null
        )
    );
    let colIndex = 2;

    // Add other columns
    for (let field of fields) {
        let fieldTypeId = GeoPackageDataType.fromName(field.typeName);

        columns.push(
            FeatureColumn.createColumn(
                colIndex,
                field.name,
                fieldTypeId,
                false,
                null
            )
        );
        colIndex++;
    }

    let bbox = new BoundingBox(-180, 180, -90, 90);

    gpkg.createFeatureTable(
        tableName,
        geometryColumns,
        columns,
        bbox,
        srId
    );

    await gpkg.addGeoJSONFeaturesToGeoPackage(
        geoJson.features,
        tableName
    );

    gpkg.close();

})();

geoJson.json

{
   "type":"FeatureCollection",
   "features":[
      {
         "type":"Feature",
         "geometry":{
            "type":"Point",
            "coordinates":[
               -84.336016,
               35.906206
            ]
         },
         "properties":{
            "ID":"97bbf51e-0262-4439-a217-00b3dc282bdc",
            "Count":2,
            "ItemNumber":"Item1"
         }
      },
      {
         "type":"Feature",
         "geometry":{
            "type":"Point",
            "coordinates":[
               -84.386671,
               35.943449
            ]
         },
         "properties":{
            "ID":"9642775c-3dee-4906-8411-8040e9f3329c",
            "Count":1,
            "ItemNumber":"Item2"
         }
      },
      {
         "type":"Feature",
         "geometry":{
            "type":"Point",
            "coordinates":[
               -84.301242,
               35.943728
            ]
         },
         "properties":{
            "ID":"022d12fa-f156-4ca4-9713-e5df67c078ee",
            "Count":4,
            "ItemNumber":"Item3"
         }
      },
      {
         "type":"Feature",
         "geometry":{
            "type":"Point",
            "coordinates":[
               -84.360066,
               35.950069
            ]
         },
         "properties":{
            "ID":"98841440-789b-4441-9640-b00cc1405e75",
            "Count":8,
            "ItemNumber":"Item4"
         }
      },
      {
         "type":"Feature",
         "geometry":{
            "type":"Point",
            "coordinates":[
               -84.317448,
               35.914034
            ]
         },
         "properties":{
            "ID":"f2af3539-697a-454a-a484-0b8978556f4e",
            "COUNT":11,
            "ItemNumber":"Item5"
         }
      }
   ],
   "totalFeatures":5,
   "numberMatched":5,
   "numberReturned":5,
   "timeStamp":"2023-01-19T04:19:42.308Z",
   "crs":{
      "type":"name",
      "properties":{
         "name":"urn:ogc:def:crs:EPSG::4326"
      }
   }
}

These are the resources I used to figure this out:

Example: https://github.com/ngageoint/geopackage-csv-js/blob/main/index.ts

Useful Docs: https://ngageoint.github.io/geopackage-js/api/modules/GeometryType.html https://ngageoint.github.io/geopackage-js/api/enums/GeometryType.html https://ngageoint.github.io/geopackage-js/api/modules/GeoPackageDataType.html https://ngageoint.github.io/geopackage-js/api/enums/GeoPackageDataType.html https://ngageoint.github.io/geopackage-js/api/classes/GeometryColumns.html https://ngageoint.github.io/geopackage-js/api/classes/FeatureColumn.html https://ngageoint.github.io/geopackage-js/api/classes/GeoPackage.html