npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

proj.js

v0.9.0

Published

PROJ bindings for JavaScript - with a native port for Node.js and a WASM port for the browser

Downloads

112

Readme

proj.js

This is proj.js - PROJ bindings for JavaScript with a native port for Node.js and WASM port for the browser using SWIG JSE.

This project is completely separate from proj4js which is a separate (and partial) reimplementation in JavaScript.

Current status

Alpha quality. Most basic functions work as intended. Mostly tested for leaks on the nominal code paths.

Keep in mind that I am only a very occasional user of a very small fraction of PROJ and my main interest is JavaScript bindings - Node.js and browser - for C/C++ projects. If you find methods that are not usable in the current version and submit unit tests for it, I will make them work.

Try it yourself

# Checkout from git
git clone https://github.com/mmomtchev/proj.js.git

# Install all the npm dependencies
cd proj.js
npm install
npx xpm install

# If you do not have SWIG JSE installed, download the SWIG generated files
# from a recent GHA run: https://github.com/mmomtchev/proj.js/actions
# (download swig-generated and unzip it in proj.js/swig)
mkdir -p swig && cd swig && unzip ~/Downloads/swig-generated.zip

# If you have SWIG JSE installed, generate the wrappers yourself
npm run swig

# Build the native version (requires a working C++ compiler)
npm run build:native

# Build the WASM version (requires emsdk in path)
npm run build:wasm

# Alternatively, get the compiled binaries from a recent GHA run
mkdir -p lib/binding && cd lib/binding && unzip -x ~/Downloads/native-ubuntu-latest-tiff.zip && unzip -x ~/Downloads/wasm-external-no_tiff.zip

# Run the tests (Node.js and browser)
npm test

# Run the web demo (should work on all OS if you have the WASM version)
cd test/browser && npx webpack serve --mode=production
# then open http://localhost:8030/

Usage

This package is a magickwand.js-style npm package with an automatic import that resolves to either the native module or the WASM module depending on the environment.

The following code will import the module:

import qPROJ from 'proj.js';
const PROJ = await qPROJ;
console.log(`proj.db is inlined: ${PROJ.proj_js_inline_projdb}`);
if (!PROJ.proj_js_inline_projdb) {
  const proj_db = new Uint8Array(await (await fetch(proj_db_url)).arrayBuffer());
  PROJ.loadDatabase(proj_db);
}

Node.js will pick up the native binary, while a modern bundler such as webpack or rollup with support for Node.js 16 exports will pick up the WASM module.

This requires ES6, Node.js 16 and a recent webpack or rollup. If using TypeScript, you will have to transpile to ES6. Most major web components were updated with those features in 2022.

If importing in a legacy CJS environment, you will be limited to using the native module in Node.js only:

const PROJ = require('proj.js/native');
console.log(`proj.db is inlined: ${PROJ.proj_js_inline_projdb}`);

When using the native module, proj.db is always external and automatically loaded from require.resolve('proj.js/lib/binding/proj/proj.db').

If using TypeScript, you will need to explicitly import the types in the PROJ namespace because PROJ is a variable:

import qPROJ from 'proj.js';
import type * as PROJ from 'proj.js';
const PROJ = await qPROJ;
console.log(`proj.db is inlined: ${PROJ.proj_js_inline_projdb}`);
if (!PROJ.proj_js_inline_projdb) {
  const proj_db = new Uint8Array(await (await fetch(proj_db_url)).arrayBuffer());
  PROJ.loadDatabase(proj_db);
}

WASM size considerations

When using WASM, proj.db can either be inlined in the WASM bundle or it can be loaded from an Uint8Array before use.

Currently, the bundle size remains an issue.

| Component | raw | brotli | brotli | --- | --- | --- | | proj.wasm w/ TIFF w/o proj.db | 8593K | 1735K | | proj.wasm w/o TIFF w/o proj.db | 7082K | 1302K | | proj.db | 9240K | 1320K |

It should be noted that while using -Os in emscripten can lead to a two-fold reduction of the raw size, the size of the compressed build will always remain the same. Sames goes for optimizing with binaryen - despite the very significant raw size gain, the compressed size gain is relatively insignificant.

curl support is enabled only in the native build - there is no simple solution to networking for the WASM build.

Linking with my own sqlite-wasm-http project to access a remote proj.db, using SQL over HTTP, is a very significant project that will further increase the bundle size to the point nullifying the gains from proj.db. It does not seem to be a logical option at the moment.

Currently the biggest contributor to raw code size is SWIG JSE which produces large amounts of identical code for each function. This may me improved in a future version, but bear in mind that SWIG-generated code has the best compression ratio. It is also worth investigating what can be gained from modularization of the SWIG wrappers and if it is really necessary to wrap separately all derived classes.

Performance

Initial crude benchmarks, tested on i7 9700K @ 3.6 GHz with the C++ quickstart:

| Test | Native | WASM in V8 | | --- | --- | --- | | DatabaseContext.create() | 0.171ms | 16.316ms | | AuthorityFactory.create('string') | 0.071ms | 0.44ms | | CoordinateOperationContext.create() | 0.052ms | 0.397ms | | AuthorityFactory.create('EPSG') | 0.011ms | 0.274ms | | createFromUserInput() | 0.283ms | 0.617ms | | CoordinateOperationFactory.create().createOperations() | 0.588ms | 1.885ms | | coordinateTransformer() | 0.29ms | 19.117ms | | transform() | 0.014ms | 0.234ms |

Globally, the first impression is that the library is usable both on the backend and in the browser in fully synchronous mode. The only real hurdle at the moment remains the WASM bundle size.