Already Copied
Javascript Doc

Getting Started

Goong JS is a JavaScript library that uses WebGL to render interactive maps from Goong Map styles. It is part of the Goong GL ecosystem, which includes Goong Mobile SDK, a compatible renderer written in C++ with bindings for desktop and mobile platforms.

Quickstart

To get started, you need an access token, get one at https://account.goong.io

Include the JavaScript and CSS files in the <head> of your HTML file.

<script src='https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js'></script>
<link href='https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css' rel='stylesheet' />

Include the following code in the <body> of your HTML file.

<div id='map' style='width: 400px; height: 300px;'></div>
<script>
goongjs.accessToken = 'your access token here';
var map = new goongjs.Map({
    container: 'map',
    style: 'https://tiles.goong.io/assets/goong_map_web.json'
});
</script>

Style

Display a map

Initialize a map in an HTML element with Goong JS.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Display a map</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>
	body { margin: 0; padding: 0; }
	#map { position: absolute; top: 0; bottom: 0; width: 100%; };
</style>
</head>
<body>
<div id="map"></div>
<script>
	goongjs.accessToken = '<your access token here>';
    var map = new goongjs.Map({
        container: 'map', // container id
        style: 'https://tiles.goong.io/assets/goong_map_web.json', // stylesheet location
        center: [105, 21], // starting position [lng, lat]
        zoom: 9 // starting zoom
    });
</script>

</body>
</html>

Add an icon to the map

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Add an icon to the map</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>
	body { margin: 0; padding: 0; }
	#map { position: absolute; top: 0; bottom: 0; width: 100%; };
</style>
</head>
<body>
<div id="map"></div>

<script>
	goongjs.accessToken = '<your access token here>';
    var map = new goongjs.Map({
        container: 'map',
        style: 'https://tiles.goong.io/assets/goong_map_web.json'
    });

    map.on('load', function() {
        map.loadImage(
            'https://upload.wikimedia.org/wikipedia/commons/thumb/6/60/Cat_silhouette.svg/400px-Cat_silhouette.svg.png',
            function(error, image) {
                if (error) throw error;
                map.addImage('cat', image);
                map.addLayer({
                    'id': 'points',
                    'type': 'symbol',
                    'source': {
                        'type': 'geojson',
                        'data': {
                            'type': 'FeatureCollection',
                            'features': [
                                {
                                    'type': 'Feature',
                                    'geometry': {
                                        'type': 'Point',
                                        'coordinates': [0, 0]
                                    }
                                }
                            ]
                        }
                    },
                    'layout': {
                        'icon-image': 'cat',
                        'icon-size': 0.25
                    }
                });
            }
        );
    });
</script>

</body>
</html>

Add an animated icon to the map

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Add an animated icon to the map</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>
	body { margin: 0; padding: 0; }
	#map { position: absolute; top: 0; bottom: 0; width: 100%; };
</style>
</head>
<body>
<div id="map"></div>

<script>
	goongjs.accessToken = '<your access token here>';
    var map = new goongjs.Map({
        container: 'map',
        style: 'https://tiles.goong.io/assets/goong_map_web.json'
    });

    var size = 200;

    // implementation of CustomLayerInterface to draw a pulsing dot icon on the map    
    var pulsingDot = {
        width: size,
        height: size,
        data: new Uint8Array(size * size * 4),

        // get rendering context for the map canvas when layer is added to the map
        onAdd: function() {
            var canvas = document.createElement('canvas');
            canvas.width = this.width;
            canvas.height = this.height;
            this.context = canvas.getContext('2d');
        },

        // called once before every frame where the icon will be used
        render: function() {
            var duration = 1000;
            var t = (performance.now() % duration) / duration;

            var radius = (size / 2) * 0.3;
            var outerRadius = (size / 2) * 0.7 * t + radius;
            var context = this.context;

            // draw outer circle
            context.clearRect(0, 0, this.width, this.height);
            context.beginPath();
            context.arc(
                this.width / 2,
                this.height / 2,
                outerRadius,
                0,
                Math.PI * 2
            );
            context.fillStyle = 'rgba(255, 200, 200,' + (1 - t) + ')';
            context.fill();

            // draw inner circle
            context.beginPath();
            context.arc(
                this.width / 2,
                this.height / 2,
                radius,
                0,
                Math.PI * 2
            );
            context.fillStyle = 'rgba(255, 100, 100, 1)';
            context.strokeStyle = 'white';
            context.lineWidth = 2 + 4 * (1 - t);
            context.fill();
            context.stroke();

            // update this image's data with data from the canvas
            this.data = context.getImageData(
                0,
                0,
                this.width,
                this.height
            ).data;

            // continuously repaint the map, resulting in the smooth animation of the dot
            map.triggerRepaint();

            // return `true` to let the map know that the image was updated
            return true;
        }
    };

    map.on('load', function() {
        map.addImage('pulsing-dot', pulsingDot, { pixelRatio: 2 });

        map.addLayer({
            'id': 'points',
            'type': 'symbol',
            'source': {
                'type': 'geojson',
                'data': {
                    'type': 'FeatureCollection',
                    'features': [
                        {
                            'type': 'Feature',
                            'geometry': {
                                'type': 'Point',
                                'coordinates': [0, 0]
                            }
                        }
                    ]
                }
            },
            'layout': {
                'icon-image': 'pulsing-dot'
            }
        });
    });
</script>

</body>
</html>

Sources

Add live realtime data

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Add live realtime data</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>
	body { margin: 0; padding: 0; }
	#map { position: absolute; top: 0; bottom: 0; width: 100%; };
</style>
</head>
<body>
<div id="map"></div>

<script>
	goongjs.accessToken = '<your access token here>';
    var map = new goongjs.Map({
        container: 'map',
        style: 'https://tiles.goong.io/assets/goong_map_web.json',
        zoom: 0
    });

    var url = 'https://wanderdrone.appspot.com/';
    map.on('load', function() {
        window.setInterval(function() {
            map.getSource('drone').setData(url);
        }, 2000);

        map.addSource('drone', { type: 'geojson', data: url });
        map.addLayer({
            'id': 'drone',
            'type': 'symbol',
            'source': 'drone',
            'layout': {
                'icon-image': 'rocket-15'
            }
        });
    });
