diff --git a/docs/docs-sidebar.json b/docs/docs-sidebar.json index 6abb9ad9da..d83d2129e3 100644 --- a/docs/docs-sidebar.json +++ b/docs/docs-sidebar.json @@ -131,6 +131,7 @@ "modules/3d-tiles/api-reference/cesium-ion-loader", "modules/arrow/api-reference/arrow-loader", "modules/arrow/api-reference/arrow-writer", + "modules/arrow/api-reference/geoarrow-loader", "modules/bson/api-reference/bson-loader", "modules/bson/api-reference/bson-writer", "modules/csv/api-reference/csv-loader", diff --git a/docs/modules/arrow/api-reference/geoarrow-loader.md b/docs/modules/arrow/api-reference/geoarrow-loader.md index ca4b8aa227..0a98b6dab8 100644 --- a/docs/modules/arrow/api-reference/geoarrow-loader.md +++ b/docs/modules/arrow/api-reference/geoarrow-loader.md @@ -2,6 +2,10 @@ ![arrow-logo](../images/apache-arrow-small.png) +

+ From-v4.1 +

+ The `GeoArrowLoader` parses Apache Arrow columnar table format files, and looks for `GeoArrow` type extensions to parse geometries from the table. | Loader | Characteristic | diff --git a/docs/modules/arrow/formats/geoarrow.md b/docs/modules/arrow/formats/geoarrow.md index 38ed71f5a7..b79835d986 100644 --- a/docs/modules/arrow/formats/geoarrow.md +++ b/docs/modules/arrow/formats/geoarrow.md @@ -22,22 +22,22 @@ Geospatial tabular data where one or more columns contains feature geometries an Note that GeoArrow is not a separate format from Apache Arrow rather, the GeoArrow specification simply describes additional conventions for metadata and layout of geospatial data. This means that a valid GeoArrow file is always a valid Arrow file. This is done through [Arrow extension type](https://arrow.apache.org/docs/format/Columnar.html#extension-types) definitions that ensure type-level metadata (e.g., CRS) is propagated when used in Arrow implementations. +## Geometry Types + +| Geometry type | Read | Write | Description | +| -------------------------- | ---- | ----- | -------------------- | +| `geoarrow.point` | ✅ | ❌ | | +| `geoarrow.multipoint` | ✅ | ❌ | | +| `geoarrow.linestring` | ✅ | ❌ | | +| `geoarrow.multilinestring` | ✅ | ❌ | | +| `geoarrow.polygon` | ✅ | ❌ | | +| `geoarrow.multipolygon` | ✅ | ❌ | | +| `geoarrow.wkb` | ✅ | ❌ | `WKB` also supported | +| `geoarrow.wkt` | ✅ | ❌ | `WKT` also supported | + ## Relationship with GeoParquet -The [GeoParquet specification](https://github.com/opengeospatial/geoparquet) is closely related to GeoArrow. Notable differences: +The [GeoParquet](/docs/modules/parquet/formats/geoparquet) [specification](https://github.com/opengeospatial/geoparquet) is closely related to GeoArrow. Notable differences: - GeoParquet is a file-level metadata specification - GeoArrow is a field-level metadata and memory layout specification - -## Geometry Types - -| Geometry type | Read | Write | Description | -| -------------------------- | ---- | ----- | ----------- | -| `geoarrow.multipolygon` | ✅ | ❌ | | -| `geoarrow.polygon` | ✅ | ❌ | | -| `geoarrow.multipoint` | ✅ | ❌ | | -| `geoarrow.point` | ✅ | ❌ | | -| `geoarrow.multilinestring` | ✅ | ❌ | | -| `geoarrow.linestring` | ✅ | ❌ | | -| `geoarrow.wkb` | ❌ | ❌ | | -| `geoarrow.wkt` | ❌ | ❌ | | \ No newline at end of file diff --git a/examples/website/geospatial/app.tsx b/examples/website/geospatial/app.tsx index 3f3f3daa21..92013ce6e6 100644 --- a/examples/website/geospatial/app.tsx +++ b/examples/website/geospatial/app.tsx @@ -5,14 +5,14 @@ import React, {useState, useEffect} from 'react'; import {createRoot} from 'react-dom/client'; import {Map} from 'react-map-gl'; -import maplibregl from 'maplibre-gl'; +import maplibregl, {Properties} from 'maplibre-gl'; import {DeckGL} from '@deck.gl/react/typed'; import {MapController} from '@deck.gl/core/typed'; import {GeoJsonLayer} from '@deck.gl/layers/typed'; import {ControlPanel} from './components/control-panel'; -import {FileUploader} from './components/file-uploader'; +// import {FileUploader} from './components/file-uploader'; import type {Example} from './examples'; import {INITIAL_LOADER_NAME, INITIAL_EXAMPLE_NAME, INITIAL_MAP_STYLE, EXAMPLES} from './examples'; @@ -22,12 +22,12 @@ import {Loader, load /* registerLoaders */} from '@loaders.gl/core'; import {ParquetLoader, installBufferPolyfill} from '@loaders.gl/parquet'; import {FlatGeobufLoader} from '@loaders.gl/flatgeobuf'; // import {GeoPackageLoader} from '@loaders.gl/geopackage'; -import {ArrowLoader} from '@loaders.gl/arrow'; +import {GeoArrowLoader} from '@loaders.gl/arrow'; installBufferPolyfill(); const LOADERS: Loader[] = [ - ArrowLoader, + GeoArrowLoader, ParquetLoader, FlatGeobufLoader // GeoPackageLoader @@ -76,15 +76,14 @@ type AppState = { }; /** - * + * A Geospatial table map viewer */ export default function App(props: AppProps) { - const [state, setState] = useState({ // EXAMPLE STATE examples: EXAMPLES, - selectedExample: INITIAL_EXAMPLE_NAME, - selectedLoader: INITIAL_LOADER_NAME, + selectedExample: null, + selectedLoader: null, // CURRENT VIEW POINT / CAMERA POSITION viewState: INITIAL_VIEW_STATE, @@ -96,74 +95,75 @@ export default function App(props: AppProps) { useEffect(() => { let examples: Record> = {...EXAMPLES}; if (props.format) { - // Move the preferred format examples to the "top" - examples = {[props.format]: EXAMPLES[props.format], ...EXAMPLES}; - // Remove any keys - for (const key of Object.keys(examples)) { - if (key.endsWith('Test')) { - delete examples[key]; - } - } + // Keep only the preferred format examples + examples = {[props.format]: EXAMPLES[props.format]}; } const selectedLoader = props.format || INITIAL_LOADER_NAME; + let selectedExample = props.format + ? Object.keys(examples[selectedLoader])[0] + : INITIAL_EXAMPLE_NAME; - let selectedExample = INITIAL_EXAMPLE_NAME; - if (props.format) { - for (const exampleName of Object.keys(examples[selectedLoader])) { - selectedExample = exampleName; - break; - } - } - setState({...state, examples, selectedExample, selectedLoader}); + onExampleChange({selectedLoader, selectedExample, example: examples[selectedLoader][selectedExample], state, setState}); + setState(state => ({...state, examples, selectedExample, selectedLoader})); }, [props.format]); + let schema = state.loadedTable?.schema ? {metadata: state.loadedTable?.schema.metadata, ... state.loadedTable?.schema} : null; + return (
- onExampleChange({...props, state, setState})} + onExampleChange={(props) => onExampleChange({...props, state, setState})} > {state.error ?
{state.error}
: ''}
center long/lat: {state.viewState.longitude.toFixed(3)}, - {state.viewState.latitude.toFixed(3)}, - zoom: {state.viewState.zoom.toFixed(2)} + {state.viewState.latitude.toFixed(3)}, zoom: {state.viewState.zoom.toFixed(2)}
- setState({...state, loadedTable: null})} - onFileSelected={async (uploadedFile: File) => { + { + /* TODO -restore drag and drop + setState(state => ({...state, loadedTable: null}))} + onFileSelected={async (uploadedFile: File) => { // TODO - error handling const data = (await load(uploadedFile, LOADERS, LOADER_OPTIONS)) as Table; - setState({ + setState(state => ({ ...state, selectedExample: uploadedFile.name, loadedTable: data - }); - }} + })); + }} /> + */}
setState({...state, viewState})} + onViewStateChange={({viewState}) => setState(state => ({...state, viewState}))} controller={{type: MapController, maxPitch: 85}} - getTooltip={({object}) => - object && { - html: `\ -

${object.properties?.name}

-
${object.geometry?.coordinates?.[0]}
-
${object.geometry?.coordinates?.[1]}
`, - style: { - backgroundColor: '#ddd', - fontSize: '0.8em' + getTooltip={({object}) => { + const {name, ...properties} = object?.properties || {}; + const props = Object.entries(properties) + .map(([key, value]) => `
${key}: ${value}
`) + .join('\n'); + return ( + object && { + html: `\ +

${name}

+${props} +
Coords: ${object.geometry?.coordinates?.[0]};${object.geometry?.coordinates?.[1]}
`, + style: { + backgroundColor: '#ddd', + fontSize: '0.8em' + } } - } - } + ); + }} >
@@ -181,22 +181,19 @@ async function onExampleChange(args: { const {selectedLoader, selectedExample, example, state, setState} = args; const url = example.data; - console.log('Loading', url); try { const data = (await load(url, LOADERS, LOADER_OPTIONS)) as Table; - console.log('Loaded data', data); + console.log('Loaded data',url, data); const viewState = {...state.viewState, ...example.viewState}; - setState({...state, selectedLoader, selectedExample, viewState, loadedTable: data}); + setState(state => ({...state, selectedLoader, selectedExample, viewState, loadedTable: data})); } catch (error) { - console.log('Failed to load data', url, error); - setState({...state, error: `Could not load ${selectedExample}: ${error.message}`}); + console.error('Failed to load data', url, error); + setState(state => ({...state, error: `Could not load ${selectedExample}: ${error.message}`})); } } function renderLayer({selectedExample, selectedLoader, loadedTable}) { - const geojson = loadedTable as GeoJSON; - console.warn('Rendering layer with', geojson); return [ new GeoJsonLayer({ id: `geojson-${selectedExample}(${selectedLoader})`, diff --git a/examples/website/geospatial/components/control-panel.tsx b/examples/website/geospatial/components/control-panel.tsx index 98d8898f40..311ddc4979 100644 --- a/examples/website/geospatial/components/control-panel.tsx +++ b/examples/website/geospatial/components/control-panel.tsx @@ -1,7 +1,7 @@ import styled from 'styled-components'; -import React, {PureComponent} from 'react'; -import PropTypes from 'prop-types'; -import {Example, INITIAL_EXAMPLE_NAME, INITIAL_LOADER_NAME} from '../examples'; +import React, {useState, useEffect} from 'react'; +import MonacoEditor from '@monaco-editor/react'; +import type {Example} from '../examples'; const Container = styled.div` display: flex; @@ -19,6 +19,19 @@ const Container = styled.div` line-height: 2; outline: none; z-index: 100; + height: calc(100vh - 105px); + width: 500px; + + .loading-indicator { + margin: 0; + text-align: center; + transition: opacity 300ms ease-out; + } + + > .monaco-editor { + height: calc(100vh - 200px) !important; + width: 700px !important; + } `; const DropDown = styled.select` @@ -37,102 +50,94 @@ type PropTypes = React.PropsWithChildren<{ }) => void; }>; -export class ControlPanel extends PureComponent { - static defaultProps: PropTypes = { +/** + * Shows the example selection dropdown and some additional information + */ +export const ControlPanel: React.FC = (props: PropTypes) => { + props = { examples: {}, droppedFile: null, selectedExample: null, selectedLoader: null, - onExampleChange: () => {} + onExampleChange: () => {}, + ...props }; - _autoSelected: boolean; - - constructor(props) { - super(props); - this._autoSelected = false; + return ( + + + + {props.children} +

Table Schema

+ +
+ ); +}; + +/** + * Shows the selected example in bold font + */ +const ExampleHeader: React.FC = ({selectedLoader, selectedExample}) => { + if (!selectedLoader || !selectedExample) { + return null; } - componentDidMount() { - const {examples = {}, onExampleChange} = this.props; - - let selectedLoader = this.props.selectedLoader; - let selectedExample = this.props.selectedExample; - - if ((!selectedLoader || !selectedExample) && !this._autoSelected) { - selectedLoader = INITIAL_LOADER_NAME; - selectedExample = examples[selectedLoader][INITIAL_EXAMPLE_NAME]; - this._autoSelected = true; - } - - if (selectedLoader && selectedExample) { - const example = examples[selectedLoader][selectedExample]; - onExampleChange({selectedLoader, selectedExample, example}); - } + return ( +
+

+ {selectedExample} {selectedLoader}{' '} +

+
+ ); +}; + +/** + * Dropdown that lets user select a new example + */ +const ExampleDropDown: React.FC = ({ + examples = {}, + selectedLoader, + selectedExample, + onExampleChange +}) => { + if (!selectedLoader || !selectedExample) { + return false; } - _renderDropDown() { - const {examples = {}, selectedLoader, selectedExample, onExampleChange} = this.props; - - if (!selectedLoader || !selectedExample) { - return false; - } - - const selectedValue = `${selectedLoader}.${selectedExample}`; - - return ( - { - const loaderExample = evt.target.value as string; - const value = loaderExample.split('.'); - const loaderName = value[0]; - const exampleName = value[1]; - const example = examples[loaderName][exampleName]; - onExampleChange({selectedLoader: loaderName, selectedExample: exampleName, example}); - }} - > - {Object.keys(examples).map((loaderName, loaderIndex) => { - const loaderExamples = examples[loaderName]; - return ( - - {Object.keys(loaderExamples).map((exampleName, exampleIndex) => { - const value = `${loaderName}.${exampleName}`; - return ( - - ); - })} - - ); - })} - - ); - } - - _renderHeader() { - const {selectedLoader, selectedExample} = this.props; - if (!selectedLoader || !selectedExample) { - return null; - } - - return ( -
-

- {selectedExample} {selectedLoader}{' '} -

-
- ); - } - - render() { - return ( - - {this._renderHeader()} - {this._renderDropDown()} - {this.props.children} - - ); - } -} + const selectedValue = `${selectedLoader}.${selectedExample}`; + + return ( + { + const loaderExample = evt.target.value as string; + const value = loaderExample.split('.'); + const loaderName = value[0]; + const exampleName = value[1]; + const example = examples[loaderName][exampleName]; + onExampleChange({selectedLoader: loaderName, selectedExample: exampleName, example}); + }} + > + {Object.keys(examples).map((loaderName, loaderIndex) => { + const loaderExamples = examples[loaderName]; + return ( + + {Object.keys(loaderExamples).map((exampleName, exampleIndex) => { + const value = `${loaderName}.${exampleName}`; + return ( + + ); + })} + + ); + })} + + ); +}; diff --git a/examples/website/geospatial/examples.ts b/examples/website/geospatial/examples.ts index fa485c8f3e..17162275f0 100644 --- a/examples/website/geospatial/examples.ts +++ b/examples/website/geospatial/examples.ts @@ -3,6 +3,7 @@ export const INITIAL_LOADER_NAME = 'GeoParquet'; export const INITIAL_EXAMPLE_NAME = 'Airports'; + // export const INITIAL_LOADER_NAME = 'GeoJSON'; // export const INITIAL_EXAMPLE_NAME = 'Vancouver'; @@ -30,9 +31,16 @@ export const LOADERS_URL = 'https://raw.githubusercontent.com/visgl/loaders.gl/m const DECKGL_DATA_URL = 'https://raw.githubusercontent.com/visgl/deck.gl-data/master'; const PARQUET_PATH = '/formats/geoparquet'; -const GEOARROW_TEST_DATA = `${LOADERS_URL}/modules/arrow/test/data`; // geoarrow +const GEOARROW_TEST_DATA = `${LOADERS_URL}/modules/arrow/test/data/geoarrow`; export const EXAMPLES: Record> = { + GeoArrow: { + multipolygon_hole: { + format: 'geoarrow', + data: `${GEOARROW_TEST_DATA}/multipolygon_hole.arrow`, + viewState: {...VIEW_STATE, longitude: 0, latitude: 0, zoom: 4} + } + }, GeoParquet: { Airports: { format: 'geoparquet', diff --git a/examples/website/geospatial/package.json b/examples/website/geospatial/package.json index 8e226c0c94..d15c1702e1 100644 --- a/examples/website/geospatial/package.json +++ b/examples/website/geospatial/package.json @@ -18,11 +18,12 @@ "@loaders.gl/flatgeobuf": "^4.0.0", "@loaders.gl/geopackage": "^4.0.0", "@loaders.gl/parquet": "^4.0.0", + "@monaco-editor/react": "^4.5.0", "mapbox-gl": "npm:empty-npm-package@^1.0.0", "maplibre-gl": "^2.4.0", "node-stdlib-browser": "^1.2.0", - "react": "^18.0.0", - "react-dom": "^18.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", "react-map-gl": "^7.0.0", "styled-components": "^4.2.0" }, diff --git a/examples/website/geospatial/tsconfig.json b/examples/website/geospatial/tsconfig.json new file mode 100644 index 0000000000..a7ca1cd93a --- /dev/null +++ b/examples/website/geospatial/tsconfig.json @@ -0,0 +1,21 @@ +{ + "include": [".", "../../../modules/*/src"], + "compilerOptions": { + "root": ["."], + // "target": "ESNext", + // "useDefineForClassFields": true, + // "lib": ["DOM", "DOM.Iterable", "ESNext"], + // "allowJs": false, + // "skipLibCheck": false, + // "esModuleInterop": false, + // "allowSyntheticDefaultImports": true, + // "strict": true, + // "forceConsistentCasingInFileNames": true, + // "module": "ESNext", + // "moduleResolution": "Node", + // "resolveJsonModule": true, + // "isolatedModules": true, + // "noEmit": true, + "jsx": "react-jsx" + } +} diff --git a/examples/website/geospatial/vite.config.ts b/examples/website/geospatial/vite.config.ts index 7cffe37aeb..45efbade4e 100644 --- a/examples/website/geospatial/vite.config.ts +++ b/examples/website/geospatial/vite.config.ts @@ -8,7 +8,7 @@ const getAliases = async (frameworkName, frameworkRootDir) => { modules.forEach((module) => { aliases[`${frameworkName}/${module}`] = `${frameworkRootDir}/modules/${module}/src`; }); - console.log(aliases); + // console.log(aliases); return aliases; }; diff --git a/examples/website/tiles/tsconfig.json b/examples/website/tiles/tsconfig.json index a7ca1cd93a..17f90b19a6 100644 --- a/examples/website/tiles/tsconfig.json +++ b/examples/website/tiles/tsconfig.json @@ -2,20 +2,6 @@ "include": [".", "../../../modules/*/src"], "compilerOptions": { "root": ["."], - // "target": "ESNext", - // "useDefineForClassFields": true, - // "lib": ["DOM", "DOM.Iterable", "ESNext"], - // "allowJs": false, - // "skipLibCheck": false, - // "esModuleInterop": false, - // "allowSyntheticDefaultImports": true, - // "strict": true, - // "forceConsistentCasingInFileNames": true, - // "module": "ESNext", - // "moduleResolution": "Node", - // "resolveJsonModule": true, - // "isolatedModules": true, - // "noEmit": true, "jsx": "react-jsx" } } diff --git a/modules/arrow/src/parsers/parse-arrow-sync.ts b/modules/arrow/src/parsers/parse-arrow-sync.ts index f6a71f1419..43c585d88c 100644 --- a/modules/arrow/src/parsers/parse-arrow-sync.ts +++ b/modules/arrow/src/parsers/parse-arrow-sync.ts @@ -6,6 +6,7 @@ import type {ArrowTable} from '../lib/arrow-table'; import {convertTable} from '@loaders.gl/schema'; import * as arrow from 'apache-arrow'; import {convertArrowToColumnarTable} from '../tables/convert-arrow-to-columnar-table'; +import {serializeArrowSchema} from '../schema/convert-arrow-schema'; // Parses arrow to a columnar table export function parseArrowSync( @@ -13,7 +14,11 @@ export function parseArrowSync( options?: {shape?: 'arrow-table' | 'columnar-table' | 'object-row-table' | 'array-row-table'} ): ArrowTable | ColumnarTable | ObjectRowTable | ArrayRowTable { const apacheArrowTable = arrow.tableFromIPC([new Uint8Array(arrayBuffer)]); - const arrowTable: ArrowTable = {shape: 'arrow-table', data: apacheArrowTable}; + const arrowTable: ArrowTable = { + shape: 'arrow-table', + schema: serializeArrowSchema(apacheArrowTable.schema), + data: apacheArrowTable + }; const shape = options?.shape || 'arrow-table'; switch (shape) { diff --git a/modules/arrow/src/tables/convert-arrow-to-columnar-table.ts b/modules/arrow/src/tables/convert-arrow-to-columnar-table.ts index c9d609765c..f52e269ac0 100644 --- a/modules/arrow/src/tables/convert-arrow-to-columnar-table.ts +++ b/modules/arrow/src/tables/convert-arrow-to-columnar-table.ts @@ -24,6 +24,7 @@ export function convertArrowToColumnarTable(table: ArrowTable): ColumnarTable { return { shape: 'columnar-table', + schema: table.schema, data: columnarTable }; } diff --git a/modules/arrow/src/tables/convert-arrow-to-geojson-table.ts b/modules/arrow/src/tables/convert-arrow-to-geojson-table.ts index 5b82d9797e..7fdf8adb43 100644 --- a/modules/arrow/src/tables/convert-arrow-to-geojson-table.ts +++ b/modules/arrow/src/tables/convert-arrow-to-geojson-table.ts @@ -16,6 +16,7 @@ import {getGeometryColumnsFromSchema} from '@loaders.gl/gis'; export function convertApacheArrowToArrowTable(arrowTable: arrow.Table): ArrowTable { return { shape: 'arrow-table', + schema: serializeArrowSchema(arrowTable.schema), data: arrowTable }; } @@ -58,6 +59,7 @@ export function convertArrowToGeoJSONTable(table: ArrowTable): GeoJSONTable { return { shape: 'geojson-table', type: 'FeatureCollection', + schema: table.schema, features }; } diff --git a/modules/arrow/src/tables/convert-columnar-to-row-table.ts b/modules/arrow/src/tables/convert-columnar-to-row-table.ts index f0d0fb841f..ad49de2c27 100644 --- a/modules/arrow/src/tables/convert-columnar-to-row-table.ts +++ b/modules/arrow/src/tables/convert-columnar-to-row-table.ts @@ -24,6 +24,7 @@ export function convertColumnarToRowFormatTable(columnarTable: ColumnarTable): O return { shape: 'object-row-table', + schema: columnarTable.schema, data: rowFormatTable }; } diff --git a/modules/draco/src/draco-loader.ts b/modules/draco/src/draco-loader.ts index d4c514f701..7b5317c828 100644 --- a/modules/draco/src/draco-loader.ts +++ b/modules/draco/src/draco-loader.ts @@ -1,5 +1,6 @@ // loaders.gl, MIT license // Copyright (c) vis.gl contributors + import type {Loader, LoaderOptions} from '@loaders.gl/loader-utils'; import type {DracoMesh} from './lib/draco-types'; import type {DracoParseOptions} from './lib/draco-parser'; @@ -15,15 +16,6 @@ export type DracoLoaderOptions = LoaderOptions & { }; }; -const DEFAULT_DRACO_OPTIONS: DracoLoaderOptions = { - draco: { - decoderType: typeof WebAssembly === 'object' ? 'wasm' : 'js', // 'js' for IE11 - libraryPath: 'libs/', - extraAttributes: {}, - attributeNameEntry: undefined - } -}; - /** * Worker loader for Draco3D compressed geometries */ @@ -38,5 +30,12 @@ export const DracoLoader: Loader = { mimeTypes: ['application/octet-stream'], binary: true, tests: ['DRACO'], - options: DEFAULT_DRACO_OPTIONS + options: { + draco: { + decoderType: typeof WebAssembly === 'object' ? 'wasm' : 'js', // 'js' for IE11 + libraryPath: 'libs/', + extraAttributes: {}, + attributeNameEntry: undefined + } + } }; diff --git a/modules/gis/src/lib/tables/convert-table-to-geojson.ts b/modules/gis/src/lib/tables/convert-table-to-geojson.ts index b41482f4d8..a5ae1105c0 100644 --- a/modules/gis/src/lib/tables/convert-table-to-geojson.ts +++ b/modules/gis/src/lib/tables/convert-table-to-geojson.ts @@ -51,7 +51,7 @@ function parseGeometry( ? geometry.buffer.slice(geometry.byteOffset, geometry.byteOffset + geometry.byteLength) : (geometry as ArrayBuffer); const geojson = wkbLoader?.parseSync?.(arrayBuffer, { - wkb: {shape: 'geometry'} + wkb: {shape: 'geojson-geometry'} }) as unknown as Geometry; return geojson; // binaryGeometry ? binaryToGeometry(binaryGeometry) : null; // const binaryGeometry = WKBLoader.parseSync?.(geometry); diff --git a/modules/wkt/test/twkb-loader.spec.ts b/modules/wkt/test/twkb-loader.spec.ts index 974f252b2c..2b694677c0 100644 --- a/modules/wkt/test/twkb-loader.spec.ts +++ b/modules/wkt/test/twkb-loader.spec.ts @@ -51,7 +51,7 @@ test('TWKBLoader#2D', async (t) => { // } // if (testCase.wkbXdr && testCase.binary && testCase.geoJSON) { -// t.deepEqual(parseSync(testCase.twkbXdr, TWKBLoader, {wkb: {shape: 'geometry'}}), testCase.geoJSON); +// t.deepEqual(parseSync(testCase.twkbXdr, TWKBLoader, {wkb: {shape: 'geojson-geometry'}}), testCase.geoJSON); // } // } diff --git a/website/src/examples-sidebar.js b/website/src/examples-sidebar.js index 50f71d0c8e..881ba914f4 100644 --- a/website/src/examples-sidebar.js +++ b/website/src/examples-sidebar.js @@ -19,6 +19,7 @@ type: 'category', label: 'Geospatial Loaders', items: [ + 'geoarrow', 'geoparquet', // 'geopackage', sql.js bundling issue... 'flatgeobuf', diff --git a/website/src/examples/geoarrow.mdx b/website/src/examples/geoarrow.mdx new file mode 100644 index 0000000000..03dee21b48 --- /dev/null +++ b/website/src/examples/geoarrow.mdx @@ -0,0 +1,7 @@ +# GeoArrow + +import Demo from 'examples/website/geospatial/app'; + +
+ +
diff --git a/website/static/images/examples/geoarrow.jpg b/website/static/images/examples/geoarrow.jpg new file mode 100644 index 0000000000..bd9953a6d1 Binary files /dev/null and b/website/static/images/examples/geoarrow.jpg differ