BrasilPec - Beef cattle intensification scenarios

BrasilPec - Beef cattle intensification scenarios

Part of the project Scenarios for the intensification of beef cattle in Brazil.

The map from Scenarios for the intensification of beef cattle in Brazil (in Portuguese) projects Brazilian cattle ranching year by year up to 2030. Six groups - Pastagem (pasture), Reforma de Pasto (pasture reform), Rebanho (herd), Taxa de Lotação (stocking rate), Confinamento (feedlots) and Margem de Lucro (profit margin) - hold one layer per scenario: baseline and intensificação for pasture, and base, mixpast, mixsup and mixsup2 for the others. Each of the 22 scenario layers has its own timeline: press play, or drag it, to step from 2012 (2013 for pasture reform) to 2030, one year per second. Query 144 shows how to animate many yearly maps without loading them all at once.

How it is built

  • One timeline per layer. Each layer’s panel holds a timeline whose steps are the years, with nextStepInterval=1000; the layer row’s button is tied to it. See timeline panel and layer panel buttons.
  • A few years loaded at a time. Each year is a style of the scenario map. The layer lists the map five times with five styles; when the timeline leaves the years currently loaded, beforeCalc calls changeLayers to load the next ones, then shows only the selected year. See the execution model.
  • Remembering state between rounds. An inputmanager widget stores the last block of years, so changeLayers runs only when the block changes. See InputManager.
  • Fixed legend classes. The feedlot layers call setCalculateLegend with eight classes, from 0 up to 150,000-360,000 (150,000-380,000 for mixsup2). See LegendHtml.
  • Shared helpers. setQueryGlobalProperties defines the year bookkeeping (MapManager, showOnlyOneLayer) used by all 22 layers.
  • Groups. Each group is an array whose first item gives its title and color. See the layer and group model.

Try this

  • Open Confinamento, turn on two scenarios and play both timelines.
  • Drag the pasture timeline straight from 2012 to 2030 and watch the map reload.

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.

timeline · scenarios over time (input)

Timeline2 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|

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"}]|

inputmanager · values kept for your functions (input)

InputManager2 entries

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

Tool to store local variables to be used in others functions callbacks.
PS: DOM elements cannot be used in 'expression' context, because them cannot be sent to WebWorkers (javascript language limitation).
Usage: '{{inputmanager}}'
View the complete InputManager API here.

getValue

function(key) : *# Get the stored value by his property name, if it does not exists returns null.

Get the stored value by his property name, if it does not exists returns null.

key String
Stored property name.

Returns Desired stored property when it exists or null otherwise.

setValues

function(obj, cancelUpdate, local)# Stores object properties for later usage.

Stores object properties for later usage.

PS: If has name property collision the older is replaced. PS: Values go to one of two buckets of the manager: global (the default — serialized and sent to expression, so it must hold plain JSON-compatible data) or _local_ (with local=true — kept in the browser only, may hold DOM elements, Ext components, functions or circular objects). getValue(key) looks in global first, then in _local_.

obj Object
Object with the properties to be stored.
cancelUpdate Boolean
False if this change must cause layer recalculation, True otherwise.
local Boolean
True to store the property locally, False otherwise. The local properties aren't sent to 'expression' calbacks. (i.e. If a element is recursive or have DOM elements, it must local avoid stringify errors on 'expression' callbacks)
inputs.id['state'].setValues({year: 2020});                      // recalculates the layer
inputs.id['state'].setValues({lastInterval: cur}, true, true);  // silent, browser-only

Calculated layers: methods (this.)

LayerInternal2 entries
Methods of a calculated layer that your functions call on this - this.setCalculateLegend in beforeCalc, this.changeLayers to switch its maps, this.getInputs... They are not keys you write in the layer.
View all layer internal helper functions API here.

changeLayers

function(newConfigs, force)method# Replaces an internal layer at a given index.

Written as this.changeLayers

Replaces an internal layer at a given index. PS: It's highly recommended to pass multiple configurations in an array, instead of calling this function multiple times in the same callback.

newConfigs Array|Object
One or more layers configurations with a property 'index' indicating the replacing layer. Each config object must contain at least the following properties: [{name: 'MAP_FULL_NAME', styles: 'MAP_STYLE', index: 'MAP_INDEX_TO_CHANGE'}, ... ]
force Boolean
Force redraw even if no change is done when the layer is the same.
{
     name: "CSR:rodovias,CSR:municipios",
     otherNames: "CSR:roads",
     beforeCalc: function(layerVals, inputVals) {
         this.changeLayers([{name: 'CSR:roads', styles: fMapName + "_1", index: 0}]);
     }
  }