</script>

</body>
</html>

Add a raster tile source

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Add a raster tile source</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>
	body { margin: 0; padding: 0; }
	#map { position: absolute; top: 0; bottom: 0; width: 100%; };
</style>
</head>
<body>
<div id="map"></div>
<script>
	goongjs.accessToken = '<your access token here>';
    var map = new goongjs.Map({
        container: 'map', // container id
        style: {
            'version': 8,
            'sources': {
                'raster-tiles': {
                    'type': 'raster',
                    'tiles': [
                        'https://stamen-tiles.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.jpg'
                    ],
                    'tileSize': 256,
                    'attribution':
                        'Map tiles by <a target="_top" rel="noopener" href="http://stamen.com">Stamen Design</a>, under <a target="_top" rel="noopener" href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a target="_top" rel="noopener" href="http://openstreetmap.org">OpenStreetMap</a>, under <a target="_top" rel="noopener" href="http://creativecommons.org/licenses/by-sa/3.0">CC BY SA</a>'
                }
            },
            'layers': [
                {
                    'id': 'simple-tiles',
                    'type': 'raster',
                    'source': 'raster-tiles',
                    'minzoom': 0,
                    'maxzoom': 22
                }
            ]
        },
        center: [-74.5, 40], // starting position
        zoom: 2 // starting zoom
    });
</script>

</body>
</html>

Layers

Animate a line

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title>Animate a line</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
    <style>
        body {
            margin: 0;
            padding: 0;
        }

        #map {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }

        ;
    </style>
</head>

<body>
    <style>
        button {
            position: absolute;
            margin: 20px;
        }

        #pause::after {
            content: 'Pause';
        }

        #pause.pause::after {
            content: 'Play';
        }
    </style>
    <div id="map"></div>
    <button id="pause"></button>
    <script>
        goongjs.accessToken = '<your access token here>';
        var map = new goongjs.Map({
            container: 'map',
            style: 'https://tiles.goong.io/assets/goong_map_web.json',
            center: [0, 0],
            zoom: 0.5
        });

        // Create a GeoJSON source with an empty lineString.
        var geojson = {
            'type': 'FeatureCollection',
            'features': [{
                'type': 'Feature',
                'geometry': {
                    'type': 'LineString',
                    'coordinates': [
                        [0, 0]
                    ]
                }
            }]
        };

        var speedFactor = 30; // number of frames per longitude degree
        var animation; // to store and cancel the animation
        var startTime = 0;
        var progress = 0; // progress = timestamp - startTime
        var resetTime = false; // indicator of whether time reset is needed for the animation
        var pauseButton = document.getElementById('pause');

        map.on('load', function() {
            // add the line which will be modified in the animation
            map.addLayer({
                'id': 'line-animation',
                'type': 'line',
                'source': {
                    'type': 'geojson',
                    'data': geojson
                },
                'layout': {
                    'line-cap': 'round',
                    'line-join': 'round'
                },
                'paint': {
                    'line-color': '#ed6498',
                    'line-width': 5,
                    'line-opacity': 0.8
                }
            });

            startTime = performance.now();

            animateLine();

            // click the button to pause or play
            pauseButton.addEventListener('click', function() {
                pauseButton.classList.toggle('pause');
                if (pauseButton.classList.contains('pause')) {
                    cancelAnimationFrame(animation);
                } else {
                    resetTime = true;
                    animateLine();
                }
            });

            // reset startTime and progress once the tab loses or gains focus
            // requestAnimationFrame also pauses on hidden tabs by default
            document.addEventListener('visibilitychange', function() {
                resetTime = true;
            });

            // animated in a circle as a sine wave along the map.
            function animateLine(timestamp) {
                if (resetTime) {
                    // resume previous progress
                    startTime = performance.now() - progress;
                    resetTime = false;
                } else {
                    progress = timestamp - startTime;
                }

                // restart if it finishes a loop
                if (progress > speedFactor * 360) {
                    startTime = timestamp;
                    geojson.features[0].geometry.coordinates = [];
                } else {
                    var x = progress / speedFactor;
                    // draw a sine wave with some math.
                    var y = Math.sin((x * Math.PI) / 90) * 40;
                    // append new coordinates to the lineString
                    geojson.features[0].geometry.coordinates.push([x, y]);
                    // then update the map
                    map.getSource('line-animation').setData(geojson);
                }
                // Request the next frame of the animation.
                animation = requestAnimationFrame(animateLine);
            }
        });
    </script>

</body>

</html>

Animate a point

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title>Animate a point</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
    <style>
        body {
            margin: 0;
            padding: 0;
        }

        #map {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }

        ;
    </style>
</head>

<body>
    <div id="map"></div>
    <script>
        goongjs.accessToken = '<your access token here>';
        var map = new goongjs.Map({
            container: 'map',
            style: 'https://tiles.goong.io/assets/goong_map_web.json',
            center: [0, 0],
            zoom: 2
        });

        var radius = 20;

        function pointOnCircle(angle) {
            return {
                'type': 'Point',
                'coordinates': [Math.cos(angle) * radius, Math.sin(angle) * radius]
            };
        }

        map.on('load', function() {
            // Add a source and layer displaying a point which will be animated in a circle.
            map.addSource('point', {
                'type': 'geojson',
                'data': pointOnCircle(0)
            });

            map.addLayer({
                'id': 'point',
                'source': 'point',
                'type': 'circle',
                'paint': {
                    'circle-radius': 10,
                    'circle-color': '#007cbf'
                }
            });

            function animateMarker(timestamp) {
                // Update the data to a new position based on the animation timestamp. The
                // divisor in the expression `timestamp / 1000` controls the animation speed.
                map.getSource('point').setData(pointOnCircle(timestamp / 1000));

                // Request the next frame of the animation.
                requestAnimationFrame(animateMarker);
            }

            // Start the animation.
            animateMarker(0);
        });
    </script>

