Creating a Custom TEF Application

You can create custom TerraExplorer Fusion applications by using iframes to embed the TEF window in your custom HTML. The TerraExplorer and Fusion APIs, can then be used together with any other script to customize your application. See "Adding Custom TEF Tools" in this chapter for information.

A screenshot of a computer Description automatically generated with medium confidence

To create a custom TEF application:

1.     Copy the entire .\TerraExplorerFusion directory to your server and place it next to your web application.

2.     In your HTML file, create the TEF iframe element and link it to the TE.html page:

 <iframe id='tef' src="./TEF/TE.html" class="tef"/>

3.     Add custom URL parameters to control different TerraExplorer Fusion characteristics such as the project to load, a custom styling file (css) to hide/restyle GUI elements, start location etc. See "URL Parameters" in this chapter for information.

 <iframe id='tef' src="./TEF/TE.html?project=https://cloud.skylineglobe.com/SG/demos/projects/Mexico_Beach_Emergency_Response&css=sampleCustomizedGUI" class="tef"/>

4.     Add the onTEFInit callback function that will be called when TEF initializes. In this callback you can get the TerraExplorer main API interface, SGWorld, and use it to add and control elements in the 3D view:

function onTEFInit(event) {
            SGWorld = document.getElementById('tef').contentWindow.SGWorld;
}

5.     Add the onTEFProjectLoaded callback function that will be called when the project is loaded:

function onTEFProjectLoaded(event) {
            var position= SGWorld.Creator.CreatePosition (-97.0, 38.0, 100, 0, -70,0,500);
            SGWorld.Navigate.FlyTo (position);
}

