Welcome to the Harris Geospatial product documentation center. Here you will find reference guides, help documents, and product libraries.


  >  Docs Center  >  Geospatial Services Framework  >  GSF Tutorial: WebApp Map Client

Geospatial Services Framework

GSF Tutorial: WebApp Map Client

GSF - Tutorial - WebApp Map Client

This tutorial demonstrates a multi-step workflow for creating a web application to analyze and visualize raster data overlaid on an interactive map. First, a new request handler must be created to support communication between the client and the server. The analytics require having access to an ENVI+IDL development environment and creating a custom ENVITask. A WebApp Map Client is then created to submit jobs requiring this custom task with the help of the custom request handler.

Note: As in other tutorials, the full example code blocks are provided here at the bottom of the page.

Create a WebApp Request Handler


A request handler is designed to support client access to the server. This tutorial sets up a webpage for a browser client to use. The browser then uses the GSF Javascript Client SDK to communicate with the server.

Create a new folder under the server directory named webapp-request-handler. This folder should contain these files, created during this tutorial:

Note: This tutorial provides the code for the webapp-request-handler needed for completing the WebApp Map Client tutorial. For an in-depth discussion of creating custom request handlers, see the Custom Request Handler Tutorial. As in other tutorials, the full example code blocks are provided here at the bottom of the page.

package.json

This file provides information about the request handler.

{
  "name": "Webapp-request-handler",
  "version": "1.0.0",
  "description": "Provides a web client for submitting a job to the server.",
  "main": "handler.js",
  "dependencies": {},
  "devDependencies": {},
  "scripts": {}
}

handler.js

This file contains the necessary code for the request handler.

var express = require('express');
/**
 * webappRequestHandler
 * Provides an endpoint for serving up a static HTML page for submitting jobs.
 */
function WebappRequestHandler() {
  this.init = function(app) {
    // Set up endpoint.
    app.use('/webapp/', express.static(__dirname + '/html/'));
  };
}
module.exports = WebappRequestHandler;

Configure The Server

The last step is to add the new webapp-request-handler to the list of request handlers. To do this from a command line, start a command prompt in the GSFxx directory and execute the following command:

node updateConfig.js config.json --arrayadd requestHandlers={\"type\":\"./webapp-request-handler\"}

The updateConfig.js script will automatically back up the original config.json file for you.

You may also manually enable the webapp-request-handler by editing the config.json as shown below. It is recommended that you back up your config file before making any changes manually.

  "requestHandlers": [
    ...,
    {
      "type": "./webapp-request-handler"
    }
  ],

Restart the server any time this file is changed so it reflects the new configuration.

Create a Bounding Box Task


Next, in order for the web application to place the raster over the correct map location, it must compute a bounding box. This ENVITask creates that bounding box, specifying the location and the extent of the raster in map coordinates. It takes as input a raster, and it returns the latitude and longitude coordinates of the farthest points within the raster in the four cardinal directions. The creation of this bounding box task requires three primary files: an IDL .pro file, an IDL .sav file, and an ENVI .task file. Save all of these files in the custom_code directory under the ENVI install (ex. linux: /usr/local/harris/envixx/custom_code/, windows: C:\Program Files\Harris\ENVIxx\custom_code).

Create the following files:

Note: As in other tutorials, the full example code blocks are provided here at the bottom of the page.

exampleboundingbox.pro

To create the ENVITask pro code, follow these steps.

  • Launch IDL
  • Copy the provided code into a new file.
  • Save the pro file as exampleboundingbox.pro in the ENVI install custom_code folder.

First, define the procedure. The compile option is recommended to ensure proper handling of arrays and array-indexing.

pro ExampleBoundingBox, INPUT_RASTER=inputRaster, $
                        NORTH=north, $
                        SOUTH=south, $
                        WEST=west, $
                        EAST=east
  compile_opt idl2                      
  ...
end

Check that the spatial reference information passed into the procedure is valid. Then proceed to extract column (sample) and row (line) information from the input raster.

  spatialRef = inputRaster.SpatialRef
  if (~Isa(spatialRef,'ENVIStandardRasterSpatialRef')) then begin
    message,'Input Raster must contain a standard spatial reference.'
  endif
  ns = inputRaster.NColumns
  nl = inputRaster.NRows   

Build the file-coordinate bounding box from the input raster's number of lines and samples. Convert first into map coordinates and then into latitude and longitude. The WebMap API requires latitude and longitude coordinates.

  fileBoundingBox = [[0,0],[ns-1,0],[0,nl-1],[ns-1,nl-1]]
  ; Convert to map coordinates 
  spatialRef.ConvertFileToMap, fileBoundingBox[0,*],fileBoundingBox[1,*], $
    mapBoundingBoxX, mapBoundingBoxY
  ; Convert to longitude/latitude coordinates.
  spatialRef.ConvertMapToLonLat, mapBoundingBoxX, mapBoundingBoxY, $
    boundingLon, boundingLat

Finally, separate the information into north, south, east, and west. Be aware that each WebMap API may require different formats for the bounding box. This WebMap API calls for cardinal directions.

  south = Min(boundingLat, MAX=north)
  west = Min(boundingLon, MAX=east)  

ExampleBoundingBox.task

To create the ENVITask task file, follow these steps.

  • Copy the below contents into a new file in the IDL editor.
  • Save the task file as ExampleBoundingBox.task in the ENVI install custom_code folder.

First, describe the properties of this task. For more information on creating ENVITasks, see the documentation provided at http://harrisgeospatial.com/docs/.

{
    "name": "ExampleBoundingBox",
    "baseClass": "ENVITaskFromProcedure",
    "routine": "exampleboundingbox",
    "displayName": "Lat/Lon Bounding Box",
    "description": "This task returns the farthest north, south, east, and west points of a raster in latitude/longitude.",
    "version": "5.3",
    "parameters": [
    ...
    ]
}

Next, populate the parameters array with the properties of the input raster and the four cardinal directions.

        {
            "name": "INPUT_RASTER",
            "displayName": "Input Raster",
            "dataType": "ENVIRASTER",
            "direction": "input",
            "parameterType": "required",
            "description": "Specify a raster with a standard projection to retrieve bounding box."
        },
        {
            "name": "NORTH",
            "displayName": "North",
            "dataType": "DOUBLE",
            "direction": "output",
            "parameterType": "required",
            "description": "The farthest north point."
        },
        {
            "name": "SOUTH",
            "displayName": "South",
            "dataType": "DOUBLE",
            "direction": "output",
            "parameterType": "required",
            "description": "The farthest south point."
        },
        {
            "name": "WEST",
            "displayName": "West",
            "dataType": "DOUBLE",
            "direction": "output",
            "parameterType": "required",
            "description": "The farthest west point."
        },
        {
            "name": "EAST",
            "displayName": "East",
            "dataType": "DOUBLE",
            "direction": "output",
            "parameterType": "required",
            "description": "The farthest east point."
        }

After completing the creation of exampleboundingbox.pro and exampleboundingbox.task you should verify the task executes successfully in your ENVI+IDL development environment.

First, verify the new ENVITask can load.

IDL>e=ENVI(/headless)
ENVI>task=ENVITask('ExampleBoundingBox')

Typically, if the above step fails it is due to the JSON syntax in the task file. A good resource for validating and correcting JSON is http://jsonlint.com.

Next, verify the task can execute the code contained within exampleboundingbox.pro

ENVI>file=FilePath('qb_boulder_msi',SUBDIR=['data'],ROOT_DIR=e.Root_Dir)
ENVI>raster=e.OpenRaster(file)
ENVI>task.Input_Raster = raster
ENVI>task.execute
ENVI>print, [[task.North,task.West],[task.South,task.East]]

The result printed should be:

       40.010834      -105.23121
       39.984964      -105.19757

exampleboundingbox.sav

By default, in GSF, the IDL/ENVI Service Engines require that IDL/ENVITasks are deployed with save files (.sav).

To generate an IDL save file you want a clean IDL session. Issue the following command at the IDL prompt.

.reset

Important: Open the exampleboundingbox.pro file in the IDL session, and compile it.

Then issue the save command with the location of your ENVI custom_code directory, changing "xx" to match the version of ENVI you are using (e.g. 54):

Linux

save, filename='/usr/local/harris/envixx/custom_code/exampleboundingbox.sav', /ROUTINES

Windows

save, filename='C:\Program Files\harris\envixx\custom_code\exampleboundingbox.sav', /ROUTINES

If your server environment has access to an equal number of IDL development licenses as GSF workers, you can update the engine configuration to pass the --compile flag through the "engineArgs" option to use the procedure file (.pro) instead.

To do this from a command line, start a command prompt in the GSFxx directory and execute the following command:

node updateConfig.js config.json --set engines[type:envi-service-engine].engineArgs=--compile

The updateConfig.js script will automatically back up the original config.json file for you.

You may also manually update the envi-service-engine by editing the config.json as shown below. It is recommended that you back up your config file before making any changes manually.

  "engines": [
    ...,
    {
      "type": "envi-service-engine",
      ...
      "engineArgs": "--compile"
    }
  ],

Create a WebApp Map Client


The WebApp Map Client created in this tutorial displays the result of the bounding box task and an ENVI raster analytic task overlayed on an interactive map, providing geographical context for satellite imagery.

Create the WebApp

Create a subfolder under the webapp-request-handler folder and name it html. Place the following files in the html folder.

Note: As in other tutorials, the full example code blocks are provided here at the bottom of the page.

index.html

Place the following code in an index.html file. The server, by default, serves up any file within this directory with the name index.html. The HTML page created from this file allows users to specify a task and its parameters and submit that task to the server.

First, set up the HTML file with the proper formatting.

<html>
<head>
    ...
</head>
<body>
  <!-- user input -->
  <form id="postJobForm" name="postJobForm">
    ...
  </form>
  ...
</body>
</html>

Filling in the head portion of the HTML file describes the support files to be loaded. Two of these files, GSFutils.js and style.css, are created as part of this tutorial.

    <title>GSF - GSF Web Map Example</title>
    <!-- Load stylesheet -->
    <link rel="stylesheet" href="style.css" />
    <!-- Load JQuery -->
    <script src="http://code.jquery.com/jquery-2.2.4.min.js"></script>
    <!-- Load ths GSF SDK -->
    <script src="../sdk/js/GSF.min.js"></script>

Then, the form section can be populated. The fieldset code block generates the fields the WebApp should display for taking user input, which here are Task, Input Raster in JSON format, and Input Parameters in JSON format. Since this is a tutorial, this code also auto-populates the fields with suggested input such as the SpectralIndex task. It describes the input raster type and the desired index. This block also defines the submit button to be added to the WebApp.

    <fieldset>
        <legend>Submit a Job</legend>
        Task:<br>
        <input id="Task" size="60" type="text" value="SpectralIndex"><br>
        <br>
        Input Raster (JSON): <br>
        <input id="inputRaster" size="80" type="text" value="http://localhost:9191/ese/data/qb_boulder_msi"><br>
        Input Parameters (JSON):<br>
        <textarea cols="80" id="InputParameters" name="inputs" rows="9">
{
    "INPUT_RASTER": {
      "FACTORY": "URLRaster",
      "URL":"%INPUT_RASTER%"
    },
    "INDEX": "Normalized Difference Vegetation Index"
}
        </textarea>
        <br>
        <button type="submit">Submit</button>
    </fieldset>

Outside of the form section but still within the body section, define labels for progress messages and map loading. Finally, load the JavaScript Leaflet library and the app.js WebApp logic file created later in this tutorial.

  <!-- This label shows the progress messages from the server -->
  <label id="progress"></label>
  <!-- this div will be where the webmap is loaded. -->
  <div id="map"> </div>
  <!-- load leaflet library -->
  <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.css" />
  <script src="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.js"></script>
  <!-- load our app logic -->
  <script src="app.js"></script>

style.css

This file contains the information for how the map should be displayed and styled.

#map {
  width:100%;
  height: 500px;
}