</body>

</html>

Display HTML clusters with custom properties

drawing

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title>Display HTML clusters with custom properties</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
    <style>
        body {
            margin: 0;
            padding: 0;
        }

        #map {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }

        ;
    </style>
</head>

<body>
    <div id="map"></div>

    <script>
        goongjs.accessToken = '<your access token here>';
        var map = new goongjs.Map({
            container: 'map',
            zoom: 0.3,
            center: [0, 20],
            style: 'https://tiles.goong.io/assets/goong_map_web.json'
        });

        map.addControl(new goongjs.NavigationControl());

        // filters for classifying earthquakes into five categories based on magnitude
        var mag1 = ['<', ['get', 'mag'], 2];
        var mag2 = ['all', ['>=', ['get', 'mag'], 2],
            ['<', ['get', 'mag'], 3]
        ];
        var mag3 = ['all', ['>=', ['get', 'mag'], 3],
            ['<', ['get', 'mag'], 4]
        ];
        var mag4 = ['all', ['>=', ['get', 'mag'], 4],
            ['<', ['get', 'mag'], 5]
        ];
        var mag5 = ['>=', ['get', 'mag'], 5];

        // colors to use for the categories
        var colors = ['#fed976', '#feb24c', '#fd8d3c', '#fc4e2a', '#e31a1c'];

        map.on('load', function() {
            // add a clustered GeoJSON source for a sample set of earthquakes
            map.addSource('earthquakes', {
                'type': 'geojson',
                'data': 'https://docs.goong.io/assets/earthquakes.geojson',
                'cluster': true,
                'clusterRadius': 80,
                'clusterProperties': {
                    // keep separate counts for each magnitude category in a cluster
                    'mag1': ['+', ['case', mag1, 1, 0]],
                    'mag2': ['+', ['case', mag2, 1, 0]],
                    'mag3': ['+', ['case', mag3, 1, 0]],
                    'mag4': ['+', ['case', mag4, 1, 0]],
                    'mag5': ['+', ['case', mag5, 1, 0]]
                }
            });
            // circle and symbol layers for rendering individual earthquakes (unclustered points)
            map.addLayer({
                'id': 'earthquake_circle',
                'type': 'circle',
                'source': 'earthquakes',
                'filter': ['!=', 'cluster', true],
                'paint': {
                    'circle-color': [
                        'case',
                        mag1,
                        colors[0],
                        mag2,
                        colors[1],
                        mag3,
                        colors[2],
                        mag4,
                        colors[3],
                        colors[4]
                    ],
                    'circle-opacity': 0.6,
                    'circle-radius': 12
                }
            });
            map.addLayer({
                'id': 'earthquake_label',
                'type': 'symbol',
                'source': 'earthquakes',
                'filter': ['!=', 'cluster', true],
                'layout': {
                    'text-field': [
                        'number-format',
                        ['get', 'mag'],
                        {
                            'min-fraction-digits': 1,
                            'max-fraction-digits': 1
                        }
                    ],
                    'text-font': ['Open Sans Semibold', 'Arial Unicode MS Bold'],
                    'text-size': 10
                },
                'paint': {
                    'text-color': [
                        'case',
                        ['<', ['get', 'mag'], 3],
                        'black',
                        'white'
                    ]
                }
            });

            // objects for caching and keeping track of HTML marker objects (for performance)
            var markers = {};
            var markersOnScreen = {};

            function updateMarkers() {
                var newMarkers = {};
                var features = map.querySourceFeatures('earthquakes');

                // for every cluster on the screen, create an HTML marker for it (if we didn't yet),
                // and add it to the map if it's not there already
                for (var i = 0; i < features.length; i++) {
                    var coords = features[i].geometry.coordinates;
                    var props = features[i].properties;
                    if (!props.cluster) continue;
                    var id = props.cluster_id;

                    var marker = markers[id];
                    if (!marker) {
                        var el = createDonutChart(props);
                        marker = markers[id] = new goongjs.Marker({
                            element: el
                        }).setLngLat(coords);
                    }
                    newMarkers[id] = marker;

                    if (!markersOnScreen[id]) marker.addTo(map);
                }
                // for every marker we've added previously, remove those that are no longer visible
                for (id in markersOnScreen) {
                    if (!newMarkers[id]) markersOnScreen[id].remove();
                }
                markersOnScreen = newMarkers;
            }

            // after the GeoJSON data is loaded, update markers on the screen and do so on every map move/moveend
            map.on('data', function(e) {
                if (e.sourceId !== 'earthquakes' || !e.isSourceLoaded) return;

                map.on('move', updateMarkers);
                map.on('moveend', updateMarkers);
                updateMarkers();
            });
        });

        // code for creating an SVG donut chart from feature properties
        function createDonutChart(props) {
            var offsets = [];
            var counts = [
                props.mag1,
                props.mag2,
                props.mag3,
                props.mag4,
                props.mag5
            ];
            var total = 0;
            for (var i = 0; i < counts.length; i++) {
                offsets.push(total);
                total += counts[i];
            }
            var fontSize =
                total >= 1000 ? 22 : total >= 100 ? 20 : total >= 10 ? 18 : 16;
            var r = total >= 1000 ? 50 : total >= 100 ? 32 : total >= 10 ? 24 : 18;
            var r0 = Math.round(r * 0.6);
            var w = r * 2;

            var html =
                '<svg width="' +
                w +
                '" height="' +
                w +
                '" viewbox="0 0 ' +
                w +
                ' ' +
                w +
                '" text-anchor="middle" style="font: ' +
                fontSize +
                'px sans-serif">';

            for (i = 0; i < counts.length; i++) {
                html += donutSegment(
                    offsets[i] / total,
                    (offsets[i] + counts[i]) / total,
                    r,
                    r0,
                    colors[i]
                );
            }
            html +=
                '<circle cx="' +
                r +
                '" cy="' +
                r +
                '" r="' +
                r0 +
                '" fill="white" /><text dominant-baseline="central" transform="translate(' +
                r +
                ', ' +
                r +
                ')">' +
                total.toLocaleString() +
                '</text></svg>';

            var el = document.createElement('div');
            el.innerHTML = html;
            return el.firstChild;
        }

        function donutSegment(start, end, r, r0, color) {
            if (end - start === 1) end -= 0.00001;
            var a0 = 2 * Math.PI * (start - 0.25);
            var a1 = 2 * Math.PI * (end - 0.25);
            var x0 = Math.cos(a0),
                y0 = Math.sin(a0);
            var x1 = Math.cos(a1),
                y1 = Math.sin(a1);
            var largeArc = end - start > 0.5 ? 1 : 0;

            return [
                '<path d="M',
                r + r0 * x0,
                r + r0 * y0,
                'L',
                r + r * x0,
                r + r * y0,
                'A',
                r,
                r,
                0,
                largeArc,
                1,
                r + r * x1,
                r + r * y1,
                'L',
                r + r0 * x1,
                r + r0 * y1,
                'A',
                r0,
                r0,
                0,
                largeArc,
                0,
                r + r0 * x0,
                r + r0 * y0,
                '" fill="' + color + '" />'
            ].join(' ');
        }
    </script>

