Widgets

Há vários widgets que você pode usar para criar interfaces. Esses widgets incluem botões, caixas de seleção, controles deslizantes, caixas de texto e menus de seleção. Os widgets só podem ser impressos ou adicionados a um painel uma vez. As seções a seguir ilustram a funcionalidade básica, a aparência e a sensação dos widgets. Consulte a seção "Estilo" para mais informações sobre como estilizar seus widgets. Os exemplos a seguir simplesmente print() os widgets para o console. Para saber como adicionar widgets aos painéis, consulte a página Painéis e layouts.

ui.Label

Os rótulos são simplesmente áreas em que o texto aparece. Por exemplo, o código a seguir imprime um rótulo:

Editor de código (JavaScript)

var label = ui.Label('Cool label!');
print(label);

Que tem esta aparência:

ui_label.png

Divida rótulos longos inserindo um caractere de nova linha (\n) e definindo o argumento de propriedade de estilo whiteSpace como 'pre':

print(ui.Label('Here is a:\nnew line', {whiteSpace: 'pre'}));

ui.Button

Um botão é um widget de interface interativo que pode ser clicado. É possível especificar uma função a ser chamada (a função "callback") quando um usuário clica no botão. Para mais informações sobre o processamento de eventos com funções de callback, consulte a página de eventos. O exemplo a seguir imprime o centro atual do mapa quando o botão é clicado:

Editor de código (JavaScript)

var button = ui.Button({
  label: 'Get Map Center',
  onClick: function() {
    print(Map.getCenter());
  }
});
print(button);

Que tem esta aparência:

ui_button.png

ui.Checkbox

Uma caixa de seleção é um widget que permite que o usuário marque (ou desmarque) uma caixa. Quando o estado da caixa de seleção muda, os callbacks registrados no widget recebem um valor booleano que indica se a caixa de seleção está marcada. Exemplo:

Editor de código (JavaScript)

var checkbox = ui.Checkbox('Show SRTM layer', true);

checkbox.onChange(function(checked) {
  // Shows or hides the first map layer based on the checkbox's value.
  Map.layers().get(0).setShown(checked);
});

Map.addLayer(ee.Image('CGIAR/SRTM90_V4'));
print(checkbox);

A caixa de seleção impressa vai ficar assim:

ui_checkbox.png

Ao marcar a caixa, uma camada é ativada e exibida no mapa. Assim como outros componentes da interface, o Map do editor de código pode ser manipulado de forma programática. Saiba mais sobre o objeto map na página Painéis e layouts.

ui.Slider

Um controle deslizante é um widget que permite que o usuário ajuste um controle deslizante para receber um número dentro do intervalo do controle. Configure o intervalo usando o construtor ou definindo propriedades do controle deslizante. O exemplo a seguir usa o controle deslizante para definir a opacidade da primeira camada no Mapa:

Editor de código (JavaScript)

var slider = ui.Slider();

slider.setValue(0.9);  // Set a default value.
slider.onChange(function(value) {
  Map.layers().get(0).setOpacity(value);
});

Map.addLayer(ee.Image(255), {palette: 'blue'});
print(slider);

O controle deslizante vai ficar assim:

ui_slider.png

O valor do controle deslizante é mostrado à direita dele.

ui.DateSlider

O widget DateSlider é semelhante ao Slider, mas processa datas explicitamente. Um DateSlider configurado para selecionar um dia de junho 2018 tem esta aparência:

DateSlider.png

O DateSlider é útil para filtrar coleções, conforme mostrado no exemplo abaixo, que cria um composto anual com base no DateRange definido no DateSlider:

Editor de código (JavaScript)

// Use a DateSlider to create annual composites of this collection.
var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1');
// Use the start of the collection and now to bound the slider.
var start = ee.Image(collection.first()).date().get('year').format();
var now = Date.now();
var end = ee.Date(now).format();

// Run this function on a change of the dateSlider.
var showMosaic = function(range) {
  var mosaic = ee.Algorithms.Landsat.simpleComposite({
    collection: collection.filterDate(range.start(), range.end())
  });
  // Asynchronously compute the name of the composite.  Display it.
  range.start().get('year').evaluate(function(name) {
    var visParams = {bands: ['B4', 'B3', 'B2'], max: 100};
    var layer = ui.Map.Layer(mosaic, visParams, name + ' composite');
    Map.layers().set(0, layer);
  });
};