app.js

This JavaScript file contains the code for the WebApp. This WebApp uses Leaflet, a JavaScript interactive map library. The latitude and longitude coordinates given for the center of the map display are for a location in Boulder, CO. The input raster used in the bounding box task example is satellite imagery of Boulder, CO over this same area.

/**
 * Setup Leaflet
 */
var map = L.map('map', {
  center: [40.0150, -105.2705],
  zoom: 3
});
/**
 * Add basemap
 */
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

Here, a function invokes the bounding box task and overlays the raster on the map.

/**
 * Add an imageOverlay and zoom to it.
 */
function addImageToMap(imageUrl, boundingBox) {
  L.imageOverlay(imageUrl, boundingBox).addTo(map);
  map.fitBounds(boundingBox);
}

Users often desire progress messages during execution, so this function creates a handler.

/**
 * Generate a progress message handler
 */
function progressHandler(task) {
  return function(data) {
    $('#progress').text(task + ' ' + data.progress + '% ' + data.message);
  }
}

To ensure the images display and align properly, set the coordinate system.

/**
 * This coordSys should match the projection used in the webmap.
 * Leaflet uses 3857 by default.
 */
var coordSys = {
    FACTORY: "CoordSys",
    COORD_SYS_CODE: 3857
};

Create a connection to the GSF server from which this tutorial is hosted.

