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

@alpaca-travel/mapbox-gl-native

v1.0.2

Published

Node.js bindings to Mapbox GL native

Downloads

7

Readme

Mapbox GL Native Node Bindings

This project provides pre-built Node.js bindings to Mapbox GL. Official node bindings from Mapbox are discontinued, per mapbox-gl-native#16418.

This just performs a more recent build supporting the original naturalatlas (see original fork)

sudo apt-get install libuv1
npm install @alpaca-travel/mapbox-gl-native --save

Current Node Version Support: 8, 10, 12, 13, 14, 15, 16, 17, 18

Rendering a map tile

const fs = require("fs");
const path = require("path");
const mbgl = require("@alpaca-travel/mapbox-gl-native");
const sharp = require("sharp");

const options = {
  request: function (req, callback) {
    fs.readFile(path.join(__dirname, "test", req.url), function (err, data) {
      callback(err, { data: data });
    });
  },
  ratio: 1,
};

const map = new mbgl.Map(options);

map.load(require("./test/fixtures/style.json"));

map.render({ zoom: 0 }, function (err, buffer) {
  if (err) throw err;

  map.release();

  var image = sharp(buffer, {
    raw: {
      width: 512,
      height: 512,
      channels: 4,
    },
  });

  // Convert raw image buffer to PNG
  image.toFile("image.png", function (err) {
    if (err) throw err;
  });
});

The first argument passed to map.render is an options object, all keys are optional:

{
    zoom: {zoom}, // number, defaults to 0
    width: {width}, // number (px), defaults to 512
    height: {height}, // number (px), defaults to 512
    center: [{longitude}, {latitude}], // array of numbers (coordinates), defaults to [0,0]
    bearing: {bearing}, // number (in degrees, counter-clockwise from north), defaults to 0
    pitch: {pitch}, // number (in degrees, arcing towards the horizon), defaults to 0
    classes: {classes} // array of strings
}

When you are finished using a map object, you can call map.release() to permanently dispose the internal map resources. This is not necessary, but can be helpful to optimize resource usage (memory, file sockets) on a more granular level than V8's garbage collector. Calling map.release() will prevent a map object from being used for any further render calls, but can be safely called as soon as the map.render() callback returns, as the returned pixel buffer will always be retained for the scope of the callback.

Implementing a file source

When creating a Map, you must pass an options object (with a required request method and optional 'ratio' number) as the first parameter.

const map = new mbgl.Map({
  request: function (req) {
    // TODO
  },
  ratio: 2.0,
});

The request() method handles a request for a resource. The ratio sets the scale at which the map will render tiles, such as 2.0 for rendering images for high pixel density displays. The req parameter has two properties:

{
  "url": "http://example.com",
  "kind": 1
}

The kind is an enum and defined in mbgl.Resource:

{
  "Unknown": 0,
  "Style": 1,
  "Source": 2,
  "Tile": 3,
  "Glyphs": 4,
  "SpriteImage": 5,
  "SpriteJSON": 6
}

The kind enum has no significance for anything but serves as a hint to your implemention as to what sort of resource to expect. E.g., your implementation could choose caching strategies based on the expected file type.

The request implementation should pass uncompressed data to callback. If you are downloading assets from a source that applies gzip transport encoding, the implementation must decompress the results before passing them on.

A sample implementation that reads files from disk would look like the following:

var map = new mbgl.Map({
  request: function (req, callback) {
    fs.readFile(path.join("base/path", req.url), function (err, data) {
      callback(err, { data: data });
    });
  },
});

This is a very barebones implementation and you'll probably want a better implementation. E.g. it passes the url verbatim to the file system, but you'd want add some logic that normalizes http URLs. You'll notice that once your implementation has obtained the requested file, you have to deliver it to the requestee by calling callback(), which takes either an error object or null and an object with several keys:

{
    modified: new Date(),
    expires: new Date(),
    etag: "string",
    data: new Buffer()
}

A sample implementation that uses request to fetch data from a remote source:

const mbgl = require("@alpaca-travel/mapbox-gl-native");
const request = require("request");

const map = new mbgl.Map({
  request: function (req, callback) {
    request(
      {
        url: req.url,
        encoding: null,
        gzip: true,
      },
      function (err, res, body) {
        if (err) {
          callback(err);
        } else if (res.statusCode == 200) {
          const response = {};

          if (res.headers.modified) {
            response.modified = new Date(res.headers.modified);
          }
          if (res.headers.expires) {
            response.expires = new Date(res.headers.expires);
          }
          if (res.headers.etag) {
            response.etag = res.headers.etag;
          }

          response.data = body;

          callback(null, response);
        } else {
          callback(new Error(JSON.parse(body).message));
        }
      }
    );
  },
});

Stylesheets are free to use any protocols, but your implementation of request must support these; e.g. you could use s3:// to indicate that files are supposed to be loaded from S3.

Listening for log events

The module imported with require('mapbox-gl-native') inherits from EventEmitter, and the NodeLogObserver will push log events to this. Log messages can have class, severity, code (HTTP status codes), and text parameters.

const mbgl = require("@alpaca-travel/mapbox-gl-native");
mbgl.on("message", function (msg) {
  t.ok(msg, "emits error");
  t.equal(msg.class, "Style");
  t.equal(msg.severity, "ERROR");
  t.ok(msg.text.match(/Failed to load/), "error text matches");
});