// Asynchronously compute the date range and show the slider.
var dateRange = ee.DateRange(start, end).evaluate(function(range) {
  var dateSlider = ui.DateSlider({
    start: range['dates'][0],
    end: range['dates'][1],
    value: null,
    period: 365,
    onChange: showMosaic,
    style: {width: '180px'}
  });
  Map.add(dateSlider.setValue(now));
});

// Initialize the map location at southern Africa.
Map.setCenter(23.861, -27.144, 6);

ui.Textbox

Uma caixa de texto é um local para coletar texto inserido pelo usuário. Exemplo:

Editor de código (JavaScript)

var textbox = ui.Textbox({
  placeholder: 'Enter text here...',
  onChange: function(text) {
    print('So what you are saying is ' + text + '?');
  }
});
print(textbox);

A caixa de texto vai ficar assim:

ui_textbox.png

O callback só é acionado quando o usuário termina de digitar texto (e pressiona Return) ou quando o usuário clica fora da caixa de texto.

ui.Select

O widget de seleção representa um menu suspenso de opções que o usuário pode escolher. O exemplo a seguir ilustra um menu suspenso para permitir que um usuário selecione um local:

Editor de código (JavaScript)

var places = {
  MTV: [-122.0849, 37.3887],
  PEK: [116.4056, 39.9097],
  ZRH: [8.536, 47.376]
};

var select = ui.Select({
  items: Object.keys(places),
  onChange: function(key) {
    Map.setCenter(places[key][0], places[key][1]);
  }
});

// Set a place holder.
select.setPlaceholder('Choose a location...');

print(select);

O widget de seleção vai ficar assim:

ui_select.png

ui.Chart

Os gráficos no pacote ui.Chart se comportam de maneira semelhante aos gráficos no pacote Chart. Especificamente, um ui.Chart é um shell fino em torno de uma instância do ChartWrapper da API Google Visualization. Para mais informações sobre como manipular objetos ChartWrapper, consulte esta referência. Para mais informações sobre as funções auxiliares de gráficos no Earth Engine, consulte a documentação de gráficos.

ui.Thumbnail

O widget de miniatura pode ser usado para visualizar objetos ee.Image e ee.ImageCollection. Quando um ee.Image é fornecido, o widget mostra uma imagem estática. Quando um ee.ImageCollection é fornecido, ele mostra uma animação com um frame por imagem na entrada. Assim como em ee.Image.getThumbURL() e ee.ImageCollection.getVideoThumbURL(), é possível especificar parâmetros para controlar o formato e as dimensões da miniatura resultante:

Editor de código (JavaScript)

// Create a box around an area in the Brazilian Amazon.
var box = ee.Geometry.Polygon([[
  [-62.9564, 2.5596], [-62.9550, 2.4313], [-62.8294, 2.4327], [-62.8294, 2.5596]
]]);

// Visualize the image in RGB.
var image = ee.Image('LANDSAT/LE07/C02/T1_L2/LE07_233058_20011113')
                .select(['SR_B[1-3]'])  // blue, green, red reflectance
                .multiply(0.0000275).add(-0.2)  // apply scaling factors
                .visualize({
                  bands: ['SR_B3', 'SR_B2', 'SR_B1'],
                  min: 0,
                  max: 0.12,
                  gamma: 1.3
                });

// Print a thumbnail to the console.
print(ui.Thumbnail({
  image: image,
  params: {dimensions: '256x256', region: box, format: 'png'},
  style: {height: '300px', width: '300px'}
}));

A miniatura vai ficar assim:

ui_thumbnail.png

ui.Map

Um ui.Map é um widget de mapa. Na verdade, o Map padrão do Code Editor é uma instância dessa classe. Assim como outros widgets, é possível imprimir um mapa no console. Manipule o conteúdo do mapa limpando, recebendo ou definindo camadas individuais. O exemplo a seguir imprime um mapa no console que mostra os limites do Mapa do editor de código:

Editor de código (JavaScript)

// Make a little map.
var map = ui.Map();

// Make the little map display an inset of the big map.
var createInset = function() {
  var bounds = ee.Geometry.Rectangle(Map.getBounds());
  map.centerObject(bounds);
  map.clear();
  map.addLayer(bounds);
};

// Run it once to initialize.
createInset();

// Get a new inset map whenever you click on the big map.
Map.onClick(createInset);