// Use the GSF server where this tutorial is hosted
var protocol = location.protocol.substring(0,location.protocol.length - 1);
var hostname = location.hostname;
var port = location.port;
// Create a server object
const server = GSF.server({
  protocol: protocol,
  address: hostname,
  port: port
});

Create an ENVI Service object, and Task objects for the known tasks we will use.

// Create an ENVI service object
const service = server.service('ENVI');
// Create a task object for each task we will use
const exportRasterTaskName = 'ExportRasterToPNG';
const exportRasterTask = service.task(exportRasterTaskName);
const boundingBoxTaskName = 'ExampleBoundingBox';
const boundingBoxTask = service.task(boundingBoxTaskName);

The code must also set up the submit button for the WebApp. To do this, get and parse input and task names.

// Attach an on click event to the submit button
$("#postJobForm").submit(function(evt) {
  evt.preventDefault();
  // Set progress so we know it is processing
  $("#progress").text("Running workflow...");
  // Get input fields
  var rasterURL = $("#inputRaster").val();
  var inputParams = $("#InputParameters").val();
  // insert raster uri into input
  // This searches for the %INPUT_RASTER% string and replaces it with the specified rasterURL.
  // Then parse it into JSON.
  var processingTaskInput = JSON.parse(inputParams.replace('%INPUT_RASTER%', rasterURL));
  // Get the task name from the input form and create a task for it
  var processingTaskName = $("#Task").val();
  var processingTask = service.task(processingTaskName);

Run the specified task (e.g. SpectralIndex). The output raster generated by the task may not be web-friendly. By reprojecting it onto the map projection, applying a linear stretch, and exporting to PNG, the code produces a much nicer display.

  // Run the processing task. This returns a JavaScript Promise for the resulting image URL.
  var processing = processingTask.submitAndWait({parameters: processingTaskInput}, progressHandler(processingTaskName))
  .then(function(results) {
    var reprojectParams = {
      INPUT_RASTER: {
        FACTORY: 'ReprojectRaster',
        INPUT_RASTER: {
          FACTORY: 'LinearPercentStretchRaster',
          INPUT_RASTER: results.OUTPUT_RASTER,
          PERCENT: 2
        },
        COORD_SYS: coordSys
      }
    };
    return exportRasterTask.submitAndWait({parameters: reprojectParams}, progressHandler(exportRasterTaskName))
  })
  .then(function(results) {
    // Return the URL of the output raster
    return results.OUTPUT_RASTER.url;
  })
  .catch(function(err) {alert(processingTaskName + ' task failed: ' + err);});

While those tasks are running, we will submit the ExampleBoundingBox task to calculate the bounding box of the image so that we know where to place the output on the map.

  // Prepare the input for the bounding box task.
  var reprojectedRasterInput = {
    INPUT_RASTER: {
      FACTORY: 'ReprojectRaster',
      INPUT_RASTER: {
        FACTORY: 'URLRaster',
        URL: rasterURL
      },
      COORD_SYS: coordSys
    }
  }

The code here runs the ExampleBoundingBox job and gets the bounding box output coordinates.

  // While the processing task is running, start a task to determine the bounding box for the
  // reprojected image. This returns a JavaScript Promise for the bounding box
  var boundingBox = boundingBoxTask.submitAndWait({parameters: reprojectedRasterInput}, progressHandler(boundingBoxTaskName))
  .then(function(results) {
    // Set the output variable so we know this task is complete
    return [[results.NORTH, results.WEST],[results.SOUTH, results.EAST]];
  })
  .catch(function(err) {alert(boundingBoxTaskName + ' task failed: ' + err);});

The two processing chains are now running asynchronously. Use Promise.all to wait for them to complete, and then process the output.

  // Wait for both Promise chains to complete, then display the results on the map
  Promise.all([processing, boundingBox]).then(function(results) {
    var imageUrl = results[0];
    var boundingBox = results[1];
    addImageToMap(imageUrl, boundingBox);
  });
});