Note     A sample custom TEF application file called sampleTEinIFrame.html is included in the application files of TerraExplorer Fusion under custom (.\custom\sampleTEinIFrame.html). This demo initializes the TEF and offers three options: Load with GUI, Load without GUI, and Load with Customized GUI.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <script src="../js/jquery-3.6.0.min.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"

        integrity="sha384-aFq/bzH65dt+w6FI2ooMVUpc+21e0SRygnTpmBvdBgSdnuTN7QbdgL+OapgHtvPp" crossorigin="anonymous">

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"

        integrity="sha384-qKXV1j0HvMUeCBQ+QVp7JcfGl760yU08IQ+GpUo5hlbpg51QRiuqHAJz8+BrxE/N"
        crossorigin="anonymous"></script>
    <script language="javascript" src="../Tools/ToolsCommon80.js"></script>
    <style>
        body {
            width: 100%;
            height: 100%;
            background-color: #DCDCDC;
        }
        .leftBar {
            background-color: beige;
            min-height: 80vh;
        }
        .tef {
            width: 100%;
            height: 80vh;
            background-color: #eeeee4;
        }
        button {
            width: 40%;
            height: 60px;
        }
        div.lead {
            margin-left: 10px;
        }
        .caption{
            margin: 0px auto;
            width: 35%;
            text-align: center;
        }
    </style>
    <script>
        var SGWorld = null;
        var TEF = null;
        $(() => {
            TEF = document.getElementById('tef');
        });
        function onTEFInit(event) {
            SGWorld = TEF.contentWindow.SGWorld;
            SGWorld.AttachEvent('OnRenderQualityChanged', OnRenderQualityChanged);
        }
        function onTEFProjectLoaded(event) {
            $("#analysisButtons").show();
        }
        function loadTEF(GUI) {
            var guiURL = (GUI) ? "" : "&script=sampleCustomButtons.js&css=sampleCustomButtons";
            $("#tef").attr('src', "../te.html?project=https://cloud.skylineglobe.com/sg/demos/projects/Mexico_Beach_Emergency_Response" + guiURL);
        }
        function loadPartialTEF() {
            var guiURL = "&css=sampleCustomizedGUI";
            $("#tef").attr('src', "../te.html?project=https://cloud.skylineglobe.com/sg/demos/projects/Mexico_Beach_Emergency_Response" + guiURL);
        }
        function rotate() {
            if (SGWorld === null)
                alert("TEF not loaded");
            else
                SGWorld.Command.Execute(1057, 0);
        }
        function distance() {
            if (SGWorld === null)
                alert("TEF not loaded");
            else
                TEF.contentWindow.analysis.openAnalysisToolURL('./Tools/DistanceMeasurement/distanceMeasurement.html', 'distance', false);
        }
        function area() {
            if (SGWorld === null)
                alert("TEF not loaded");
            else
                TEF.contentWindow.analysis.openAnalysisToolURL('./Tools/AreaMeasurement/AreaMeasurement.html', 'area', false);
        }
        function volume() {
            if (SGWorld === null)
                alert("TEF not loaded");
            else
                TEF.contentWindow.analysis.openAnalysisToolURL('./Tools/Volume/Volume.html', 'volume', false);
        }
        function profile() {
            if (SGWorld === null)
                alert("TEF not loaded");
            else
                TEF.contentWindow.analysis.openAnalysisToolURL('./Tools/TerrainProfile/TerrainProfile.html', 'profile', false);
        }
        function viewshed() {
            if (SGWorld === null)
                alert("TEF not loaded");
            else
                TEF.contentWindow.analysis.openAnalysisToolURL('./Tools/ImageComparison/MeshComparisonPopup.html', 'compare', false);
        }
        function home() {
            if (SGWorld === null)
                alert("TEF not loaded");
            else
                TEF.contentWindow.navigate.home();
        }
        function OnRenderQualityChanged(quality) {
            $("#buffer").text(quality)
            return false;
        }
        function draw(type) {
            var position = SGWorld.Window.PixelToWorld(SGWorld.Window.Rect.Width / 2, SGWorld.Window.Rect.Height / 2, 0).Position;
            var radius = SGWorld.Navigate.GetPosition(0).DistanceTo(position) / 20;
            var group = TEF.contentWindow.projectTree.getMyDataGroup();
            switch (type) {
                case 0:
                    SGWorld.Creator.CreateCircle(position, radius, SGWorld.Creator.CreateColor(0, 255, 0, 1), SGWorld.Creator.CreateColor(0, 0, 0, 0), group, "circle");
                    break;
                case 1:
                    SGWorld.Creator.CreateArrow(position, radius, 4, SGWorld.Creator.CreateColor(0, 255, 0, 1), SGWorld.Creator.CreateColor(0, 0, 0, 0), group, "arrow");
                    break;
                case 2:
                    SGWorld.Creator.CreateBox(position, radius, radius, radius, SGWorld.Creator.CreateColor(0, 255, 0, 1), SGWorld.Creator.CreateColor(120, 10, 200, 100), group, "box");
                    break;
                default:
                    break;
            }
            TEF.contentWindow.projectTree.refreshMyData();
        }
    </script>
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="jumbotron p-0">
                <h1 class="i18n display-4">Header</h1>
                <p class="i18n lead">SmallHeader</p>
                <hr class="my-4">
                <p class="i18n">AboutHeader</p>
            </div>
        </div>
        <div class="row">
            <div class="col-3 leftBar">
                <p class="caption"><strong><u class="i18n">CaptionGUI</u></strong></p>
                <button class="i18n btn btn-secondary my-1 mx-md-1 mx-lg-2" onclick="loadTEF(true);">ButtonLoadWithGUI</button>
                <button class="i18n btn btn-secondary my-1 mx-md-1 mx-lg-2" onclick="loadTEF(false)">ButtonLoadWithoutGUI</button>
                <button class="i18n btn btn-secondary my-1 mx-md-1 mx-lg-2" onclick="loadPartialTEF()">ButtonLoadPartialGUI</button> <br>
                <hr>
                <div id="analysisButtons" style="display:none">
                    <p class="caption"><strong><u class="i18n">CaptionTEFTools</u></strong></p>
                    <button class="i18n btn btn-secondary my-1 mx-md-1 mx-lg-2" onclick="distance();">ButtonDistance</button>
                    <button class="i18n btn btn-secondary my-1 mx-md-1 mx-lg-2" onclick="area();">ButtonArea</button>
                    <button class="i18n btn btn-secondary my-1 mx-md-1 mx-lg-2" onclick="volume();">ButtonVolume</button>
                    <button class="i18n btn btn-secondary my-1 mx-md-1 mx-lg-2" onclick="profile();">ButtonProfile</button>
                    <button class="i18n btn btn-secondary my-1 mx-md-1 mx-lg-2" onclick="viewshed()">ButtonLayerComparison</button>
                    <hr>
                    <p class="caption"><strong><u class="i18n">CaptionActions</u></strong></p>
                    <button class="i18n btn btn-secondary my-1 mx-md-1 mx-lg-2" onclick="rotate()">ButtonRotate</button>
                    <button class="i18n btn btn-secondary my-1 mx-md-1 mx-lg-2" onclick="home()">ButtonHome</button>
                    <button class="i18n btn btn-secondary my-1 mx-md-1 mx-lg-2" onclick="draw(0);">ButtonDrawCircle</button>
                    <button class="i18n btn btn-secondary my-1 mx-md-1 mx-lg-2" onclick="draw(1);">ButtonDrawArrow</button>
                    <button class="i18n btn btn-secondary my-1 mx-md-1 mx-lg-2" onclick="draw(2);">ButtonDrawBox</button>
                    <hr>
                    <p class="caption"><strong><u class="i18n">CaptionEvents</u></strong></p>
                    <div class="lead pl-4">
                        Quality: <span id="buffer"></span>
                    </div>
                </div>
            </div>
            <div class="col-8">
                <iframe id='tef' src="" class="tef" />
            </div>
        </div>
    </div>
</body>
</html>