setCalculateLegend

function(legendEntries)method# Defines the legend of the calculated map yourself, which also skips the automatic legend calculation for this cycle.

Written as this.setCalculateLegend

Defines the legend of the calculated map yourself, which also skips the automatic legend calculation for this cycle. It is meant to be called inside beforeCalc, the moment right before a new legend would be computed, but it can also be called from a tool callback (e.g. a {{button}} handler). When the given entries equal the current legend nothing is redrawn.

legendEntries Array.<{color: Array.<Number>, value: *, title: String}>
Legend entries sorted by value in ascending order (entries out of order are ignored). color is the [R, G, B] colour of the entry, value the highest value that maps to it, title the label shown in the legend.
beforeCalc: function(inputs) {
   this.setCalculateLegend([
      {color: [0, 0, 255], value: 500, title: 'Up to 500 m'},
      {color: [255, 255, 0], value: 1000, title: 'From 500 m to 1000 m'},
      {color: [255, 0, 0], value: 3000, title: 'Above 1000 m'},
   ]);
}

Layer callbacks: functions you write

LayersFunctions1 entry
Functions you write in a layer and the platform calls: expression, afterCalc and legendColor on calculated layers; beforeCalc, onInputsReady, onVisibilityChange and the functions map on calculated and file layers. Inside them this is the layer - except in expression, see Kinds of layer.

beforeCalc

function= nullcallback# This function is executed before any calculation is made in the 'expression()' function.

This function is executed before any calculation is made in the 'expression()' function. It runs on calculated layers (source: 'calculate'), even when there is no 'expression()', and on file layers (source: 'file'), where it runs again whenever an input changes or a resource finishes loading (see VectorLayer.generateNewLegend).

inputs Array
The value of each input defined in the descriptionHtml. The order of the values is the same as the inputs (i.e. the first input in the descriptionHtml is inputs[0], the second is inputs[1] and so on).
[
  {
     title: 'Example of beforeCalc function',
     color: '#FFA500',
     elements: [
        {
           title: 'This beforeCalc function will show a message at the bottom right of the screen',
           name: 'CSR:geologia',
           source: 'calculate',
           visibility: true,
           paramsButtonConfig: [
              {
                 type: 'query',
                 pressed: true
              },
           ],
           descriptionHtml:
              '{{label|text=The beforeCalc function will be called after every user interaction before any calculation}}'
              +
              '{{textfield|fieldLabel=Enter your name|id=textInput|labelStyle=text-align:center;}}',
           beforeCalc: function(inputs) {
              let inputValue = inputs[0];
              ExtjsUtils.ALERTIFY.log('Hello ' + inputValue + '!');
           },
        },
     ],
  },
]

Layer properties

LayersProperties2 entries
Keys of a layer object: which map it shows (name, source, styles), how it looks (title, opacity, visibility) and how its row and panel behave.

styles

String= string.emptyproperty# Defines which styles will be applied over the maps defined at the 'name' property.

Defines which styles will be applied over the maps defined at the 'name' property. The styles are applied in the same order as the maps are declared in name. For example, if there are 3 maps in the 'name' property and 3 styles. The first style will be applied to the first map, the second to the second map, and so on. A style's Mappia identifier is the map name without its namespace plus _ and an index (estados published with two styles gives estados_0 and estados_1), and the styles a map really offers are the ones its published capabilities declare: open the layer's style chooser in the interface to see and pick them, or read the Style entries of the map in the WMS capabilities. Styles are created when the map is published (a QGIS style file is converted at publication time), not by the query. PS: Styles are separated by comma, one per map in name, in the same order.

[
  {
     title: 'Example of style',
     color: '#666699',
     elements: [
        {
           name: 'CSR:precip_monthly_average,CSR:precip_monthly_average',
           // The first style 'precip_monthly_average_1' is applied to the first map 'precip_monthly_average' and the second style 'precip_monthly_average_2' is applied to the second map 'precip_monthly_average'
           styles: 'precip_monthly_average_1,precip_monthly_average_2',
           // The source needs to be calculate to apply the style
           source: 'calculate',
           visibility: true,
        },
     ],
  },
]
{
       ...,
         name: 'CSR:municipios',
         style: 'municipios_0',
       ...
  }
{
       ...,
         name: 'CSR:estados,CSR:geologia',
         style: 'estados_0,geologia_1',
       ...
  }

updateAutomatically

Boolean= falseproperty# Decides what happens when the reader changes an input of the layer's panel (a widget in descriptionHtml).

Decides 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;
       },
     },
   ],
 },
]

QUERY · setup calls and the running query

QUERY1 entry
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.

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}}" }
]