Run the WebApp

Before running the webapp, remember to configure the server and restart the server if it is running. Open the WebApp in a browser: http://localhost:9191/webapp

Full Example Code Blocks


Note: Do not forget to Configure the Server before Running the WebApp.

Code for WebApp Request Handler

Place the following files in a webapp-request-handler folder in the server directory, and add the provided contents.

package.json

{
  "name": "Webapp-request-handler",
  "version": "1.0.0",
  "description": "Provides a web client for submitting a job to the server.",
  "main": "handler.js",
  "dependencies": {},
  "devDependencies": {},
  "scripts": {}
}

handler.js

var express = require('express');
/**
 * webappRequestHandler
 * Provides an endpoint for serving up a static HTML page for submitting jobs.
 */
function WebappRequestHandler() {
  this.init = function(app) {
    // Set up endpoint.
    app.use('/webapp/', require('express').static(__dirname + '/html/'));
  };
}
module.exports = WebappRequestHandler;

Code for Bounding Box Task

Place all of the following files in the custom_code directory under the ENVI install (ex. C:\Program Files\Harris\ENVIxx\custom_code), and add the provided contents.

exampleboundingbox.pro

pro ExampleBoundingBox, INPUT_RASTER=inputRaster, $
                        NORTH=north, $
                        SOUTH=south, $
                        WEST=west, $
                        EAST=east
  compile_opt idl2                      
  spatialRef = inputRaster.SpatialRef
  if (~Isa(spatialRef,'ENVIStandardRasterSpatialRef')) then begin
    message,'Input Raster must contain a standard spatial reference.'
  endif
  ns = inputRaster.NColumns
  nl = inputRaster.NRows   
  ; Build the file coordinate bounding box from the input raster's number of
  ; lines and samples                     
  fileBoundingBox = [[0,0],[ns-1,0],[0,nl-1],[ns-1,nl-1]]
  ; Convert to map coordinates 
  spatialRef.ConvertFileToMap, fileBoundingBox[0,*],fileBoundingBox[1,*], $
    mapBoundingBoxX, mapBoundingBoxY
  ; Convert to longitude/latitude coordinates.  This is what the
  ; web map APIs require  
  spatialRef.ConvertMapToLonLat, mapBoundingBoxX, mapBoundingBoxY, $
    boundingLon, boundingLat
  ; Seperate the information into north, south, east, and west.  Each
  ; web map API may require different format for the bounding box 
  south = Min(boundingLat, MAX=north)
  west = Min(boundingLon, MAX=east)  
