Skip to content

Live demo ​

Open the demo in a new tab →

Everything below happens in your browser. There is no server: the GeoJSON is converted to shapefile bytes by the WebAssembly module, zipped with fflate, and handed to the browser's download machinery.

What to try ​

Export the sample layers. Three layers around Central Park — points, lines and polygons. A shapefile holds one geometry type, which is exactly why three layers produce three sets of files. Switch the layout to see how the archive is arranged:

LayoutProduces
FlatParkTrails.shp, ParkZones.shp, … all at the root
FoldersParkTrails/ParkTrails.shp, …
Nested zipsParkTrails.zip, ParkZones.zip, …

Then drag the archive you just downloaded back onto the drop zone. It reads back and zooms to the features — including the nested layout, which is an archive of archives.

Watch the field names. restricted_access is 17 characters and dBase caps field names at 11 bytes, so the export reports what it was renamed to. That mapping is returned to you rather than left to be discovered in a GIS later.

The code behind it ​

The demo is a Vite + Vue 3 app using the Composition API. The whole export is this:

ts
import { writeLayers, zipLayers } from '@crmackey/shapefile-wasm';
import { triggerDownload } from '@crmackey/shapefile-wasm/browser';

const written = await writeLayers(
  selected.value.map((layer) => ({
    name: layer.name,
    geojson: layer.geojson,
    epsg: 4326,
  })),
);

const zip = zipLayers(written, { layout: options.layout });
triggerDownload(zip, 'central-park.zip');

And the import, from a dropped File:

ts
import { readShapefileFile } from '@crmackey/shapefile-wasm/browser';

const layers = await readShapefileFile(file);
for (const layer of layers) {
  map.addSource(layer.name, { type: 'geojson', data: layer.geojson });
}

The source is in demo/.

Released under the MIT License.