Skip to main content

How to limit zoom and tilt in a 3D map

UPDATED: | POSTED: | by Stefan Schüttenkopf

In this tutorial we walk you through the steps to limit the zoom as well as the tilt for your 3D application in order to increase performance.
💡
The code snippets seen here, can also be dragged and dropped from our code snippets area found in the M.App Enterprise App Engine

Code injection to your 3D browser application

Go to Studio → Browser → M.Apps and click on the Open in editor icon.

Go to Studio -> Browser -> M.Apps and click on the Open in editor icon.

function main() {
    window.map.stores.navigation.pitchBounds3D = {minPitch: -90, maxPitch: -40};
    window.map.stores.navigation.altitudeBounds3D = {minAltitude: 20, maxAltitude: 2000};
}

pitchBounds3D

In the above mentioned example the user is allowed to tilt to a maximum degree of 50°.

minPitch By default -90°, which means nadir = straight down look

maxPitch The maximum tilt angle. Must be between -90° and 0°. For Google-like tilt you have to set the value to -34°, which gives you an tilt angle of 66°

altitudeBounds3D

In the above mentioned example the user is allowed to zoom in to a "flight height" of 20m and to zoom out to 2000m.

If you want to have an advanced tutorial - please read on

Combine flight height with visibility of layers

This advanced tutorial takes the above learned code snippet and combine it with the visibility changes of layers in your 3D map.

import { PerspectiveCamera } from '@luciad/ria/view/camera/PerspectiveCamera';
import * as ReferenceProvider from '@luciad/ria/reference/ReferenceProvider';
import * as TransformationFactory from '@luciad/ria/transformation/TransformationFactory';
import { LayerTreeNode } from '@luciad/ria/view/LayerTreeNode';

function findLayerByName(name: string) {

    function _findLayerByName(name: string, node: LayerTreeNode) {
        if(node.label === name)
            return node;
        
        for(let child of node.children) {
            let result = _findLayerByName(name, child);
            if(result)
                return result;
        }

        return undefined;
    }
    for(let childNode of window.map.layerTree.children) {
        let result = _findLayerByName(name, childNode);
        if(result)
            return result;
    }

    return undefined;
}

function applyFlightHeightSwitch(flightHeightUpperBound: number, layername: string) {

    const localCRS = ReferenceProvider.getReference("EPSG:xxxxx");
	const localToWorld = TransformationFactory.createTransformation(window.map.reference, localCRS);
    
    const ThemeName = findLayerByName(layername);
    const allChildren = window.map.getAllLayers(ThemeName);

    let savedState: any = undefined;

    window.map.on('MapChange', () => {
        const camera = window.map.camera as PerspectiveCamera;
        const wgs84Point = localToWorld.transform(camera.eyePoint);

        if(wgs84Point.z > flightHeightUpperBound && savedState === undefined) {
            savedState = {};
            allChildren.forEach(c => {
                 savedState[c.id] = c.visible;
                 c.visible = false;
            })
        } else if(wgs84Point.z < flightHeightUpperBound && savedState !== undefined) {
            allChildren.forEach(c => {
                if(savedState[c.id]) {
                    c.visible = savedState[c.id];
                }
            });
            savedState = undefined;
        }
    })
} 

Line 31: EPSG:xxxxx defines the EPSG code of your local CRS

Now you can use applyFlightHeightSwitch function within the main function of your browser application and as per definition you have to set the flightHeightUpperBounds in metre and the themeName, for which the layers should get invisible.

function main() {
    applyFlightHeightSwitch(700, 'Photovoltaik');
}