BananaGL

3D Web Visualization Library

The development of this library is now on hold; Metacity Tools are in the process of transitioning from BananaGL to MetacityGL

Visualize data preprocessed by Metacity with BananaGL - a client-side web visualization library. It is built with three.js and Typescript.

  • 👩‍💻 Newest releases are always available on our GitHub

  • 📦 Datasets can be obtained from our DataAPI service

Quick Start Guide

See Releases on our GitHub.

  1. Download bananagl.zip and use its contents in your project.

  2. Create index.html and start coding!

Minimal HTML starting template:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>BananaGL Project</title>
</head>
<body>
    <div id="container">
        <canvas id="canvas">Your browser does not support canvas</canvas>
    </div>
    <script src="bananagl.js"></script>
    <script>
        window.onload = () => {
            const canvas = document.getElementById("canvas");

            const gl = new BananaGL.BananaGL({ 
                canvas: canvas,
                metacityWorker: "metacityWorker.js",
            });
    </script>
</body>
</html>

Never set any CSS styles (directly or in a separate style sheet) modifying the width or height of the<canvas> passed to BananaGL. Set the sizes on its parent instead.

BananaGL keeps the provided <canvas> at 100% width and height of its parents, and adds a small annotation to its bottom.

Initialization

First, you need to initialize the library:

const gl = new BananaGL.BananaGL({ 
    canvas: canvas,
    metacityWorker: "metacityWorker.js",
});

The function accepts a parameter object with the following properties:

How Camera works

The Camera has two significant attributes which influence the LOD loading, etc.:

  • position - actual position of the camera in 3D space

  • target - focus point of the camera that always lies in the z = 0 plane

Despite its looks, BananaGL uses Perspective camera with fov = 5, and by default, all limits are set up for viewing data in the coordinate system EPSG:5514.

Layer

You can add new geographic layers to you visualization following way:

const gl = new BananaGL.BananaGL({...});

gl.loadLayer({
    api: "https://data.metacity.cc/terrain",
    baseColor: 0xffffff
});

The function accepts a parameter object with the following properties:

Styles

The color of mesh models can be modified by providing styling rules to individual layers.

const gl = new BananaGL.BananaGL({...});

gl.loadLayer({
    api: "https://data.metacity.cc/buildings",
    baseColor: 0xffffff,
    style: [
        gl.style.withAttributeEqualTo("utilization", "office").useColor(0x0000ff),
        gl.style.withAttributeEqualTo("height", 50).useColor(0xff0000)
    ]
});

In the example above, the object with attribute utilization set to value office will be blue, and all buildings with height equal to 50 will be red.

Computed Properties

On loading, all mesh objects are automatically assigned the following attributes:

  • height - number, height of the object

  • baseHeight - number, minimal z-coordinate of all object vertices

  • bbox - [number[], number[]], object bounding box, bbox[0] is the minimal coordinate , bbox[1] is maximum

Rule Resolution

If two or more rules apply to a single object, the last matched rule is applied.

If no rule matches, the baseColor of the layer is applied.

Rule Chaining

If you want to specify a rule where both of the rules must apply, you can chain them in a following way:

const gl = new BananaGL.BananaGL({...});

gl.loadLayer({
    api: "https://data.metacity.cc/buildings",
    baseColor: 0xffffff,
    style: [
        gl.style.withAttributeEqualTo("utilization", "office")
                .withAttributeEqualTo("height", 50).useColor(0xffe135)
    ]
});

Style Rules

Several styling rules are available:

.forAll

Applies the same color to all objects, essentially the same as using baseColor (just more computationally expensive, use only for testing or if you really despise your users).

gl.style.forAll().useColor(0xffe135)

.withAttributeEqualTo

Applies color to all objects with a certain attribute equal to a provided value.

gl.style.withAttributeEqualTo("usage", "restaurant").useColor(0xffe135)

.withAttributeRange

Applies color to all objects with a certain attribute in provided range.

gl.style.withAttributeRange("height", 10, 20).useColor(0xffe135)
gl.style.withAttributeRange("height", 10, 20).useColor([0x000000, 0xffffff])

.withAttributeRangeExt

Applies color to all objects with a certain attribute in provided range. If the value is outside of the range, the color is extrapolated (constant method).

Combined with useColor using a single color works as an indication of whether the attribute is present.

gl.style.withAttributeRangeExt("height", 10, 20).useColor(0xffe135)
gl.style.withAttributeRangeExt("height", 10, 20).useColor([0x000000, 0xffffff])

.useColor

Specifies which color or colormap should be used if this particular rule applies. You can specify a single color

gl.style.withAttributeEqualTo("usage", "restaurant").useColor(0xffe135)

or a color palette. Palettes work well in combination with AttributeRange rules.

gl.style.withAttributeRangeExt("height", 10, 20).useColor([0x000000, 0xffffff])

If you call useColor more than once on a single rule, the last provided value is used.

gl.style.withAttributeEqualTo("usage", "restaurant")
        .useColor(0xffe135) //<- not used
        .useColor(0xffffff) //<- used

Last updated