// Display the inset map in the console.
print(map);

O mapa inserido deve ficar assim:

ui_map.png

Neste exemplo, o usuário precisa clicar no mapa grande para que o mapa menor seja desenhado.

Também é possível manipular camadas no mapa chamando layers() na instância do mapa. O layers() retorna um ui.data.ActiveList, um objeto semelhante a uma matriz. Quando isso acontece, as camadas do mapa também mudam. Saiba mais na seção ui.Map.Layer.

ui.Map.Layer

Uma camada não é um widget estilizável, como um ui.Button. É apenas uma representação de dados da camada no mapa. O exemplo a seguir demonstra como atualizar um mapa criando uma camada e atualizando as propriedades dela com base na entrada do usuário:

Editor de código (JavaScript)

var consoleMap = ui.Map({
  lon: -2.0174,
  lat: 48.6474,
  zoom: 13
});

// Create a Layer from this Sentinel-2 image
var image = ee.Image('COPERNICUS/S2/20150821T111616_20160314T094808_T30UWU');
var visParams = {bands: ['B4', 'B3', 'B2'], max: 2048, gamma: 1};
var layer = ui.Map.Layer(image, visParams);

// Update the map by updating the layers list.
var layers = consoleMap.layers();
layers.add(layer);

// Make a textbox to accept a gamma value.
// Update the layer when the gamma value is entered.
var gammaBox = ui.Textbox({
  value: 1,
  onChange: function(value) {
    // visParams is NOT an ActiveDictionary, so set it again.
    visParams.gamma = value;
    layer.setVisParams(visParams);
  }
});

print(ui.Label('Enter a gamma value:'));
print(gammaBox);
print(consoleMap);

ui.Map.CloudStorageLayer

Se você quiser mostrar (por exemplo) uma camada relativamente cara para computação, exporte seus dados para um bucket do Cloud Storage por motivos de desempenho. Essas camadas estáticas, apenas de visualização, podem deixar seus apps e scripts mais responsivos. É possível criar uma camada de exibição estática para essa finalidade usando Export.map.toCloudStorage(). Para usar um conjunto de blocos exportado anteriormente por Export.map.toCloudStorage(), crie um novo ui.Map.Layer de um bucket e um caminho especificados do Cloud Storage:

Map.add(ui.Map.CloudStorageLayer({
  bucket: 'earthenginepartners-hansen',
  path: 'tiles/gfc_v1.4/loss_year',
  maxZoom: 12,
  suffix: '.png'
}));

Ao executar um script que carrega uma camada do Cloud Storage, você pode receber a seguinte mensagem de aviso:

Alerta de camada de nuvem

ui.Map.DrawingTools

Há um conjunto de ferramentas de desenho de geometria que é adicionado por padrão ao Map no editor de código. É possível mudar o comportamento dessas ferramentas no Map padrão chamando Map.drawingTools(). Por exemplo, para ocultar as ferramentas de desenho:

Editor de código (JavaScript)

Map.drawingTools().setShown(false);

Os mapas recém-criados não recebem ferramentas de desenho por padrão, mas podem ser ativadas chamando o método drawingTools() no mapa:

Editor de código (JavaScript)

var map = ui.Map();
// Prints true since drawingTools() adds drawing tools to the map.
print(map.drawingTools().getShown());
// Replace the default Map with the newly created map.
ui.root.widgets().reset([map]);

As camadas de geometria desenhadas pelas ferramentas de desenho são colocadas em um ui.data.ActiveList, que pode ser acessado chamando Map.drawingTools().layers(). A lista de camadas de geometria responde a eventos como outras listas ativas, por exemplo, a lista de camadas no Map retornado por Map.layers(). O exemplo a seguir mostra como definir a visibilidade das camadas de geometria desenhadas pelas ferramentas (que são mostradas por padrão):

Editor de código (JavaScript)

Map.drawingTools().layers().forEach(function(layer) {
  layer.setShown(false);
});

Para adicionar uma camada de forma programática às ferramentas de desenho, chame o método addLayer nas ferramentas de desenho ou adicione uma camada diretamente à lista de camadas:

Editor de código (JavaScript)

var geometries = [ee.Geometry.Point([0,0]), ee.Geometry.Rectangle([[0,0], [1,1]])];
Map.drawingTools().addLayer(geometries, 'my_geometry1', 'red');

