@loaders.gl/geopackage
Version:
GeoPackage data loaders
311 lines (307 loc) • 9.69 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// dist/index.js
var dist_exports = {};
__export(dist_exports, {
GeoPackageLoader: () => GeoPackageLoader
});
module.exports = __toCommonJS(dist_exports);
// dist/lib/parse-geopackage.js
var import_loader_utils = require("@loaders.gl/loader-utils");
var import_wkt = require("@loaders.gl/wkt");
var import_gis = require("@loaders.gl/gis");
var import_proj4 = require("@math.gl/proj4");
var import_sql = __toESM(require("sql.js"), 1);
var SQL_JS_VERSION = "1.8.0";
var DEFAULT_SQLJS_CDN = import_loader_utils.isBrowser ? `https://cdnjs.cloudflare.com/ajax/libs/sql.js/${SQL_JS_VERSION}/` : null;
var ENVELOPE_BYTE_LENGTHS = {
0: 0,
1: 32,
2: 48,
3: 48,
4: 64,
// values 5-7 are invalid and _should_ never show up
5: 0,
6: 0,
7: 0
};
var SQL_TYPE_MAPPING = {
BOOLEAN: "bool",
TINYINT: "int8",
SMALLINT: "int16",
MEDIUMINT: "int32",
INT: "int32",
INTEGER: "int32",
FLOAT: "float32",
DOUBLE: "float64",
REAL: "float64",
TEXT: "utf8",
BLOB: "binary",
DATE: "utf8",
DATETIME: "utf8",
GEOMETRY: "binary",
POINT: "binary",
LINESTRING: "binary",
POLYGON: "binary",
MULTIPOINT: "binary",
MULTILINESTRING: "binary",
MULTIPOLYGON: "binary",
GEOMETRYCOLLECTION: "binary"
};
async function parseGeoPackage(arrayBuffer, options) {
var _a;
const { sqlJsCDN = DEFAULT_SQLJS_CDN } = (options == null ? void 0 : options.geopackage) || {};
const { reproject = false, _targetCrs = "WGS84" } = (options == null ? void 0 : options.gis) || {};
const db = await loadDatabase(arrayBuffer, sqlJsCDN);
const tables = listVectorTables(db);
const projections = getProjections(db);
const selectedTable = tables.find((table) => {
var _a2;
return table.table_name === ((_a2 = options == null ? void 0 : options.geopackage) == null ? void 0 : _a2.table);
});
const tableName = selectedTable ? selectedTable.table_name : tables[0].table_name;
const shape = (_a = options == null ? void 0 : options.geopackage) == null ? void 0 : _a.shape;
switch (shape) {
case "geojson-table":
return getVectorTable(db, tableName, projections, {
reproject,
_targetCrs
});
case "tables":
const outputTables = {
shape: "tables",
tables: []
};
for (const table of tables) {
const { table_name: tableName2 } = table;
outputTables.tables.push({
name: tableName2,
table: getVectorTable(db, tableName2, projections, {
reproject,
_targetCrs
})
});
}
return outputTables;
default:
throw new Error(shape);
}
}
async function loadDatabase(arrayBuffer, sqlJsCDN) {
let SQL;
if (sqlJsCDN) {
SQL = await (0, import_sql.default)({
locateFile: (file) => `${sqlJsCDN}${file}`
});
} else {
SQL = await (0, import_sql.default)();
}
return new SQL.Database(new Uint8Array(arrayBuffer));
}
function listVectorTables(db) {
const stmt = db.prepare("SELECT * FROM gpkg_contents WHERE data_type='features';");
const vectorTablesInfo = [];
while (stmt.step()) {
const vectorTableInfo = stmt.getAsObject();
vectorTablesInfo.push(vectorTableInfo);
}
return vectorTablesInfo;
}
function getVectorTable(db, tableName, projections, { reproject, _targetCrs }) {
const dataColumns = getDataColumns(db, tableName);
const geomColumn = getGeometryColumn(db, tableName);
const featureIdColumn = getFeatureIdName(db, tableName);
const { columns, values } = db.exec(`SELECT * FROM \`${tableName}\`;`)[0];
let projection;
if (reproject) {
const geomColumnProjStr = projections[geomColumn.srs_id];
projection = new import_proj4.Proj4Projection({
from: geomColumnProjStr,
to: _targetCrs
});
}
const geojsonFeatures = [];
for (const row of values) {
const geojsonFeature = constructGeoJsonFeature(
columns,
row,
geomColumn,
// @ts-ignore
dataColumns,
featureIdColumn
);
geojsonFeatures.push(geojsonFeature);
}
const schema = getSchema(db, tableName);
if (projection) {
return {
shape: "geojson-table",
type: "FeatureCollection",
// @ts-expect-error TODO - null geometries causing problems...
features: (0, import_gis.transformGeoJsonCoords)(geojsonFeatures, projection.project),
schema
};
}
return {
shape: "geojson-table",
schema,
type: "FeatureCollection",
// @ts-expect-error TODO - null features
features: geojsonFeatures
};
}
function getProjections(db) {
const stmt = db.prepare("SELECT * FROM gpkg_spatial_ref_sys;");
const projectionMapping = {};
while (stmt.step()) {
const srsInfo = stmt.getAsObject();
const { srs_id, definition } = srsInfo;
projectionMapping[srs_id] = definition;
}
return projectionMapping;
}
function constructGeoJsonFeature(columns, row, geomColumn, dataColumns, featureIdColumn) {
const idIdx = columns.indexOf(featureIdColumn);
const id = row[idIdx];
const geomColumnIdx = columns.indexOf(geomColumn.column_name);
const geometry = parseGeometry(row[geomColumnIdx].buffer);
const properties = {};
if (dataColumns) {
for (const [key, value] of Object.entries(dataColumns)) {
const idx = columns.indexOf(key);
properties[value] = row[idx];
}
} else {
for (let i = 0; i < columns.length; i++) {
if (i === idIdx || i === geomColumnIdx) {
continue;
}
const columnName = columns[i];
properties[columnName] = row[i];
}
}
return {
id,
type: "Feature",
geometry,
properties
};
}
function getFeatureIdName(db, tableName) {
const stmt = db.prepare(`PRAGMA table_info(\`${tableName}\`)`);
while (stmt.step()) {
const pragmaTableInfo = stmt.getAsObject();
const { name, pk } = pragmaTableInfo;
if (pk) {
return name;
}
}
return null;
}
function parseGeometry(arrayBuffer) {
var _a, _b;
const view = new DataView(arrayBuffer);
const { envelopeLength, emptyGeometry } = parseGeometryBitFlags(view.getUint8(3));
if (emptyGeometry) {
return null;
}
const wkbOffset = 8 + envelopeLength;
const binaryGeometry = (_b = (_a = import_wkt.WKBLoader).parseSync) == null ? void 0 : _b.call(_a, arrayBuffer.slice(wkbOffset));
return (0, import_gis.binaryToGeometry)(binaryGeometry);
}
function parseGeometryBitFlags(byte) {
const envelopeValue = (byte & 14) / 2;
const envelopeLength = ENVELOPE_BYTE_LENGTHS[envelopeValue];
return {
littleEndian: Boolean(byte & 1),
envelopeLength,
emptyGeometry: Boolean(byte & 16),
extendedGeometryType: Boolean(byte & 32)
};
}
function getGeometryColumn(db, tableName) {
const stmt = db.prepare("SELECT * FROM gpkg_geometry_columns WHERE table_name=:tableName;");
stmt.bind({ ":tableName": tableName });
stmt.step();
const geometryColumn = stmt.getAsObject();
return geometryColumn;
}
function getDataColumns(db, tableName) {
let stmt;
try {
stmt = db.prepare("SELECT * FROM gpkg_data_columns WHERE table_name=:tableName;");
} catch (error) {
if (error.message.includes("no such table")) {
return null;
}
throw error;
}
stmt.bind({ ":tableName": tableName });
const result = {};
while (stmt.step()) {
const column = stmt.getAsObject();
const { column_name, name } = column;
result[column_name] = name || null;
}
return result;
}
function getSchema(db, tableName) {
const stmt = db.prepare(`PRAGMA table_info(\`${tableName}\`)`);
const fields = [];
while (stmt.step()) {
const pragmaTableInfo = stmt.getAsObject();
const { name, type: sqlType, notnull } = pragmaTableInfo;
const type = SQL_TYPE_MAPPING[sqlType];
const field = { name, type, nullable: !notnull };
fields.push(field);
}
return { fields, metadata: {} };
}
// dist/geopackage-loader.js
var VERSION = "latest";
var GeoPackageLoader = {
dataType: null,
batchType: null,
id: "geopackage",
name: "GeoPackage",
module: "geopackage",
version: VERSION,
extensions: ["gpkg"],
mimeTypes: ["application/geopackage+sqlite3"],
category: "geometry",
parse: parseGeoPackage,
options: {
geopackage: {
sqlJsCDN: DEFAULT_SQLJS_CDN,
shape: "tables"
},
gis: {}
}
};
//# sourceMappingURL=index.cjs.map