X-ray of the CAR - Forest Code balance per property
Part of the project X-ray of the CAR (Brazil's environmental registry).
The English map of the X-ray of the CAR shows the Forest Code balance of the private rural properties registered in the CAR, Brazil’s Rural Environmental Registry, in the Amazon and the Cerrado. Move the cursor over a property: a popup gives its legal reserve debt or surplus, its municipality and its state. Click a property: the “Property report” window lists its area, legal reserve surplus and debt (2008 and 2018), APP debt and deforestation after 2008 (potentially legal and potentially illegal), under a heading that classes it as potentially illegal deforestation, potentially legal deforestation or deforestation-free. This is query 195; query 189 is the Portuguese version, and query 190 an earlier English variant linked from the methodology page.
How it is built
- Hidden helper maps. The interactive layer reads three maps at once;
insideOpacity: [1, 0.0, 0.0]shows the first and hides the two others, which supply the property’s balance and its municipality code under the cursor. See the layer and group model. - Hover popup. A
hoverpixelwidget withrunOnHovercalls the layer’sonHover, which fills the popup from those values and from a municipal CSV. See Hoverpixel. - Click report. A
pickpointwidget withonefeature=truekeeps one selected property;beforeCalcreads its attributes withgetAttributesand writes the report into awindowwidget. See PickPoint and Window. - Data files. Two
loadcsvwidgets load the municipal analysis and a table of state codes. See LoadCsv. - On/off switch. A toggle
buttonturns click and hover interaction on and off; it and the report window are also tied to buttons on the layer row. See Button and layer panel buttons. - Legend and opacity.
legendhtml(only the first map, reversed) andopacityslidersit in the panel. See LegendHtml and OpacitySlider. - Links that open one layer. The query reads an extra
optionURL parameter: the methodology page links to the map with, for example,&option=prodes_legal_amazon_2018so that only that layer starts visible.
Try this
- Zoom into Mato Grosso, hover across several properties, then click one with a legal reserve debt.
- Use the button in the panel to turn the interaction off and pan freely.
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
QUERY1 entrysetQueryGlobalProperties
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 …
setQueryGlobalPropertiesWritten 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}}" }
]hoverpixel · value under the mouse (input)
Hoverpixel3 entriesWritten in a layer's descriptionHtml as {{hoverpixel|parameter=value|...}}
Usage: {{hoverpixel}}
runOnClickOutside
function# True to run the callback function even when clicking outside of the layer, False to disable.
runOnClickOutsideTrue to run the callback function even when clicking outside of the layer, False to disable. (Default False)
runOnHover
function= undefined# Defines a callback when the user hovers the map.
runOnHoverDefines 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:
lonis x andlatis 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);
}|runOnHoverOutside
function# True to run the callback function even when hovering outside of the layer, False to disable.
runOnHoverOutsideTrue to run the callback function even when hovering outside of the layer, False to disable. (Default False)
pickpoint · pick a point on the map (input)
PickPoint3 entriesWritten in a layer's descriptionHtml as {{pickpoint|parameter=value|...}}
The returned values are from the original mal to the selected point,
in case of RASTER is returned a cell value, in case of shapefile the geometry is returned too.
Usage: {{pickpoint}}
getAttributes
function(mapIndex) : Array.<Object># Returns the attributes of every selected point for one of the layers of the composed map: one object per selection (in click order) holding the feature data of that layer, or {} when the click …
getAttributesReturns the attributes of every selected point for one of the layers of the composed map: one object per selection (in click order) holding the feature data of that layer, or {} when the click hit nothing on it (e.g. a raster). This is the usual way to read the selection in beforeCalc.
- mapIndex Number
- 0-based index of the layer inside the composed layer (
nameorder).
Returns Attribute objects of the selected features on that layer.
beforeCalc: function(inputs) {
var picked = inputs.id['property_pick'].getAttributes(1);
var names = picked.map(function(attrs) { return attrs.Name; });
}markLayerInd
Number# Defines by layer index which one to draw its geometry when a click event happens.
markLayerIndDefines by layer index which one to draw its geometry when a click event happens. (0-indexed)
|markLayerInd = 0|onefeature
boolean# Defines if PickPoint should keep only the last feature selected.
onefeatureDefines if PickPoint should keep only the last feature selected. Set it true to keep only the last one, false otherwise.
|onefeature = false|window · floating window (input)
Window3 entriesWritten in a layer's descriptionHtml as {{window|parameter=value|...}}
It can only be shown when the layer is visible.
btnID
String# Defines the id of the button that controls the window visibility.
btnIDDefines the id of the button that controls the window visibility.
|btnID = window-button-id|startVisible
Boolean# Defines if the window should start visible or not.
startVisibleDefines if the window should start visible or not. Set true if it should, false otherwise.
|startVisible = false|underButtons
Boolean# Defines where the floating window will be positioned in relation to the buttons panel.
underButtonsDefines 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|loadcsv · load a CSV table (input)
LoadCsv2 entriesWritten in a layer's descriptionHtml as {{loadcsv|parameter=value|...}}
getColunsInd
function() : Array.<String># Returns a copy of the header row — the column names, in order — so query code can discover columns instead of hard-coding indexes.
getColunsIndReturns a copy of the header row — the column names, in order — so query code can discover columns instead of hard-coding indexes. The name is a historical typo of getColumnsInd, kept for compatibility (the platform and many queries call it by this spelling; there is no correctly spelled alias).
Returns Copy of the header row.
var headers = inputs.id["fire_csv"].getColunsInd(); // ["Municipality", "Year", "Fires"]
var iFires = headers.indexOf("Fires");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.
getLinesReturns 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 linebutton · push or toggle button
Button3 entriesWritten in a layer's descriptionHtml as {{button|parameter=value|...}}
enableToggle
Boolean= false# Defines the button type as toggle.
enableToggleDefines the button type as toggle. Set true to use as toggle, false otherwise. PS: When its true the callback is 'toggleHandler', otherwise the callback is 'handler'.
|enableToggle=true|pressed
Boolean= false# Defines the button initial state.
pressedDefines the button initial state. Set it true to start pressed (only if enableToggle = true), false otherwise.
|pressed=true|toggleHandler
function= undefined# Defines the callback function on button toggle event.
toggleHandlerDefines 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);
}|legendhtml · legend of the calculated map
LegendHtml3 entriesWritten in a layer's descriptionHtml as {{legendhtml|parameter=value|...}}
Usage: '{{legendhtml}}'
filterLayers
Array.<Number>= null# Defines an array of indexes of layers to be included in map legend (from 0 to quantity of layers).
filterLayersDefines an array of indexes of layers to be included in map legend (from 0 to quantity of layers). If not defined, all layer legends are shown by default. Otherwise, only the listed indexes are included.
Ex: A composed layer with three maps: name: "CSR:estados,CSR:roads,CSR:municipalities", If 'filterLayers=[0,1]' is defined in the layer object only the legends of 'CSR:estatdos' and 'CSR:roads' are shown.
|filterLayers = [1,2]|preventClick
Boolean= false# Defines if the user can filter the maps categories by clicking on the legend.
preventClickDefines if the user can filter the maps categories by clicking on the legend. Set it true to ignore the legend click, false otherwise.
|preventClick = true|reverseLegend
Boolean= false# Defines if it should sort the legend on the decreasing order.
reverseLegendDefines if it should sort the legend on the decreasing order. Set it true to use the decreasing order, false otherwise.
|reverseLegend = true|opacityslider · layer opacity
OpacitySlider8 entriesWritten in a layer's descriptionHtml as {{opacityslider|parameter=value|...}}
Usage: '{{opacityslider}}'
aggressive
Boolean= false# Set true to apply the opacity while the thumb is being dragged instead of only when it is released.
aggressiveSet true to apply the opacity while the thumb is being dragged instead of only when it is released.
|aggressive=true|changeVisibility
Boolean= false# Set true to let the slider also control the layer visibility: the layer is hidden when the slider reaches minValue and shown again when it leaves it.
changeVisibilitySet true to let the slider also control the layer visibility: the layer is hidden when the slider reaches minValue and shown again when it leaves it. The layer must be visible when the slider is created.
|changeVisibility=true|complementaryLayer
OpenLayers.Layer# A second layer that is hidden when the slider reaches maxValue (GeoExt option to fade between two layers).
complementaryLayerA second layer that is hidden when the slider reaches maxValue (GeoExt option to fade between two layers). GeoExt expects a layer object here, which the markup cannot express (a string is not resolved to a layer), so this option is only usable from code; documented for completeness.
id
String# Defines the id of the slider component (Ext.getCmp(id)), e.g. to read getValue() or to hide() it.
idDefines the id of the slider component (Ext.getCmp(id)), e.g. to read getValue() or to hide() it. Generated when omitted. Every parameter of the tool is passed to GeoExt.LayerOpacitySlider / Ext.slider.SingleSlider unchanged (width, cls, vertical, hidden...).
|id=opacity|inverse
Boolean= false# Set true to make the slider work with transparency instead of opacity (100 = fully transparent).
inverseSet true to make the slider work with transparency instead of opacity (100 = fully transparent).
|inverse=true|maxValue
Number= 100# Defines the maximum value of the slider (opacity percent at the right end).
maxValueDefines the maximum value of the slider (opacity percent at the right end).
|maxValue=90|minValue
Number= 0# Defines the minimum value of the slider (opacity percent at the left end).
minValueDefines the minimum value of the slider (opacity percent at the left end).
|minValue=10|value
Number= 100# Defines the initial slider value (opacity in percent).
valueDefines the initial slider value (opacity in percent). It is only used when the layer has no opacity yet (opacity not set on the layer): otherwise the slider starts at the layer's current opacity.
|value=50|Layer properties
LayersProperties2 entriesinsideOpacity
Array.<Numeric>= [1, 1, 1, ...]property# Defines the opacity for the maps defined in the 'name' property.
insideOpacityDefines the opacity for the maps defined in the 'name' property. This property is an array of values which are the opacity that will be applied in the same order that the map was defined in the 'name' property. For example, the first value in the 'insideOpacity' array will define the opacity for the first map defined in the 'name' property, the second value is the opacity for the second map, and so on. The opacity value is a number between 0 and 1. 0 being transparent and 1 opaque.
[
{
title: 'Example of insideOpacity',
color: '#666699',
elements: [
{
name: 'CSR:estados,CSR:rios_principais,CSR:geologia',
source: 'calculate',
// The values are applied to the layers in the same order as they are defined in the name property. So the CSR:estados map has the opacity of 0.5, the CSR:rios_principais map has the opacity of 1, and the CSR:geologia map has the opacity of 0.7.
insideOpacity: [0.5, 1, 0.7],
visibility: true,
},
],
},
]updateAutomatically
Boolean= falseproperty# Decides what happens when the reader changes an input of the layer's panel (a widget in descriptionHtml).
updateAutomaticallyDecides what happens when the reader changes an input of the layer's panel (a widget in descriptionHtml). true: the layer is calculated again at once. false (the default): a short countdown starts, with a button to refresh now, so several changes make one calculation. The layer is drawn either way. Applies to calculated and file layers.
[
{
title: 'The map will be automatically calculated',
color: '#666699',
elements: [
{
title: 'This layer is showing just one type of relief',
name: 'CSR:geologia',
source: 'calculate',
visibility: true,
updateAutomatically: true,
expression: function(layersVals, inputs) {
// layerVals have the value of the legend applied in every pixel of the map
let mapValue = layersVals[0];
// Remove every type of relief that is not 'Mantiqueira'
if(mapValue != 'Mantiqueira') { // If the pixel is not 'Mantiqueira'
return undefined; // Don't show the pixel
}
// If the pixel is 'Mantiqueira', return the value of the pixel
return mapValue;
},
},
],
},
]REQUEST · page address and network
Request1 entrygetParameterByName
function(name) : Stringhelper# Reads a parameter of the page URL query string (?name=value), URL-decoded, with + turned into spaces.
getParameterByNameWritten 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);Group properties
GroupProperties1 entryviewTitle
String= string.emptyproperty# Define the Title of the View that will gather together the elements inside it (Groups or other Views).
viewTitleDefine 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,
},
],
},
],
},
]