var layer = ui.Map.GeometryLayer(geometries, 'my_geometry2', 'blue');
Map.drawingTools().layers().add(layer);

O estado das ferramentas de desenho também é transferido quando você publica um app. Se as ferramentas de desenho estiverem mostradas ou ocultas, elas também serão mostradas ou ocultas no app. As geometrias nas importações também serão transferidas para o app.

ui.Map.GeometryLayer

Um GeometryLayer é uma coleção de geometrias que atua como um único Geometry, GeometryCollection ou FeatureCollection que é adicionado à seção de importações na parte superior do script e pode ser referenciado no código.

Os GeometryLayers desenhados pelas ferramentas de desenho têm um comportamento padrão que pode ser substituído fornecendo novas funções de callback. Por exemplo, suponha que você queira mudanças interativas nas geometrias para acionar um evento. Para implementar um comportamento específico, defina os métodos onEdit(), onErase() ou onDraw() nas ferramentas para responder às ações do usuário. O exemplo a seguir mostra como acionar um cálculo e atualizar um rótulo com o resultado da computação quando o usuário adiciona/edita/apaga uma geometria:

Editor de código (JavaScript)

// Load elevation data.
var srtm = ee.Image('USGS/SRTMGL1_003');
Map.addLayer(srtm, {min: 0, max: 5000}, 'SRTM');

// Make a label to display mean elevation at drawn points.
var label = new ui.Label('Draw points to calculate mean elevation');
var inspector = new ui.Panel([label]);
Map.add(inspector);
// Don't make imports that correspond to the drawn points.
Map.drawingTools().setLinked(false);
// Limit the draw modes to points.
Map.drawingTools().setDrawModes(['point']);
// Add an empty layer to hold the drawn points.
Map.drawingTools().addLayer([]);
// Set the geometry type to be point.
Map.drawingTools().setShape('point');
// Enter drawing mode.
Map.drawingTools().draw();

// This function gets called when the geometry layer changes.
// Use debounce to call the function at most every 100 milliseconds.
var getAverageElevation = ui.util.debounce(function() {
  var points = Map.drawingTools().layers().get(0).toGeometry();
  var elevation = srtm.reduceRegion({
    reducer: ee.Reducer.mean(),
    geometry: points,
    scale: 30
  }).get('elevation');
  // Asynchronously evaluate the mean elevation.
  elevation.evaluate(showElevation);
}, 100);

// Set the callback function on changes of the geometry layer.
Map.drawingTools().onEdit(getAverageElevation);
Map.drawingTools().onDraw(getAverageElevation);
Map.drawingTools().onErase(getAverageElevation);

// Set the label to the result of the mean reduction.
function showElevation(elevation) {
  inspector.clear();
  var elevationLabel = ui.Label('Mean elevation: ' + elevation);
  inspector.add(elevationLabel);
}

setLinked() é usado para alternar a conexão entre as ferramentas de desenho de geometria e a seção Imports do editor de código. Neste exemplo, as ferramentas de geometria são desvinculadas para impedir a criação de importações. toGeometry é usado para converter a camada em um ee.Geometry. Se a camada importada representar um Feature ou FeatureCollection, será possível recuperar o objeto EE subjacente usando getEeObject(). Observe também o uso de ui.util.debounce para evitar que cada movimento de uma geometria acione a função de callback. Especificamente, a função não será acionada até que 100 milissegundos tenham decorrido desde o último evento. Isso ajuda a garantir que a função seja executada somente quando o usuário concluir a ação de edição.

Uma camada de geometria nas importações é associada a um Geometry ou GeometryCollection. Portanto, ela só pode conter geometrias com o mesmo estado geodesicamente porque o formato GeoJSON permite apenas um único estado geodesicamente para a coleção de geometrias. Consulte a página Geodesic vs. Planar Geometries para mais informações. A conversão da camada de geometria em uma FeatureCollection ao pressionar o ícone de engrenagem ao lado do nome da camada permite adicionar geometrias planas e geodésicas à mesma camada. No entanto, a conversão de volta para um Geometry vai gerar um erro. Para evitar isso, converta em um FeatureCollection ou exclua geometrias até que haja apenas um estado geodésico na camada.

ui.Map.Linker

Assim como uma camada, um vinculador não é um widget estilizável. É um utilitário de bastidores que pode ser usado para sincronizar o movimento de várias instâncias de ui.Map:

Editor de código (JavaScript)

