Skip to content

Elevation along a line

This example demonstrates the elevation API post request for creating an elevation graph. By integrating an elevation API, each segment of the drawn line is processed to retrieve elevation information. The elevation data is visually represented using Chart.js, offering users a clear and dynamic chart that illustrates the changes in elevation along the drawn path.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <script src="https://cdn.smartmaps.cloud/packages/smartmaps/smartmaps-gl/v2/umd/smartmaps-gl.min.js" defer></script>
        <script src="/assets/src/chart.js" defer></script>
        <style>
            body {
                margin: 0;
                padding: 0;
            }

            html,
            body,
            #map {
                height: 100%;
            }

            #controls {
                position: absolute;
                top: 10px;
                left: 10px;
                background: white;
                padding: 10px;
                z-index: 1;
            }

            #chart-container {
                position: absolute;
                display: none;
                bottom: 40px;
                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.16), 0 2px 4px rgba(0, 0, 0, 0.23);
                left: 10px;
                width: 400px;
                height: 200px;
                background: white;
                padding: 10px;
                z-index: 1;
            }
        </style>
    </head>

    <body>
        <div id="map"></div>
        <div id="controls">
            <button id="draw-line">Draw line</button>
            <button id="reset-line">Reset</button>
        </div>
        <div id="chart-container">
            <canvas id="elevation-chart"></canvas>
        </div>
        <script>
            document.addEventListener('DOMContentLoaded', () => {
                const map = new smartmapsgl.Map({
                    apiKey: "INSERT API-KEY",
                    container: "map",
                    center: { lat: 46, lng: 8 },
                    zoom: 9,
                    style: smartmapsgl.MapStyle.AUTO,
                    terrain: {
                        activated: true
                    }
                });

                let drawingMode = false;
                let lineCoordinates = [];

                const drawLineButton = document.getElementById('draw-line');
                drawLineButton.addEventListener('click', () => {
                    drawingMode = !drawingMode;
                    drawLineButton.textContent = drawingMode ? 'Calculate elevation' : 'Draw line';

                    if (!drawingMode) {
                        getElevationProfile(lineCoordinates);
                        document.getElementById('chart-container').style.display = 'block';
                    }
                });

                const resetLineButton = document.getElementById('reset-line');
                resetLineButton.addEventListener('click', () => {
                    resetLine();
                });

                map.on('click', (e) => {
                    if (drawingMode) {
                        lineCoordinates.push([e.lngLat.lng, e.lngLat.lat]);

                        if (lineCoordinates.length > 1) {
                            map.addLayer({
                                id: 'line',
                                type: 'line',
                                source: {
                                    type: 'geojson',
                                    data: {
                                        type: 'Feature',
                                        geometry: {
                                            type: 'LineString',
                                            coordinates: lineCoordinates
                                        }
                                    }
                                },
                                paint: {
                                    'line-color': '#18345c',
                                    'line-width': 3
                                }
                            });
                        }
                    }
                });

                function resetLine() {
                    if (map.getLayer('line')) {
                        map.removeLayer('line');
                        map.removeSource('line');
                    }
                    if (map.getLayer('hovered-point')) {
                        map.removeLayer('hovered-point');
                        map.removeSource('hovered-point');
                    }
                    lineCoordinates = [];
                    if (chart) {
                        chart.destroy();
                    }
                    document.getElementById('chart-container').style.display = 'none';
                }

                function getElevationProfile(coordinates) {
                    const points = [];
                    const distance = 300; //Distance between the points in meters

                    for (let i = 0; i < coordinates.length - 1; i++) {
                        const startPoint = coordinates[i];
                        const endPoint = coordinates[i + 1];
                        const numPoints = Math.floor(getDistance(startPoint[1], startPoint[0], endPoint[1], endPoint[0]) / distance);

                        for (let j = 0; j <= numPoints; j++) {
                            const t = j / numPoints;
                            const lat = startPoint[1] + t * (endPoint[1] - startPoint[1]);
                            const lng = startPoint[0] + t * (endPoint[0] - startPoint[0]);
                            points.push({ latitude: lat, longitude: lng });
                        }
                    }

                    const url = 'https://elevation.smartmaps.cloud/api/v2/Elevation/point?apiKey=[INSERT_API-KEY]';

                    fetch(url, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify({
                            points: points
                        })
                    })
                        .then(response => response.json())
                        .then(data => {
                            const elevations = data.features.map(feature => feature.properties.elevation);
                            const distances = [0];

                            for (let i = 1; i < points.length; i++) {
                                const prevPoint = points[i - 1];
                                const currentPoint = points[i];
                                const dist = getDistance(prevPoint.latitude, prevPoint.longitude, currentPoint.latitude, currentPoint.longitude);
                                distances.push(distances[i - 1] + dist);
                            }

                            createElevationChart(distances, elevations, points);
                        })
                        .catch(error => console.error('Error fetching elevation data:', error));
                }

                function getDistance(lat1, lon1, lat2, lon2) {
                    const R = 6371e3; // Earth's radius in meters 
                    const φ1 = lat1 * Math.PI / 180;
                    const φ2 = lat2 * Math.PI / 180;
                    const Δφ = (lat2 - lat1) * Math.PI / 180;
                    const Δλ = (lon2 - lon1) * Math.PI / 180;

                    const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
                        Math.cos(φ1) * Math.cos(φ2) *
                        Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
                    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

                    return R * c;
                }

                let chart;
                function createElevationChart(distances, elevations, points) {
                    const ctx = document.getElementById('elevation-chart').getContext('2d');

                    if (chart) {
                        chart.destroy();
                    }

                    chart = new Chart(ctx, {
                        type: 'line',
                        data: {
                            labels: distances,
                            datasets: [{
                                label: 'Height',
                                data: elevations,
                                borderColor: '#18345c',
                                fill: true
                            }]
                        },
                        options: {
                            plugins: {
                                legend: {
                                    display: false
                                },
                                tooltip: {
                                    callbacks: {
                                        label: function (context) {
                                            return 'Height ' + context.parsed.y + ' m';
                                        }
                                    }
                                }
                            },
                            scales: {
                                x: {
                                    grid: {
                                        display: false
                                    },
                                    ticks: {
                                        display: false
                                    }
                                },
                                y: {
                                    grid: {
                                        display: false
                                    },
                                    title: {
                                        text: 'Height (m)'
                                    }
                                }
                            },
                            elements: {
                                point: {
                                    radius: 1,
                                    hoverRadius: 5,
                                    hitRadius: 5
                                }
                            },
                            onHover: (event, chartElement) => {
                                if (chartElement.length) {
                                    const index = chartElement[0].index;
                                    const hoveredPoint = points[index];
                                    addMarkerToMap(hoveredPoint.latitude, hoveredPoint.longitude);
                                }
                            }
                        }
                    });
                }

                function addMarkerToMap(lat, lng) {
                    // Remove existing marker if needed
                    if (map.getLayer('hovered-point')) {
                        map.removeLayer('hovered-point');
                        map.removeSource('hovered-point');
                    }

                    map.addLayer({
                        id: 'hovered-point',
                        type: 'circle',
                        source: {
                            type: 'geojson',
                            data: {
                                type: 'Feature',
                                geometry: {
                                    type: 'Point',
                                    coordinates: [lng, lat]
                                }
                            }
                        },
                        paint: {
                            'circle-radius': 5,
                            'circle-color': '#18345c'
                        }
                    });
                }
            });
        </script>
    </body>
</html>