end

ExampleBoundingBox.task

{
    "name": "ExampleBoundingBox",
    "baseClass": "ENVITaskFromProcedure",
    "routine": "exampleboundingbox",
    "displayName": "Lat/Lon Bounding Box",
    "description": "This task returns the farthest north, south, east, and west points of a raster in latitude/longitude.",
    "version": "5.3",
    "parameters": [
        {
            "name": "INPUT_RASTER",
            "displayName": "Input Raster",
            "dataType": "ENVIRASTER",
            "direction": "input",
            "parameterType": "required",
            "description": "Specify a raster with a standard projection to retrieve bounding box."
        },
        {
            "name": "NORTH",
            "displayName": "North",
            "dataType": "DOUBLE",
            "direction": "output",
            "parameterType": "required",
            "description": "The farthest north point."
        },
        {
            "name": "SOUTH",
            "displayName": "South",
            "dataType": "DOUBLE",
            "direction": "output",
            "parameterType": "required",
            "description": "The farthest south point."
        },
        {
            "name": "WEST",
            "displayName": "West",
            "dataType": "DOUBLE",
            "direction": "output",
            "parameterType": "required",
            "description": "The farthest west point."
        },
        {
            "name": "EAST",
            "displayName": "East",
            "dataType": "DOUBLE",
            "direction": "output",
            "parameterType": "required",
            "description": "The farthest east point."
        }
    ]
}

Code for WebApp Map Client

Create an html folder within the webapp-request-handler folder, and place these files here. Add the provided contents.

index.html

<html>
<head>
    <title>GSF - GSF Web Map Example</title>
    <!-- Load stylesheet -->
    <link rel="stylesheet" href="style.css" />
    <!-- Load JQuery -->
    <script src="http://code.jquery.com/jquery-2.2.4.min.js"></script>
    <!-- Load ths GSF SDK -->
    <script src="../sdk/js/GSF.min.js"></script>
</head>
<body>
  <!-- user input -->
  <form id="postJobForm" name="postJobForm">
    <fieldset>
        <legend>Submit a Job</legend>
        Task:<br>
        <input id="Task" size="60" type="text" value="SpectralIndex"><br>
        <br>
        Input Raster (JSON): <br>
        <input id="inputRaster" size="80" type="text" value="http://localhost:9191/ese/data/qb_boulder_msi"><br>
        Input Parameters (JSON):<br>
        <textarea cols="80" id="InputParameters" name="inputs" rows="9">
{
    "INPUT_RASTER": {
      "FACTORY": "URLRaster",
      "URL":"%INPUT_RASTER%"
    },
    "INDEX": "Normalized Difference Vegetation Index"
}
        </textarea>
        <br>
        <button type="submit">Submit</button>
    </fieldset>
  </form>
  <!-- This label shows the progress messages from the server -->
  <label id="progress"></label>
  <!-- this div will be where the webmap is loaded. -->
  <div id="map"> </div>
  <!-- load leaflet library -->
  <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.css" />
  <script src="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.js"></script>
  <!-- load our app logic -->
  <script src="app.js"></script>
</body>
</html>

style.css

#map {
  width:100%;
  height: 500px;
}

app.js

/**
 * Setup Leaflet
 */
var map = L.map('map', {
  center: [40.0150, -105.2705],
  zoom: 3
});
/**
 * Add basemap
 */
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
/**
 * Add an imageOverlay and zoom to it.
 */