</body>

</html>

Style lines with a data-driven property

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title>Style lines with a data-driven property</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
    <style>
        body {
            margin: 0;
            padding: 0;
        }

        #map {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }

        ;
    </style>
</head>

<body>
    <div id="map"></div>
    <script>
        goongjs.accessToken = '<your access token here>';
        var map = new goongjs.Map({
            container: 'map',
            style: 'https://tiles.goong.io/assets/goong_map_web.json',
            center: [105.78812, 21.01652],
            zoom: 16
        });

        map.on('load', function() {
            map.addLayer({
                'id': 'lines',
                'type': 'line',
                'source': {
                    'type': 'geojson',
                    'data': {
                        'type': 'FeatureCollection',
                        'features': [{
                            'type': 'Feature',
                            'properties': {
                                'color': '#33C9EB' // blue
                            },
                            'geometry': {
                                'type': 'LineString',
                                'coordinates': [
                                    [21.01652, 105.78812],
                                    [21.01596, 105.78735],
                                    [21.01578, 105.78750],
                                    [21.01657, 105.78861],
                                    [21.01753, 105.79016],
                                    [21.01753, 105.79018],
                                    [21.01754, 105.79020],
                                    [21.01755, 105.79022],
                                    [21.01756, 105.79023],
                                    [21.01757, 105.79025],
                                    [21.01759, 105.79026],
                                    [21.01822, 105.79128],
                                    [21.01846, 105.79167],
                                    [21.01886, 105.79233],
                                    [21.01902, 105.79259],
                                    [21.01909, 105.79271],
                                    [21.01927, 105.79302],
                                    [21.01961, 105.79360],
                                    [21.01901, 105.79433],
                                    [21.01867, 105.79477],
                                    [21.01841, 105.79518],
                                    [21.01823, 105.79549],
                                    [21.01806, 105.79607],
                                    [21.01781, 105.79691],
                                    [21.01769, 105.79728],
                                    [21.01756, 105.79766],
                                    [21.01734, 105.79837],
                                    [21.01715, 105.79893],
                                    [21.01703, 105.79914],
                                    [21.01697, 105.79925],
                                    [21.01669, 105.79962],
                                    [21.01616, 105.80017],
                                    [21.01568, 105.80066],
                                    [21.01500, 105.80131],
                                    [21.01455, 105.80174],
                                    [21.01440, 105.80159],
                                    [21.01453, 105.80150],
                                    [21.01442, 105.80149]
                                ]
                            }
                        }]
                    }
                },
                'paint': {
                    'line-width': 3,
                    // to set the line-color to a feature property value.
                    'line-color': ['get', 'color']
                }
            });
        });
    </script>

</body>

</html>

Add a pattern to a polygon

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title>Add a pattern to a polygon</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
    <style>
        body {
            margin: 0;
            padding: 0;
        }

        #map {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }

        ;
    </style>
</head>

<body>
    <div id="map"></div>

    <script>
        goongjs.accessToken = '<your access token here>';
        var map = new goongjs.Map({
            container: 'map',
            style: 'http://tiles.goong.io/assets/goong_map_web.json',
            zoom: 1
        });

        map.on('load', function() {
            // Add GeoJSON data
            map.addSource('source', {
                'type': 'geojson',
                'data': {
                    'type': 'Feature',
                    'properties': {},
                    'geometry': {
                        'type': 'Polygon',
                        'coordinates': [
                            [
                                [-30, -25],
                                [-30, 35],
                                [30, 35],
                                [30, -25],
                                [-30, -25]
                            ]
                        ]
                    }
                }
            });

            // Load an image to use as the pattern
            map.loadImage(
                'https://upload.wikimedia.org/wikipedia/commons/thumb/6/60/Cat_silhouette.svg/64px-Cat_silhouette.svg.png',
                function(err, image) {
                    // Throw an error if something went wrong
                    if (err) throw err;

                    // Declare the image
                    map.addImage('pattern', image);

                    // Use it
                    map.addLayer({
                        'id': 'pattern-layer',
                        'type': 'fill',
                        'source': 'source',
                        'paint': {
                            'fill-pattern': 'pattern'
                        }
                    });
                }
            );
        });
    </script>

</body>

</html>

Create a gradient line using an expression

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Create a gradient line using an expression</title>
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>

	body { margin: 0; padding: 0; }
	#map { position: absolute; top: 0; bottom: 0; width: 100%; };

</style>
</head>
<body>
<div id="map"></div>

