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

bbox-fns

v0.20.2

Published

Light-weight JavaScript Bounding Box Utility Functions

Downloads

4,248

Readme

bbox-fns: work in progress

Super Light-weight JavaScript Bounding Box Utility Functions

the bounding box

Bounding boxes, or rectangular extents, are represented as an array of 4 numbers:

[xmin, ymin, xmax, ymax]

functions

bboxArea

Calculate the area of a bounding box

import bboxArea from "bbox-fns/bbox-area.js";

bboxArea([2, 3, 8, 9])
36 // (8 - 2) * (9 - 3)

bboxArray

Calculate the bounding box of an array of points (aka "a polygon ring")

import bboxArray from "bbox-fns/bbox-array.js";

bboxArray([
  [ -180, 86.06126914660831 ],
  [ -180, 85.66739606126914 ],
  [ -179, 84.87964989059081 ],
  [ -179, 84.48577680525165 ]
]);
[-180, 84.48577680525165, -179, 86.06126914660831]

// throws because of the NaN value
bboxArray([ -180, 86.06 ], [NaN, NaN], [ -179, 84.48 ]);

// skip NaN values (don't throw)
bboxArray(points, { nan_strategy: "skip" })
[-180, 84.48, -179, 86.06]

bboxPoint

Convert a single [x, y] point into a bounding box of zero width and height;

import bboxPoint from "bbox-fns/bbox-point.js";

bboxPoint([-180, 86.06126914660831]);
[-180, 86.06126914660831, -180, 86.06126914660831]

bboxSize

Calculate the width and height of a bounding box

import bboxSize from "bbox-fns/bbox-size.js";

bboxSize([-180, 84.48577680525165, -179, 86.06126914660831]);
[1, 1.5754923413566644]

booleanContains

Check if a bounding box contains another

import booleanContains from "bbox-fns/boolean-contains.js";

const western_hemisphere = [-180, -90, 0, 90];
const colorado = [-109.05378, 37.0057, -102.0665, 41.0443];

booleanContains(western_hemisphere, colorado);
true

// exclude bbox that extends to the exact edge
booleanContains(western_hemisphere, [-10, -20, 0, 20], { exclusive: true });
false

booleanContainsPoint

Check if a bounding box contains a point

import booleanContainsPoint from "bbox-fns/boolean-contains-point.js";

const western_hemisphere = [-180, -90, 0, 90];
const eastern_hemisphere = [0, -90, 180, 90];
const hawaii = [-155.844437, 19.741755];

booleanContainsPoint(western_hemisphere, hawaii);
true

// point on boundary
booleanContainsPoint(western_hemisphere, [0, 0]);
true

// ignoring points on the exact edge
booleanContainsPoint(western_hemisphere, [0, 0], { exclusive: true });
false

booleanIntersects

Checks if two bounding boxes have any intersection at all.

import booleanIntersects from "bbox-fns/boolean-intersects.js";

const western_hemisphere = [-180, -90, 0, 90];
const eastern_hemisphere = [0, -90, 180, 90];

booleanIntersects(western_hemisphere, eastern_hemisphere);
true

booleanRectangle

Checks if coordinates represent a rectangular bounding box

import booleanRectangle from "bbox-fns/boolean-rectangle.js";

// rectangle for the globe bbox [-180, -90, 180, 90]
const coords = [
  [ -180, 90 ],
  [ -180, -90 ],
  [ 0, -90 ],
  [ 0, 90 ],
  [ -180, 90 ]
];
booleanRectangle(coords);
true

// extra points that don't affect shape
const denseCoords = [
  [ -180, 90 ],
  [ -180, 0 ],
  [ -180, -90 ],
  [ -90, -90 ],
  [ 0, -90 ],
  [ 0, 0 ],
  [ 0, 90 ],
  [ -90, 90 ],
  [ -180, 90 ]
];
booleanRectangle(denseCoords);
true

intersect

import intersect from "bbox-fns/intersect.js";
const western_hemisphere = [-180, -90, 0, 90];
const eastern_hemisphere = [0, -90, 180, 90];

intersect(western_hemisphere, eastern_hemisphere);
[0, -90, 0, 90] // prime meridian

merge

import merge from "bbox-fns/merge.js";

const western_hemisphere = [-180, -90, 0, 90];
const eastern_hemisphere = [0, -90, 180, 90];
const bboxes = [western_hemisphere, eastern_hemisphere];
merge(bboxes);
[-180, -90, 180, 90] // bbox for the whole globe

polygon

Create GeoJSON-Like Polygon from a Bounding Box

import polygon from "bbox-fns/polygon.js";

polygon([-180, -90, 180, 90]);

// polygon is in counter-clockwise order
[
  [
    [-180, 90],  // top-left
    [-180, -90], // bottom-left
    [180, -90],  // bottom-right
    [180, 90],   // top-right 
    [-180, 90]   // top-left
  ]
]

calc

Calculate the bounding box of a geometry in either GeoJSON or ArcGIS JSON.

import calc from "bbox-fns/calc.js";

calc({
  type: "Polygon",
  coordinates: [
    [
      [30, 10],
      [40, 40],
      [20, 40],
      [10, 20],
      [30, 10]
    ]
  ]
});
[10, 10, 40, 40]

calcAll

Calculate an array of bounding boxes for all the input geometries. For example, a multipolygon will return multiple bounding boxes.

import calcAll from "bbox-fns/calc-all.js";

calcAll({
  type: "MultiPolygon",
  coordinates: [ ... ]
});
[bbox1, bbox2, ...]