// Add two maps to the screen.
var left = ui.Map();
var right = ui.Map();
ui.root.clear();
ui.root.add(left);
ui.root.add(right);

// Link the "change-bounds" event for the maps.
// When the user drags one map, the other will be moved in sync.
ui.Map.Linker([left, right], 'change-bounds');

ui.SplitPanel

Um ui.SplitPanel é útil para comparar coisas lado a lado. A vantagem de um ui.SplitPanel em relação a dois painéis comuns é que uma alça pode ser usada para conseguir uma transição de limpeza entre os painéis em um ui.SplitPanel. O exemplo a seguir usa um ui.SplitPanel para mostrar as diferenças espectrais das cicatrizes de queimadura:

Editor de código (JavaScript)

// Load an image of the Santa Rosa, California 2017 fires.
var image = ee.Image('LANDSAT/LC08/C02/T1_TOA/LC08_045033_20171011');

// Add a color-SWIR composite to the default Map.
Map.setCenter(-122.6624, 38.5011, 12);
Map.addLayer(image, {bands: ['B7', 'B5', 'B3'], max: 0.3}, 'color-SWIR');

// Make another map and add a color-NIR composite to it.
var linkedMap = ui.Map();
linkedMap.addLayer(image, {bands: ['B5', 'B4', 'B3'], max: 0.3}, 'color-NIR');
// Add a thermal image to the map.
linkedMap.addLayer(image, {
  bands: ['B11'],
  min: 290,
  max: 305,
  palette: ['gray', 'white', 'yellow', 'red']
}, 'Thermal');

// Link the default Map to the other map.
var linker = ui.Map.Linker([ui.root.widgets().get(0), linkedMap]);

// Make an inset map and add it to the linked map.
var inset = ui.Map();
inset.style().set({position: 'bottom-right', width: '300px', height: '250px'});
inset.setControlVisibility({all: false, mapTypeControl: true});
linkedMap.add(inset);

// Register a function to the linked map to update the inset map.
linkedMap.onChangeBounds(function() {
  var bounds = ee.Geometry.Rectangle(Map.getBounds());
  inset.centerObject(bounds);
  inset.layers().set(0, bounds);
});

// Create a SplitPanel which holds the linked maps side-by-side.
var splitPanel = ui.SplitPanel({
  firstPanel: linker.get(0),
  secondPanel: linker.get(1),
  orientation: 'horizontal',
  wipe: true,
  style: {stretch: 'both'}
});

// Set the SplitPanel as the only thing in root.
ui.root.widgets().reset([splitPanel]);

O parâmetro wipe é definido como true, no construtor ui.SplitPanel, para permitir que o usuário deslize a alça para frente e para trás entre as duas visualizações.

Estilo dos widgets

O estilo de um widget é controlado pelo dicionário de propriedades de estilo do widget. Para acessar o dicionário, chame style() no widget. O objeto retornado por style() é uma instância de ui.data.ActiveDictionary. Isso significa que definir propriedades do dicionário de estilo atualiza automaticamente a forma como o widget é exibido. As chaves permitidas para o dicionário de estilo de cada widget são detalhadas nos documentos de referência do widget para a chamada style().

Os estilos do widget podem ser definidos com o construtor, chamando style().set() ou style() com um argumento de dicionário. Exemplo:

Editor de código (JavaScript)

var redLabel = ui.Label('Big, Red Label');

redLabel.style().set('color', 'red');
redLabel.style().set('fontWeight', 'bold');
redLabel.style().set({
  fontSize: '32px',
  padding: '10px'
});

print(redLabel);

Neste exemplo, o estilo do rótulo é definido primeiro chamando style().set() com argumentos de chave e valor e, em seguida, chamando style().set() com um argumento de dicionário. A segunda chamada não substitui a primeira. Ela adiciona e substitui propriedades de estilo individuais, em vez de substituir o dicionário de estilo inteiro.

Para mais informações sobre as opções de estilo para widgets, consulte esta referência de folha de estilo (CSS) em casca para os estilos listados nos documentos style() de cada widget. Os estilos permitidos para widgets do Earth Engine são diferentes dos estilos CSS em vários lugares, principalmente fontSize e fontWeight para font-style e font-weight, respectivamente.

O dicionário de estilos também contém chaves que controlam a posição do widget. Consulte a página Painéis e layouts para mais informações sobre como usar propriedades posicionais.