<script>

	goongjs.accessToken = '<your access token here>';
    var map = (window.map = new goongjs.Map({
        container: 'map',
        style: 'tiles.goong.io/assets/goong_map_web.json',
        center: [-77.035, 38.875],
        zoom: 12
    }));

    var geojson = {
        'type': 'FeatureCollection',
        'features': [
            {
                'type': 'Feature',
                'properties': {},
                'geometry': {
                    'coordinates': [
                                        [21.01652, 105.78812],
                                        [21.01596, 105.78735],
                                        [21.01578, 105.78750],
                                        [21.01657, 105.78861],
                                        [21.01753, 105.79016],
                                        [21.01753, 105.79018],
                                        [21.01754, 105.79020],
                                        [21.01755, 105.79022],
                                        [21.01756, 105.79023],
                                        [21.01757, 105.79025],
                                        [21.01759, 105.79026],
                                        [21.01822, 105.79128],
                                        [21.01846, 105.79167],
                                        [21.01886, 105.79233],
                                        [21.01902, 105.79259],
                                        [21.01909, 105.79271],
                                        [21.01927, 105.79302],
                                        [21.01961, 105.79360],
                                        [21.01901, 105.79433],
                                        [21.01867, 105.79477],
                                        [21.01841, 105.79518],
                                        [21.01823, 105.79549],
                                        [21.01806, 105.79607],
                                        [21.01781, 105.79691],
                                        [21.01769, 105.79728],
                                        [21.01756, 105.79766],
                                        [21.01734, 105.79837],
                                        [21.01715, 105.79893],
                                        [21.01703, 105.79914],
                                        [21.01697, 105.79925],
                                        [21.01669, 105.79962],
                                        [21.01616, 105.80017],
                                        [21.01568, 105.80066],
                                        [21.01500, 105.80131],
                                        [21.01455, 105.80174],
                                        [21.01440, 105.80159],
                                        [21.01453, 105.80150],
                                        [21.01442, 105.80149]
                    ],
                    'type': 'LineString'
                }
            }
        ]
    };

    map.on('load', function() {
        // 'line-gradient' can only be used with GeoJSON sources
        // and the source must have the 'lineMetrics' option set to true
        map.addSource('line', {
            type: 'geojson',
            lineMetrics: true,
            data: geojson
        });

        // the layer must be of type 'line'
        map.addLayer({
            type: 'line',
            source: 'line',
            id: 'line',
            paint: {
                'line-color': 'red',
                'line-width': 14,
                // 'line-gradient' must be specified using an expression
                // with the special 'line-progress' property
                'line-gradient': [
                    'interpolate',
                    ['linear'],
                    ['line-progress'],
                    0,
                    'blue',
                    0.1,
                    'royalblue',
                    0.3,
                    'cyan',
                    0.5,
                    'lime',
                    0.7,
                    'yellow',
                    1,
                    'red'
                ]
            },
            layout: {
                'line-cap': 'round',
                'line-join': 'round'
            }
        });
    });

</script>

</body>
</html>

Create a heatmap layer

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Create a heatmap layer</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>
	body { margin: 0; padding: 0; }
	#map { position: absolute; top: 0; bottom: 0; width: 100%; };
</style>
</head>
<body>
<div id="map"></div>

<script>
	goongjs.accessToken = '<your access token here>';
    var map = new goongjs.Map({
        container: 'map',
        style: 'tiles.goong.io/assets/goong_map_web.json',
        center: [-120, 50],
        zoom: 2
    });

    map.on('load', function() {
        // Add a geojson point source.
        // Heatmap layers also work with a vector tile source.
        map.addSource('earthquakes', {
            'type': 'geojson',
            'data':
                'https://docs.goong.io/assets/earthquakes.geojson'
        });

        map.addLayer(
            {
                'id': 'earthquakes-heat',
                'type': 'heatmap',
                'source': 'earthquakes',
                'maxzoom': 9,
                'paint': {
                    // Increase the heatmap weight based on frequency and property magnitude
                    'heatmap-weight': [
                        'interpolate',
                        ['linear'],
                        ['get', 'mag'],
                        0,
                        0,
                        6,
                        1
                    ],
                    // Increase the heatmap color weight weight by zoom level
                    // heatmap-intensity is a multiplier on top of heatmap-weight
                    'heatmap-intensity': [
                        'interpolate',
                        ['linear'],
                        ['zoom'],
                        0,
                        1,
                        9,
                        3
                    ],
                    // Color ramp for heatmap.  Domain is 0 (low) to 1 (high).
                    // Begin color ramp at 0-stop with a 0-transparancy color
                    // to create a blur-like effect.
                    'heatmap-color': [
                        'interpolate',
                        ['linear'],
                        ['heatmap-density'],
                        0,
                        'rgba(33,102,172,0)',
                        0.2,
                        'rgb(103,169,207)',
                        0.4,
                        'rgb(209,229,240)',
                        0.6,
                        'rgb(253,219,199)',
                        0.8,
                        'rgb(239,138,98)',
                        1,
                        'rgb(178,24,43)'
                    ],
                    // Adjust the heatmap radius by zoom level
                    'heatmap-radius': [
                        'interpolate',
                        ['linear'],
                        ['zoom'],
                        0,
                        2,
                        9,
                        20
                    ],
                    // Transition from heatmap to circle layer by zoom level
                    'heatmap-opacity': [
                        'interpolate',
                        ['linear'],
                        ['zoom'],
                        7,
                        1,
                        9,
                        0
                    ]
                }
            },
            'waterway-label'
        );

        map.addLayer(
            {
                'id': 'earthquakes-point',
                'type': 'circle',
                'source': 'earthquakes',
                'minzoom': 7,
                'paint': {
                    // Size circle radius by earthquake magnitude and zoom level
                    'circle-radius': [
                        'interpolate',
                        ['linear'],
                        ['zoom'],
                        7,
                        ['interpolate', ['linear'], ['get', 'mag'], 1, 1, 6, 4],
                        16,
                        ['interpolate', ['linear'], ['get', 'mag'], 1, 5, 6, 50]
                    ],
                    // Color circle by earthquake magnitude
                    'circle-color': [
                        'interpolate',
                        ['linear'],
                        ['get', 'mag'],
                        1,
                        'rgba(33,102,172,0)',
                        2,
                        'rgb(103,169,207)',
                        3,
                        'rgb(209,229,240)',
                        4,
                        'rgb(253,219,199)',
                        5,
                        'rgb(239,138,98)',
                        6,
                        'rgb(178,24,43)'
                    ],
                    'circle-stroke-color': 'white',
                    'circle-stroke-width': 1,
                    // Transition from heatmap to circle layer by zoom level
                    'circle-opacity': [
                        'interpolate',
                        ['linear'],
                        ['zoom'],
                        7,
                        0,
                        8,
                        1
                    ]
                }
            },
            'waterway-label'
        );
    });