densePolygon

A more advanced version of polygon. Create a polygon while adding points to each side of the rectangle.

import polygon from "bbox-fns/dense-polygon.js";

// add 100 points along each side
densePolygon(bbox, { density: 100 });

// add 100 points along the top and bottom edge (x-axis)
// and 400 points along the left and right edge (y-axis)
densePolygon(bbox, { density: [100, 400] });

grid

Chop bounding box up into multiple smaller bounding boxes.

import grid from "bbox-fns/grid.js";

const globe = [-180, -90, 180, 90];
const number_of_columns = 2; // how many grid cells left to right
const number_of_rows = 2; // how many grid cells top to bottom
const quadrants = grid(globe, [number_of_columns, number_of_rows]);
[
  [-180, -90, 0, 0], // south-western
  [0, -90, 180, 0], // south-eastern
  [-180, 0, 0, 90], // north-western
  [0, 0, 180, 90]  // north-eastern
]

scale

Multiply x and y values by the given scale values

import scale from "bbox-fns/scale.js";

// shrink the grid by 50%
scale([0, 9, 50, 200], 0.5);
[0, 4.5, 25, 100];

// scale x and y values by different factors
// same as [0 * 2, 9 * 10, 50 * 2, 200 * 10]
scale([0, 9, 50, 200], [2, 10]);
[0, 90, 100, 2000]

shift

Shift bounding box horizontally and/or vertically

// shift bounding box overlapping left "edge"
// to the right, so it overlaps the right "edge"
shift([-200, 40, -160, 90], { x: 360 })
[160,40,200,90];

// shift horizontally and vertically
shift([-185, 90, -180, 95], [360, -90])
[175, 0, 180, 5]

// same as above
shift([-185, 90, -180, 95], { x: 360, y: -90 });

split

Split bounding box that crosses given x or y boundaries. For example, split a bbox that crosses the antimeridian into two bounding boxes.

import split from "bbox-fns/split.js";

// split across the antimeridian
split([-200, -90, 160, 90], { x: [-180, 180] })
[
  [-200, -90, -180, 90], // overflow, left of antimeridian
  [-180, -90, 160, 90] // right of antimeridian
]

// split across the antimeridian and the poles
split([-200, -90, 160, 100], { x: [-180, 180], y: [-90, 90] })
[
  [-200,-90,-180,90],
  [-200,90,-180,100],
  [-180,-90,160,90],
  [-180,90,160,100]
]

reproject

Reproject a bounding box using the given reprojection function

import reproject from "bbox-fns/reproject.js";
import proj4 from "proj4-fully-loaded";

// convert a bounding box from 4326 to a UTM projection
const { forward } = proj4("EPSG:4326", "EPSG:32610");
reproject(bbox, forward);

// you can also pass in an async reprojection function
reproject(bbox, forwardAsync, { async: true })

// you can also control the point density of the intermediate polygon
reproject(bbox, forward, { density: 99 })

// skip (don't throw error) when forward returns a NaN value
reproject(bbox, forward, { nan_strategy: "skip" })

sort

import sort from "bbox-fns/sort.js";

const bboxes = [
  [175, -85, 180, 90],
  [-180, -85, -175, 90]
];
sort(bboxes)
[[-180,-85,-175,90],[175,-85,180,90]]

union

Combine all bounding boxes that intersect. This is different from merge, which will combine bounding boxes even if they don't intersect.

import union from "bbox-fns/union.js";

const wyoming = [-110.99, 40.97, -104.08, 45.03];
const usa = [-125.10, 24.75, -66, 49.54];
const iceland = [-24.40,  63.29, -13.16, 66.73];

union([wyoming, usa, iceland]);

// only includes usa and iceland, because wyoming merged into usa
[[-125.10, 24.75, -66, 49.54], [-24.40,  63.29, -13.16, 66.73]]

unwrap

Un-wrap an extent that overflows the edge of the earth, returning an array of one or more bounding boxes.

import unwrap from "bbox-fns/unwrap.js";

const earth = [-180, -90, 180, 90];
const bbox = [-200, -21, -160, 87]; // extends over "left edge" of the earth

unwrap(bbox, earth);

// bounding box unwrapped and normalized within the bounds of the earth
[
  [-180, -21, -160, 87],
  [160, -21, 180, 87]
]

validate

import validate from "bbox-fns/validate.js";

validate([-180, 0, 180, 45])
true

// invalid length
validate([-180, 0, 0, 180, 45, 0])
false

// xmin greater than xmax
validate([-45, 10, -90, 20])
false

projection support

If you are looking for a library with greater projection support and a class-based approach, try geo-extent!

nomenclature

This library borrows the names of some similar Turf.js functions, but it does not borrow the internal code.

advanced usage

precise functions

In order to avoid floating point arithmetic errors, you can use the precise version of these functions where numbers are represented as strings.

import preciseBboxArray from "bbox-fns/precise/bbox-array.js";
import preciseDensePolygon from "bbox-fns/precise/dense-polygon.js";
import preciseDivide from "bbox-fns/precise/divide.js";
import preciseReproject from "bbox-fns/precise/reproject.js";

preciseDensePolygon(bbox, { density: [359, 179] }); // add 359 points to top and bottom, and 179 points to the left and right
[
  [ '-180', '80' ],  [ '-180', '79' ],  [ '-180', '78' ],  [ '-180', '77' ], /* ... */, [ '-180', '80' ]
]

preciseDivide([0, 9, 50, 200], [3, 4], { ellipsis: true })
["0", "2.25", "16.666...", "50"]