function addImageToMap(imageUrl, boundingBox) {
  L.imageOverlay(imageUrl, boundingBox).addTo(map);
  map.fitBounds(boundingBox);
}
/**
 * Generate a progress message handler
 */
function progressHandler(task) {
  return function(data) {
    $('#progress').text(task + ' ' + data.progress + '% ' + data.message);
  }
}
/**
 * This coordSys should match the projection used in the webmap.
 * Leaflet uses 3857 by default.
 */
var coordSys = {
    FACTORY: "CoordSys",
    COORD_SYS_CODE: 3857
};
// Use the GSF server where this tutorial is hosted
var protocol = location.protocol.substring(0,location.protocol.length - 1);
var hostname = location.hostname;
var port = location.port;
// Create a server object
const server = GSF.server({
  protocol: protocol,
  address: hostname,
  port: port
});
// Create an ENVI service object
const service = server.service('ENVI');
// Create a task object for each task we will use
const exportRasterTaskName = 'ExportRasterToPNG';
const exportRasterTask = service.task(exportRasterTaskName);
const boundingBoxTaskName = 'ExampleBoundingBox';
const boundingBoxTask = service.task(boundingBoxTaskName);
// Attach an on click event to the submit button
$("#postJobForm").submit(function(evt) {
  evt.preventDefault();
  // Set progress so we know it is processing
  $("#progress").text("Running workflow...");
  // Get input fields
  var rasterURL = $("#inputRaster").val();
  var inputParams = $("#InputParameters").val();
  // insert raster uri into input
  // This searches for the %INPUT_RASTER% string and replaces it with the specified rasterURL.
  // Then parse it into JSON.
  var processingTaskInput = JSON.parse(inputParams.replace('%INPUT_RASTER%', rasterURL));
  // Get the task name from the input form and create a task for it
  var processingTaskName = $("#Task").val();
  var processingTask = service.task(processingTaskName);
  // Run the processing task. This returns a JavaScript Promise for the resulting image URL.
  var processing = processingTask.submitAndWait({parameters: processingTaskInput}, progressHandler(processingTaskName))
  .then(function(results) {
    var reprojectParams = {
      INPUT_RASTER: {
        FACTORY: 'ReprojectRaster',
        INPUT_RASTER: {
          FACTORY: 'LinearPercentStretchRaster',
          INPUT_RASTER: results.OUTPUT_RASTER,
          PERCENT: 2
        },
        COORD_SYS: coordSys
      }
    };
    return exportRasterTask.submitAndWait({parameters: reprojectParams}, progressHandler(exportRasterTaskName))
  })
  .then(function(results) {
    // Return the URL of the output raster
    return results.OUTPUT_RASTER.url;
  })
  .catch(function(err) {alert(processingTaskName + ' task failed: ' + err);});
  // Prepare the input for the bounding box task.
  var reprojectedRasterInput = {
    INPUT_RASTER: {
      FACTORY: 'ReprojectRaster',
      INPUT_RASTER: {
        FACTORY: 'URLRaster',
        URL: rasterURL
      },
      COORD_SYS: coordSys
    }
  }
  // While the processing task is running, start a task to determine the bounding box for the
  // reprojected image. This returns a JavaScript Promise for the bounding box
  var boundingBox = boundingBoxTask.submitAndWait({parameters: reprojectedRasterInput}, progressHandler(boundingBoxTaskName))
  .then(function(results) {
    // Set the output variable so we know this task is complete
    return [[results.NORTH, results.WEST],[results.SOUTH, results.EAST]];
  })
  .catch(function(err) {alert(boundingBoxTaskName + ' task failed: ' + err);});
  // Wait for both Promise chains to complete, then display the results on the map
  Promise.all([processing, boundingBox]).then(function(results) {
    var imageUrl = results[0];
    var boundingBox = results[1];
    addImageToMap(imageUrl, boundingBox);
  });
});



© 2018 Harris Geospatial Solutions, Inc. |  Legal
My Account    |    Store    |    Contact Us