</script>

</body>
</html>

Camera

Fit a map to a bounding box

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Fit a map to a bounding box</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>
	body { margin: 0; padding: 0; }
	#map { position: absolute; top: 0; bottom: 0; width: 100%; };
</style>
</head>
<body>
<style>
    #fit {
        display: block;
        position: relative;
        margin: 0px auto;
        width: 50%;
        height: 40px;
        padding: 10px;
        border: none;
        border-radius: 3px;
        font-size: 12px;
        text-align: center;
        color: #fff;
        background: #ee8a65;
    }
</style>
<div id="map"></div>
<br />
<button id="fit">Fit to Ha Noi</button>
<script>
	goongjs.accessToken = '<your access token here>';
    var map = new goongjs.Map({
        container: 'map',
        style: 'https://tiles.goong.io/assets/goong_map_web.json',
        center: [105, 10],
        zoom: 9
    });

    document.getElementById('fit').addEventListener('click', function() {
        map.fitBounds([
            [106.0405383, 20.897641],
            [105.660609, 21.165533]
        ]);
    });
</script>

</body>
</html>

Fly to a location

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Fly to a location</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>
	body { margin: 0; padding: 0; }
	#map { position: absolute; top: 0; bottom: 0; width: 100%; };
</style>
</head>
<body>
<style>
    #fly {
        display: block;
        position: relative;
        margin: 0px auto;
        width: 50%;
        height: 40px;
        padding: 10px;
        border: none;
        border-radius: 3px;
        font-size: 12px;
        text-align: center;
        color: #fff;
        background: #ee8a65;
    }
</style>
<div id="map"></div>
<br />
<button id="fly">Fly</button>
<script>
	goongjs.accessToken = '<your access token here>';
    var map = new goongjs.Map({
        container: 'map',
        style: 'https://tiles.goong.io/assets/goong_map_web.json',
        center: [-74.5, 40],
        zoom: 9
    });

    document.getElementById('fly').addEventListener('click', function() {
        // Fly to a random location by offsetting the point -74.50, 40
        // by up to 5 degrees.
        map.flyTo({
            center: [
                -74.5 + (Math.random() - 0.5) * 10,
                40 + (Math.random() - 0.5) * 10
            ]
        });
    });
</script>

</body>
</html>

Set pitch and bearing

drawing

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Set pitch and bearing</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>
	body { margin: 0; padding: 0; }
	#map { position: absolute; top: 0; bottom: 0; width: 100%; };
</style>
</head>
<body>
<div id="map"></div>
<script>
	goongjs.accessToken = '<your access token here>';
    var map = new goongjs.Map({
        container: 'map',
        style: 'https://tiles.goong.io/assets/goong_map_web.json',        
        center: [105], 21],
        pitch: 60, // pitch in degrees
        bearing: -60, // bearing in degrees
        zoom: 10
    });
</script>

</body>
</html>

Controls and Overlays

Add custom icons with Markers

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Add custom icons with Markers</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>
	body { margin: 0; padding: 0; }
	#map { position: absolute; top: 0; bottom: 0; width: 100%; };
</style>
</head>
<body>
<style>
    .marker {
        display: block;
        border: none;
        border-radius: 50%;
        cursor: pointer;
        padding: 0;
    }
</style>

<div id="map"></div>

<script>
	goongjs.accessToken = '<your access token here>';
    var geojson = {
        'type': 'FeatureCollection',
        'features': [
            {
                'type': 'Feature',
                'properties': {
                    'message': 'Foo',
                    'iconSize': [60, 60]
                },
                'geometry': {
                    'type': 'Point',
                    'coordinates': [-66.324462890625, -16.024695711685304]
                }
            },
            {
                'type': 'Feature',
                'properties': {
                    'message': 'Bar',
                    'iconSize': [50, 50]
                },
                'geometry': {
                    'type': 'Point',
                    'coordinates': [-61.2158203125, -15.97189158092897]
                }
            },
            {
                'type': 'Feature',
                'properties': {
                    'message': 'Baz',
                    'iconSize': [40, 40]
                },
                'geometry': {
                    'type': 'Point',
                    'coordinates': [-63.29223632812499, -18.28151823530889]
                }
            }
        ]
    };

    var map = new goongjs.Map({
        container: 'map',
        style: 'https://tiles.goong.io/assets/goong_map_web.json',
        center: [-65.017, -16.457],
        zoom: 5
    });

    // add markers to map
    geojson.features.forEach(function(marker) {
        // create a DOM element for the marker
        var el = document.createElement('div');
        el.className = 'marker';
        el.style.backgroundImage =
            'url(https://placekitten.com/g/' +
            marker.properties.iconSize.join('/') +
            '/)';
        el.style.width = marker.properties.iconSize[0] + 'px';
        el.style.height = marker.properties.iconSize[1] + 'px';

        el.addEventListener('click', function() {
            window.alert(marker.properties.message);
        });

        // add marker to map
        new goongjs.Marker(el)
            .setLngLat(marker.geometry.coordinates)
            .addTo(map);
    });
</script>

</body>
</html>

View fullscreen map

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>View a fullscreen map</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>
	body { margin: 0; padding: 0; }
	#map { position: absolute; top: 0; bottom: 0; width: 100%; };
</style>
</head>
<body>
<div id="map"></div>

