FIP Cerrado - Fire monitoring (current map)

FIP Cerrado - Fire monitoring (current map)

Part of the project FIP - Cerrado monitoring.

This is the fire-monitoring map now on the FIP - Cerrado monitoring site (in Portuguese); the older Fip Cerrado project card shows an earlier map. The layer panel has one group per area: the whole Cerrado and eight protected areas, from Chapada dos Veadeiros and Serra da Canastra to Jalapão and the Serra do Rola-Moça state park. Opening an area zooms to it, closes the others and reports how many fire spots were recorded there. Each area holds base maps, a Planet basemap, MODIS or Sentinel imagery, its fire history (burned area 2001-2020) and the products: heat spots, fire-propagation risk, time of the fire front and the propagation risk of the last 15 days. For the Cerrado, three interactive layers (biome, conservation units, municipalities) chart the burned area and CO2 emissions of the place under the cursor. The code is query 301.

How it is built

  • Nested groups built by a function. One helper builds each area’s viewTitle group with five sub-groups; its onToggleViewGroup zooms, closes the other areas and shows the totals. See the layer and group model.
  • Timelines. Land use (2000-2019) and burned area step through yearly styles; the 15-day risk timeline builds its steps from the dates of the last 15 days, ending yesterday. See timeline panel.
  • Hover charts. On the interactive layers a hoverpixel passes the area under the cursor to onHover, which fills a window from fire and emissions CSV files read with loadcsv; a click freezes it. See Hoverpixel and LoadCsv.
  • Charts in windows. Highcharts draws burned area and emissions per year, monthly burned area against the historical mean, and the total area at risk over the 15 days, in window widgets. See charts and Window.
  • Downloads. Hidden button widgets serve the KMZ and spreadsheet downloads. See Button.
  • Notification and branding. ExtjsUtils.ALERTIFY.log reports the fire spots, and ExtjsUtils.QUERY.decorate adds a footer with the partners’ logos. See notifications.

Try this

  • Open “PARNA da Chapada dos Veadeiros” and play the 15-day risk timeline in “Produtos”.
  • In the Cerrado group, hover over a municipality and switch between the monthly and the yearly history.
  • Add &area=canastra to the map address: the map opens on Serra da Canastra.

Reference: the parameters used here

Generated from the platform source. Every entry, searchable, is in the API reference; the raw data is api.json. Open an entry for its description, parameters and example; # links to it.

QUERY · setup calls and the running query

QUERY2 entries
ExtjsUtils.QUERY: calls before the list (setQueryGlobalProperties, addRemoteWMSServer, decorate, setMappiaIoCallback) and changes to the running query from your functions (addLayer, removeLayer, postMessage).
View the complete Query API here.

decorate

function(pageProperties) : Booleanhelper# Decorates the page for the current query: header logo and top-bar style, a footer, and arbitrary CSS rules.

Written as ExtjsUtils.QUERY.decorate

Decorates the page for the current query: header logo and top-bar style, a footer, and arbitrary CSS rules. Exactly three keys are reserved:

  • header {Object}: logo: {src, style} puts an image in the top bar's logo container
       (style is an object of CSS properties applied to the container); topbar: {style} styles
       the top bar itself.
  • footer {Object}: html is the footer content, style an object of CSS properties for it;
       the footer container is shown and pinned to the bottom of the page.
  • run {Function}: called once, after the header/footer are applied — the place for
       arbitrary code that must run when the query is decorated. Every other key is passed to CSS.defineClass(key, value) as a CSS rule: the key is the selector and the value the rule body (a string such as "display: none;" or an object of CSS properties). So an accidental extra key becomes a CSS rule — do not put code under a made-up key, use run. Everything is removed when another query loads, and the whole call is a no-op while the query is only being parsed. Chain it with && before the layer array.
pageProperties Object
header, footer, run, plus selector: "css rules" pairs.

Returns Always true, so the call can be chained with && QUERY_DESCRIPTION.