<script>
	goongjs.accessToken = '<your access token here>';
    var map = new goongjs.Map({
        container: 'map', // container id
        style: 'https://tiles.goong.io/assets/goong_map_web.json', //stylesheet location
        center: [11.255, 43.77], // starting position
        zoom: 13 // starting zoom
    });

    map.addControl(new goongjs.FullscreenControl());
</script>

</body>
</html>

Locate the user

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Locate the user</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>
	body { margin: 0; padding: 0; }
	#map { position: absolute; top: 0; bottom: 0; width: 100%; };
</style>
</head>
<body>
<div id="map"></div>
<script>
	goongjs.accessToken = '<your access token here>';
    var map = new goongjs.Map({
        container: 'map', // container id
        style: 'https://tiles.goong.io/assets/goong_map_web.json',
        center: [-96, 37.8], // starting position
        zoom: 3 // starting zoom
    });

    // Add geolocate control to the map.
    map.addControl(
        new goongjs.GeolocateControl({
            positionOptions: {
                enableHighAccuracy: true
            },
            trackUserLocation: true
        })
    );
</script>

</body>
</html>

Display map navigation control

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Display map navigation controls</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>
	body { margin: 0; padding: 0; }
	#map { position: absolute; top: 0; bottom: 0; width: 100%; };
</style>
</head>
<body>
<div id="map"></div>
<script>
	goongjs.accessToken = '<your access token here>';
    var map = new goongjs.Map({
        container: 'map', // container id
        style: 'https://tiles.goong.io/assets/goong_map_web.json',
        center: [105, 21], // starting position
        zoom: 9 // starting zoom
    });

    // Add zoom and rotation controls to the map.
    map.addControl(new goongjs.NavigationControl());
</script>

</body>
</html>

Check Browser Support

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Check for browser support</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>
	body { margin: 0; padding: 0; }
	#map { position: absolute; top: 0; bottom: 0; width: 100%; };
</style>
</head>
<body>
<div id="map"></div>

<script>
	goongjs.accessToken = '<your access token here>';
    if (!goongjs.supported()) {
        alert('Your browser does not support Goong JS');
    } else {
        var map = new goongjs.Map({
            container: 'map',
            style: 'https://tiles.goong.io/assets/goong_map_web.json',
            center: [105, 21],
            zoom: 9
        });
    }
</script>

</body>
</html>

User interaction

Disable map rotation

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title>Disable map rotation</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
    <style>
        body {
            margin: 0;
            padding: 0;
        }

        #map {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }

        ;
    </style>
</head>

<body>
    <div id="map"></div>
    <script>
        goongjs.accessToken = '<your access token here>';
        var map = new goongjs.Map({
            container: 'map', // container id
            style: 'https://tiles.goong.io/assets/goong_map_web.json', //stylesheet location
            center: [-122.65, 45.52], // starting position
            zoom: 9 // starting zoom
        });

        // disable map rotation using right click + drag
        map.dragRotate.disable();

        // disable map rotation using touch rotation gesture
        map.touchZoomRotate.disableRotation();
    </script>

</body>

</html>

Create draggable marker

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title>Create a draggable Marker</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
    <style>
        body {
            margin: 0;
            padding: 0;
        }

        #map {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }

        ;
    </style>
</head>

<body>
    <style>
        .coordinates {
            background: rgba(0, 0, 0, 0.5);
            color: #fff;
            position: absolute;
            bottom: 40px;
            left: 10px;
            padding: 5px 10px;
            margin: 0;
            font-size: 11px;
            line-height: 18px;
            border-radius: 3px;
            display: none;
        }
    </style>

    <div id="map"></div>
    <pre id="coordinates" class="coordinates"></pre>

    <script>
        goongjs.accessToken = '<your access token here>';
        var coordinates = document.getElementById('coordinates');
        var map = new goongjs.Map({
            container: 'map',
            style: 'https://tiles.goong.io/assets/goong_map_web.json',
            center: [0, 0],
            zoom: 2
        });

        var marker = new goongjs.Marker({
                draggable: true
            })
            .setLngLat([0, 0])
            .addTo(map);

        function onDragEnd() {
            var lngLat = marker.getLngLat();
            coordinates.style.display = 'block';
            coordinates.innerHTML =
                'Longitude: ' + lngLat.lng + '<br />Latitude: ' + lngLat.lat;
        }

        marker.on('dragend', onDragEnd);
    </script>

</body>

</html>

Create a hover effect

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title>Create a hover effect</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
    <style>
        body {
            margin: 0;
            padding: 0;
        }

        #map {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }

        ;
    </style>
</head>

<body>
    <div id="map"></div>
    <script>
        goongjs.accessToken = '<your access token here>';
        var map = new goongjs.Map({
            container: 'map',
            style: 'https://tiles.goong.io/assets/goong_map_web.json',
            center: [-100.486052, 37.830348],
            zoom: 2
        });
        var hoveredStateId = null;

        map.on('load', function() {
            map.addSource('states', {
                'type': 'geojson',
                'data': 'https://docs.goong.io/assets/us_states.geojson'
            });

            // The feature-state dependent fill-opacity expression will render the hover effect
            // when a feature's hover state is set to true.
            map.addLayer({
                'id': 'state-fills',
                'type': 'fill',
                'source': 'states',
                'layout': {},
                'paint': {
                    'fill-color': '#627BC1',
                    'fill-opacity': [
                        'case',
                        ['boolean', ['feature-state', 'hover'], false],
                        1,
                        0.5
                    ]
                }
            });

            map.addLayer({
                'id': 'state-borders',
                'type': 'line',
                'source': 'states',
                'layout': {},
                'paint': {
                    'line-color': '#627BC1',
                    'line-width': 2
                }
            });

            // When the user moves their mouse over the state-fill layer, we'll update the
            // feature state for the feature under the mouse.
            map.on('mousemove', 'state-fills', function(e) {
                if (e.features.length > 0) {
                    if (hoveredStateId) {
                        map.setFeatureState({
                            source: 'states',
                            id: hoveredStateId
                        }, {
                            hover: false
                        });
                    }
                    hoveredStateId = e.features[0].id;
                    map.setFeatureState({
                        source: 'states',
                        id: hoveredStateId
                    }, {
                        hover: true
                    });
                }
            });

            // When the mouse leaves the state-fill layer, update the feature state of the
            // previously hovered feature.
            map.on('mouseleave', 'state-fills', function() {
                if (hoveredStateId) {
                    map.setFeatureState({
                        source: 'states',
                        id: hoveredStateId
                    }, {
                        hover: false
                    });
                }
                hoveredStateId = null;
            });
        });
    </script>

</body>

</html>

Get coordinates of the mouse pointer

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title>Get coordinates of the mouse pointer</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
    <style>
        body {
            margin: 0;
            padding: 0;
        }

        #map {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }

        ;
    </style>
</head>

<body>
    <style type="text/css">
        #info {
            display: block;
            position: relative;
            margin: 0px auto;
            width: 50%;
            padding: 10px;
            border: none;
            border-radius: 3px;
            font-size: 12px;
            text-align: center;
            color: #222;
            background: #fff;
        }
    </style>
    <div id="map"></div>
    <pre id="info"></pre>
    <script>
        goongjs.accessToken = '<your access token here>';
        var map = new goongjs.Map({
            container: 'map', // container id
            style: 'https://tiles.goong.io/assets/goong_map_web.json',
            center: [-74.5, 40], // starting position
            zoom: 9 // starting zoom
        });

        map.on('mousemove', function(e) {
            document.getElementById('info').innerHTML =
                // e.point is the x, y coordinates of the mousemove event relative
                // to the top-left corner of the map
                JSON.stringify(e.point) +
                '<br />' +
                // e.lngLat is the longitude, latitude geographical position of the event
                JSON.stringify(e.lngLat.wrap());
        });
    </script>

</body>

</html>

Fit to the bounds of a LineString

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Fit to the bounds of a LineString</title>
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@goongmaps/goong-js@1.0.2/dist/goong-js.css" rel="stylesheet" />
<style>

    body { margin: 0; padding: 0; }
    #map { position: absolute; top: 0; bottom: 0; width: 100%; };

</style>
</head>
<body>
<style>

    .btn-control {
        font: bold 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
        background-color: #3386c0;
        color: #fff;
        position: absolute;
        top: 20px;
        left: 50%;
        z-index: 1;
        border: none;
        width: 200px;
        margin-left: -100px;
        display: block;
        cursor: pointer;
        padding: 10px 20px;
        border-radius: 3px;
    }

    .btn-control:hover {
        background-color: #4ea0da;
    }

</style>
<div id="map"></div>
<button id="zoomto" class="btn-control">Zoom to bounds</button>

<script>
    goongjs.accessToken = 'your access token';
    // A GeoJSON object with a LineString route from the White House to Capitol Hill
    var geojson = {
        'type': 'FeatureCollection',
        'features': [
            {
                'type': 'Feature',
                'geometry': {
                    'type': 'LineString',
                    'properties': {},
                    'coordinates': [
                                        [ 105.78812, 21.01652],
                                        [ 105.78735, 21.01596],
                                        [ 105.78750, 21.01578],
                                        [ 105.78861, 21.01657],
                                        [ 105.79016, 21.01753],
                                        [ 105.79018, 21.01753],
                                        [ 105.79020, 21.01754],
                                        [ 105.79022, 21.01755],
                                        [ 105.79023, 21.01756],
                                        [ 105.79025, 21.01757],
                                        [ 105.79026, 21.01759],
                                        [ 105.79128, 21.01822],
                                        [ 105.79167, 21.01846],
                                        [ 105.79233, 21.01886],
                                        [ 105.79259, 21.01902],
                                        [ 105.79271, 21.01909],
                                        [ 105.79302, 21.01927],
                                        [ 105.79360, 21.01961],
                                        [ 105.79433, 21.01901],
                                        [ 105.79477, 21.01867],
                                        [ 105.79518, 21.01841],
                                        [ 105.79549, 21.01823],
                                        [ 105.79607, 21.01806],
                                        [ 105.79691, 21.01781],
                                        [ 105.79728, 21.01769],
                                        [ 105.79766, 21.01756],
                                        [ 105.79837, 21.01734],
                                        [ 105.79893, 21.01715],
                                        [ 105.79914, 21.01703],
                                        [ 105.79925, 21.01697],
                                        [ 105.79962, 21.01669],
                                        [ 105.80017, 21.01616],
                                        [ 105.80066, 21.01568],
                                        [ 105.80131, 21.01500],
                                        [ 105.80174, 21.01455],
                                        [ 105.80159, 21.01440],
                                        [ 105.80150, 21.01453],
                                        [ 105.80149, 21.01442]
                    ]
                }
            }
        ]
    };

    var map = new goongjs.Map({
        container: 'map',
        style: 'https://tiles.goong.io/assets/goong_map_web.json',
        center: [105.78812, 21.01652],
        zoom: 12
    });

    map.on('load', function() {
        map.addLayer({
            'id': 'LineString',
            'type': 'line',
            'source': {
                'type': 'geojson',
                'data': geojson
            },
            'layout': {
                'line-join': 'round',
                'line-cap': 'round'
            },
            'paint': {
                'line-color': '#BF93E4',
                'line-width': 5
            }
        });

        document.getElementById('zoomto').addEventListener('click', function() {
            // Geographic coordinates of the LineString
            var coordinates = geojson.features[0].geometry.coordinates;

            // Pass the first coordinates in the LineString to `lngLatBounds` &
            // wrap each coordinate pair in `extend` to include them in the bounds
            // result. A variation of this technique could be applied to zooming
            // to the bounds of multiple Points or Polygon geomteries - it just
            // requires wrapping all the coordinates with the extend method.
            var bounds = coordinates.reduce(function(bounds, coord) {
                return bounds.extend(coord);
            }, new goongjs.LngLatBounds(coordinates[0], coordinates[0]));

            map.fitBounds(bounds, {
                padding: 20
            });
        });
    });

</script>

</body>
</html>