ExtjsUtils.QUERY.decorate({
  header: {
    logo: { src: "https://example.org/logo.png", style: { "padding-left": "10px" } },
    topbar: { style: { "background-color": "#1b5e20" } }
  },
  footer: { html: "<b>Source:</b> my institution", style: { "text-align": "center" } },
  run: function() { console.log("decorated"); },
  ".x-tree-node-anchor": "font-size: 14px;"
}) && QUERY_DESCRIPTION

setQueryGlobalProperties

function(globalProperties) : Booleanhelper# Defines globals for the query: every key of globalProperties becomes a window property (a value, an object or a function) that layer definitions, markup widgets (handler=, onMark=...) and …

Written as ExtjsUtils.QUERY.setQueryGlobalProperties

Defines globals for the query: every key of globalProperties becomes a window property (a value, an object or a function) that layer definitions, markup widgets (handler=, onMark=...) and other query code can reference by name. The names are recorded and the globals are deleted when another query loads. A key that already exists on window and was not created by the query is refused with "Global variable can't be redefined" in the console (the platform's own globals are protected; redefining one of the query's own keys is fine). runNow is the only key the platform itself invokes: right after the globals are registered QUERY.runNow is called once (see that entry). Chain it with && before the layer array so the globals exist when the layers are evaluated; QUERY_DESCRIPTION in the examples stands for that array.

globalProperties Object
Object whose keys become globals; each value may be a value, an object or a function.

Returns Always true, so the call can be chained with && QUERY_DESCRIPTION.

ExtjsUtils.QUERY.setQueryGlobalProperties({
  globalCount: 0,
  onLayerButton: function(btn) { console.log("clicked", btn); },
  runNow: function() { ExtjsUtils.ZOOM.limitZoomLevel(17); }
}) && [
  { name: "CSR:estados", visibility: true, descriptionHtml: "{{button|id=b1|text=Go|handler=onLayerButton}}" }
]

timeline · scenarios over time (input)

Timeline3 entries

Written in a layer's descriptionHtml as {{timeline|parameter=value|...}}

Display a spatial scenarios changes in a timeline.
View the complete Timeline API here.

nextStepInterval

Number= 2100# Defines the duration of the interval between steps of the timeline in milliseconds.

Defines the duration of the interval between steps of the timeline in milliseconds.

|nextStepInterval=1000|

onPlayToggle

function# Defines the callback function called when the play/stop button is toggled, BEFORE the animation starts or stops.

Defines the callback function called when the play/stop button is toggled, BEFORE the animation starts or stops. It must return a truthy value: returning false/nothing cancels the start/stop (use it as a veto, e.g. while data is loading). pressed is true when the animation is about to start.

The value is resolved as a key of the layer functions object, then as a global function with that name, then as inline function text (function(...){...}; a plain statement body also works and returns true).

pressed Boolean
True if the button was pressed (animation about to start), False otherwise.
layer Object
The layer associated to this timeline.
timeline Object
The timeline panel.
playBtn Object
The play/stop button.
|onPlayToggle=onPlayToggle|
|onPlayToggle = function (pressed, layer, timeline, playBtn) {
     console.log("The timeline is about to " + (pressed ? "start" : "stop"));
     return true; // required, a falsy return cancels the toggle
}|

steps

Array.<Array.<(String|Object)>># Defines the timeline change steps.

Defines the timeline change steps.

|steps=[["step_0"], ["step_1"], ["step_2"]]|
|steps=[['Nome', {style:"step_0_style",name:"CSR:estados"}], ['Região', {style:"step_1_style",name:"CSR:estados"}], ['Geocódigo', {style:"step_2_style",name:"CSR:estados"}]]|
|steps=[['Nome', 'step_0'], ['Região', 'step_1'], ['Geocódigo', 'step_2']]|
|steps=[{1990: "layer_style0", 1991: "layer_style1", 1992: "layer_style2"}, 1993: "layer_style3"}]|

hoverpixel · value under the mouse (input)

Hoverpixel2 entries

Written in a layer's descriptionHtml as {{hoverpixel|parameter=value|...}}

Create a tool to instantly inspect pixel under mouse. The value of the map can also be used as input for another functions.
Usage: {{hoverpixel}}
View the complete HoverPixel API here.

runOnClick

function= undefined# Defines a callback when the user clicks on the map.

Defines a callback when the user clicks on the map.

It passes the following parameters for the callback function: handleOnClick(layerVals, inputs, coordinates, clickEvent, lastCoordinates)

layerVals Array
Array with the values of the maps at the pixel that was clicked.
inputs Array
Array with the values of the inputs defined in the descriptionHtml.
coordinates OpenLayers.LonLat
The point that was clicked, in the map's projection (Web Mercator, metres) despite the names: lon is x and lat is y. For degrees, transform it: coordinates.clone().transform(ExtjsUtils.JS.getMap().getProjectionObject(), new OpenLayers.Projection("EPSG:4326")) (lastCoordinates below already holds degrees, of the previous click and hover).
clickEvent MouseEvent
Mouse event that triggered the function.
lastCoordinates Object
Object with the last coordinates (latitude, longitude) from the last click and the last hover events. lastCoordinates = { click: { lat: // Latitude of the last click lon: // Longitude of the last click }, hover: { lat: // Latitude of the last hover lon: // Longitude of the last hover } }
|handleOnClick: function(layerVals, inputs, coordinates, clickEvent, lastCoordinates) {
     var degrees = coordinates.clone().transform(ExtjsUtils.JS.getMap().getProjectionObject(), new OpenLayers.Projection("EPSG:4326"));
     ExtjsUtils.ALERTIFY.log("Latitude: " + degrees.lat.toFixed(3) + " Longitude: " + degrees.lon.toFixed(3));
}|

runOnHover

function= undefined# Defines a callback when the user hovers the map.

Defines a callback when the user hovers the map.

It passes the following parameters for the callback function: handleOnClick(layerVals, inputs, coordinates, clickEvent, lastCoordinates)

layerVals Array
Array with the values of the maps at the pixel that was hovered.
inputs Array
Array with the values of the inputs defined in the descriptionHtml.
coordinates OpenLayers.LonLat
The point that was hovered, in the map's projection (Web Mercator, metres) despite the names: lon is x and lat is y. For degrees, transform it: coordinates.clone().transform(ExtjsUtils.JS.getMap().getProjectionObject(), new OpenLayers.Projection("EPSG:4326")) (lastCoordinates below already holds degrees, of the previous click and hover).
mouseMoveEvent MouseEvent
Mouse event that triggered the function.
lastCoordinates Object
Object with the last coordinates (latitude, longitude) from the last click and the last hover events. lastCoordinates = { click: { lat: // Latitude of the last click lon: // Longitude of the last click }, hover: { lat: // Latitude of the last hover lon: // Longitude of the last hover } }
|handleOnHover: function(layerVals, inputs, coordinates, mouseMoveEvent, lastCoordinates) {
     ExtjsUtils.ALERTIFY.log("Latitude: " + coordinates.lat + " Longitude: " + coordinates.lon);
}|

loadcsv · load a CSV table (input)

LoadCsv1 entry

Written in a layer's descriptionHtml as {{loadcsv|parameter=value|...}}

Describes the API to read and manipulate ExtjsUtils.CSV.CsvTable files from URL.
View the complete LoadCSV API here.

getLines

function(columns, values, includeHeader) : Array.<Array.<String>># Returns the lines (arrays of cell strings) whose cells in columns equal the corresponding entries of values.

Returns the lines (arrays of cell strings) whose cells in columns equal the corresponding entries of values. Columns may be given by index or by header name; to filter on several columns give one value per column, e.g. getLines([1, "Year"], ["Park A", 2024]). Values are compared as strings (the CSV is always text). Called with no arguments it returns every data line (header skipped) — a common idiom. When all filtered columns were indexed with createIndexes the lookup uses the index instead of scanning every line.

columns Array.<(String|Number)>
Indexes and/or names of the columns to filter on.
values Array
One value per entry of columns.
includeHeader Boolean
True to also return the header line when it matches (only in the scanning path, i.e. without indexes).

Returns The matching lines; all data lines when no filter is given.

var csv = inputs.id["fire_csv"];
var rows2024 = csv.getLines(["Year"], [2024]);      // by header name
var rowsParkA = csv.getLines([0, "Year"], ["Park A", 2024]); // two columns
var allRows = csv.getLines();                         // every data line

Highcharts · charts

Highcharts1 entry
Highcharts is a library used to easly create interactive charts.
Usage: (Highcharts.chart(DOM_ID, {});)
Highcharts JS has a complete set of examples and a nice documentation that can be accessed here.

chart

function(renderTo, options) : Object# Highcharts is loaded by the calculator and editor pages, so a query can call Highcharts.chart(...) without loading anything: put a container in the layer's descriptionHtml and create the chart …

Written as Highcharts.chart

Highcharts is loaded by the calculator and editor pages, so a query can call Highcharts.chart(...) without loading anything: put a container in the layer's descriptionHtml and create the chart once the panel exists - in onInputsReady, in beforeCalc or in a widget handler - then update it as results arrive instead of recreating it. ExtjsUtils.HIGHCHART.getById(id) gives the chart back from the container's id, which is what makes the update possible from another callback.

The bundled build covers the standard chart types plus highcharts-more. Extra modules are loaded on demand with AsyncLoader.loadScriptOnce (see the Sankey entry).

renderTo String
Id of the container element declared in descriptionHtml.
options Object
The Highcharts configuration object.

Returns The chart instance.

descriptionHtml: '<div id="emissions_chart" style="height:220px"></div>',
functions: {
    drawChart: function (values) {
        var chart = ExtjsUtils.HIGHCHART.getById('emissions_chart');
        if (chart) { chart.series[0].setData(values); return; }
        Highcharts.chart('emissions_chart', {
            chart: { type: 'column' },
            title: { text: 'Emissions by year' },
            xAxis: { categories: ['2020', '2021', '2022'] },
            series: [{ name: 'Mt', data: values }]
        });
    }
}

window · floating window (input)

Window2 entries

Written in a layer's descriptionHtml as {{window|parameter=value|...}}

Tool that allows to show contents in an interactive floating window.
It can only be shown when the layer is visible.
This tool is created from Ext.Window.

onBeforeHide

function# Defines a callback function to be called before hiding the floating window.

Defines a callback function to be called before hiding the floating window.

layer Object
Scope of the layer
data Array
[window, button, windowConfig] window: Window object; button: Button created; windowConfig: Window object configuration
|onBeforeHide = function (layer, [window, button, windowConfig]){
 console.log(layer);
 console.log([window, button, windowConfig]);
}|

underButtons

Boolean# Defines where the floating window will be positioned in relation to the buttons panel.

Defines where the floating window will be positioned in relation to the buttons panel. Set true to position the window under the right buttons panel, false otherwise.

|underButtons = false|

button · push or toggle button

Button2 entries

Written in a layer's descriptionHtml as {{button|parameter=value|...}}

Create a simple button to user interact with the map.
This button is created from Button.Configs.
Only some properties are listed in API here.

handler

function= undefined# Defines the callback function on button click event.

Defines the callback function on button click event. This should be used when the enableToggle property is false. this inside the callback is the layer.

The value is resolved in this order: (1) a key of the layer functions object with that name; (2) a global function with that name (e.g. defined with setQueryGlobalProperties); (3) otherwise the text itself is evaluated as a function — either a full function(){...} expression or a plain statement body. With enableToggle=true and no toggleHandler, handler is used as the toggle handler.

button Ext.Button
The button element that was clicked.
clickEvent EventObject
An event object carrying information about the click event.
|handler=onExportClick|
|handler = function (button, clickEvent){
 console.log(button, clickEvent);
}|

toggleHandler

function= undefined# Defines the callback function on button toggle event.

Defines the callback function on button toggle event. This should be used when the enableToggle property is true. this inside the callback is the layer.

The value is resolved in this order: (1) a key of the layer functions object with that name; (2) a global function with that name (e.g. defined with setQueryGlobalProperties); (3) otherwise the text itself is evaluated as a function — either a full function(){...} expression or a plain statement body.

button Ext.Button
The button element that was clicked.
state Boolean
The next state of the button, true means pressed.
|enableToggle=true|toggleHandler=onToggleDetails|
|toggleHandler = function (button, pressed){
 console.log(button, pressed);
}|

ALERTIFY · messages and questions

Alertify1 entry
Messages, alerts and questions for the reader. Usage: ExtjsUtils.ALERTIFY
View the complete Alertify API here.

log

function(msg, config)helper# Shows an user notification (if enabled).

Written as ExtjsUtils.ALERTIFY.log

Shows an user notification (if enabled).

PS: The messages before layer loading are delayed, when it finishes only the last message will be shown.

msg String
The message that will be displayed in the alert. It can be in HTML format.
config Object
Configuration parameters for the message. { force: {Boolean} Force to show notification even when disabled. func: {Callback} Callback function when the notification is clicked. onlyMsg: {Boolean} True to only show message and hide the close and the stop notifications, False otherwise. delay: {Numeric} Amout of time in milisseconds before the message hide. spamTime: {Numeric} Time the same message to be shown again is considered spam. (even with force = true). }

Group properties

GroupProperties2 entries
Keys of a group object, written next to its elements: title or viewTitle, color, openGroup, defaultProperties...

elements

Array.<Layers>= Array.emptyproperty# Defines the Layers that will be part of the Group.

Defines the Layers that will be part of the Group. Each Layer can have multiple maps inside it. All maps inside a Layer will be shown together when that Layer is enabled. Besides that, all information about those maps can be used to calculate a new one using custom functions that can be writen in JavaScript.

[
  {
     title: 'A group with Layers!',
     color: '#FFA500',
     elements: [
        // Define your Layers here
     ],
  },
]

See also To learn more about Layers and it’s properties, check their documentation at: Layer Section.

viewTitle

String= string.emptyproperty# Define the Title of the View that will gather together the elements inside it (Groups or other Views).

Define the Title of the View that will gather together the elements inside it (Groups or other Views). If an external View has in its elements another definition of a 'viewTitle', subviews will be created, like in the second example.

// Exemple 1: View with a Layers inside it
[
  {
     viewTitle: 'This View has a Group 3 Layers',
     title: 'This is a Group with 3 Layers',
     color: '#5BA300',
     elements: [
        {
           title: 'Layer 1',
           name: 'CSR:estados',
           source: 'local',
           opacity: 0.5,
           visibility: true,
        },
        {
           title: 'Layer 2',
           name: 'CSR:rios_principais',
           source: 'local',
           opacity: 0.5,
           visibility: true,
        },
        {
           title: 'Layer 3',
           name: 'CSR:geologia',
           source: 'local',
           opacity: 0.65,
           visibility: true,
        },
     ],
  },
]
// Exemple 2: View with others 'viewTitle' defined inside it
[
  {
     // This is the definition of the View
     viewTitle: 'This External View has 2 others Inner Views inside it, each with 1 Group that has 1 Layer',
     title: 'This View has 2 Groups, each with 1 Layer',
     color: '#0073E6',
     elements: [
        {
           title: 'Group 1',
           // This 'viewTitle' will create a division in the menu that shows when the mouse hovers the navigation bar option 'This View has 2 Groups, each with 1 Layer' 
           viewTitle: 'Inner View with Group 1',
           color: '#E6308A',
           elements: [
              {
                 title: 'Group 1 - Layer 1',
                 name: 'CSR:altimetria',
                 source: 'local',
                 visibility: true,
              },
           ],
        },
        {
           title: 'Group 2',
           // This 'viewTitle' will create a division in the menu that shows when the mouse hovers the navigation bar option 'This View has 2 Groups, each with 1 Layer'
           viewTitle: 'Inner View with Group 2',
           color: '#B51963',
           elements: [
              {
                 title: 'Group 2 - Layer 1',
                 name: 'CSR:batimetria',
                 source: 'local',
                 visibility: true,
              },
           ],
        },
     ],
  },
]

Group callbacks (viewTitle groups)

GroupFunctions1 entry
Functions a viewTitle group can carry; the platform calls them when its heading in the layer panel is clicked or toggled. Inside them this is the heading's node.

onToggleViewGroup

function= nullcallback# Called whenever a viewTitle group of the Legend Window is expanded or collapsed (by the user or by code).

Called whenever a viewTitle group of the Legend Window is expanded or collapsed (by the user or by code). It belongs on a group that has viewTitle: the handler is bound to that group's tree node, so this is the node and view.expanded is true after an expand and false after a collapse. When declared on a layer instead of a group, it is attached to the layer's nearest viewTitle ancestor (once per layer that declares it); on a flat layer with no viewTitle ancestor it is bound to the invisible root node, i.e. it never fires. A typical use is hiding the layers of the collapsed group and restoring them on expand.

view Ext.tree.TreeNode
The tree node of the group whose state changed (view.expanded, view.text, view.childNodes).
[
  {
     viewTitle: 'Example View (Click me!)',
     viewColor: '#FFA500',
     title: 'Click the view to change its state',
     color: '#666699',
     openGroup: true,
     onToggleViewGroup: function handleToggleViewGroup(view) {
        let viewState = (view.expanded ? 'open' : 'closed');
        ExtjsUtils.ALERTIFY.log('The ' + view.text + ' is ' + viewState );
     },
     elements: [
        {
           title: 'Layer 1',
           name: 'CSR:estados',
           source: 'local',
           startListed: true,
        },
     ],
  },
]

REQUEST · page address and network

Request2 entries
The page address (its parameters and options=) and HTTP requests. Usage: ExtjsUtils.REQUEST

get

function(url, success, failed, forceSynchronous, scope) : XMLHttpRequesthelper# Plain AJAX GET request.

Written as ExtjsUtils.REQUEST.get

Plain AJAX GET request. The usual way for query code to fetch a CSV/JSON/text resource from the Mappia server (/theme/app/data/..., a WFS GetFeature on the local GeoServer) or from any server that allows the page origin (CORS); cookies are sent on cross-origin calls. For servers without CORS headers use getCORS. Both callbacks receive the XMLHttpRequest as their only argument — read xhr.responseText.

url String
URL to load (relative to the page or absolute, including the protocol).
success function
Called with the XMLHttpRequest when the status is 200.
failed function
Called with the XMLHttpRequest on any other status.
forceSynchronous Boolean
True to make the request synchronous (deprecated), false for asynchronous.
scope Object
this for the success and failed callbacks.

Returns The request object (can be aborted with xhr.abort()).

var url = ExtjsUtils.REQUEST.getGeoserverBaseUrl() + "/wfs?service=WFS&version=1.0.0&request=GetFeature" +
    "&typename=CSR:example_layer&outputFormat=json&CQL_FILTER=code='" + code + "'";
ExtjsUtils.REQUEST.get(url, function(xhr) {
    var features = ExtjsUtils.GEOJSON.geojson2Features(JSON.parse(xhr.responseText));
    ExtjsUtils.ZOOM.zoomToExtent(features[0].geometry.getBounds());
}, function(xhr) {
    ExtjsUtils.ALERTIFY.alert("Request failed: " + xhr.status);
});

getParameterByName

function(name) : Stringhelper# Reads a parameter of the page URL query string (?name=value), URL-decoded, with + turned into spaces.

Written as ExtjsUtils.REQUEST.getParameterByName

Reads a parameter of the page URL query string (?name=value), URL-decoded, with + turned into spaces. This is the standard way for a query to receive external input (a property code, a language, a colour) from the embedding page. The name match is case-insensitive.

name String
Name of the URL parameter.

Returns The decoded value, or an empty string when the parameter is absent.

// page opened as /calculator/?queryid=1&car=MG-1234567-ABCD
var car = ExtjsUtils.REQUEST.getParameterByName("car"); // "MG-1234567-ABCD"
if (car) loadProperty(car);