Paneles y diseños

Paneles

Un ui.Panel es un contenedor de IU de nivel superior en el que se organizan los widgets. Cada ui.Panel tiene un objeto ui.Panel.Layout que controla cómo se organizan sus widgets en la pantalla. Obtén más información en la sección Diseños. Los paneles también mantienen una lista de widgets (que podrían incluir otros paneles) que se les agregaron. Para administrar los widgets en el panel, add() o remove() desde el panel, o bien llama a widgets() en el panel para recuperar la lista de widgets. La lista de widgets es una instancia de ui.data.ActiveList, lo que significa que puedes configurar el panel manipulando la lista y los widgets que contiene.

ui.root

ui.root es una instancia fija de un ui.Panel para todo lo que se encuentra en el editor de código debajo de la barra horizontal. De forma predeterminada, solo contiene un widget: el mapa predeterminado. Específicamente, el elemento en ui.root.widgets().get(0) es el objeto Map (una instancia de ui.Map) que se muestra de forma predeterminada en el Editor de código. Además del alias Map, la única otra característica especial del mapa predeterminado es que tiene herramientas de edición de geometría. Para obtener un lienzo vacío en el que compilar tu IU, clear() el mapa predeterminado de ui.root:

Editor de código (JavaScript)

ui.root.clear();

Como alternativa, puedes modificar el mapa predeterminado en el panel raíz si le agregas widgets. Específicamente, piensa en un mapa como un panel con un diseño absoluto (consulta la sección Diseños para obtener más información). En el siguiente ejemplo, se ilustra una modificación del mapa predeterminado:

Editor de código (JavaScript)

// Load a VIIRS surface reflectance image and display on the map.
var image = ee.Image('NOAA/VIIRS/001/VNP09GA/2022_06_05').select('M.*');
Map.addLayer(image, {bands: ['M5', 'M4', 'M3'], min: 0, max: 4e3, gamma: 1.5});

// Create the title label.
var title = ui.Label('Click to inspect');
title.style().set('position', 'top-center');
Map.add(title);

// Create a panel to hold the chart.
var panel = ui.Panel();
panel.style().set({
  width: '400px',
  position: 'bottom-right'
});
Map.add(panel);

// Register a function to draw a chart when a user clicks on the map.
Map.style().set('cursor', 'crosshair');
Map.onClick(function(coords) {
  panel.clear();
  var point = ee.Geometry.Point(coords.lon, coords.lat);
  var chart = ui.Chart.image.regions(image, point, null, 30);
  chart.setOptions({title: 'Band values'});
  panel.add(chart);
});

Ten en cuenta que el ejemplo modifica el mapa predeterminado (que es Map) tratándolo como un panel y agregándole widgets. Debido a que los mapas tienen un diseño absoluto, la posición de un widget en un mapa se determina mediante una propiedad position de la propiedad style del widget. Consulta la sección de diseño absoluto para obtener más detalles.

Cuando compartes un vínculo del editor de código con otro usuario, de forma predeterminada, ui.root ocupa la mayor parte de la ventana, y se ocultan el editor de texto, el panel de documentos y la consola. Si controlas el diseño de ui.root, puedes controlar la experiencia de otros usuarios con tu secuencia de comandos.

Diseños

Los diseños controlan cómo se organizan los widgets de un panel para su visualización. Hay dos opciones de diseño, que se describen a continuación: diseño de flujo y diseño absoluto. Los diseños se especifican con la clase ui.Panel.Layout. Establece el diseño de un panel en el constructor o con setLayout(). El orden en el que se agregan los widgets determina cómo se organizan en un panel con diseño de flujo. La propiedad position de cada style del widget determina cómo se organizará un widget en un panel con diseño absoluto. Si el estilo de un widget es irrelevante para el diseño en el que se coloca, se ignora.

Flujo

Un diseño de flujo muestra widgets en una fila ('horizontal') o una columna ('vertical'). Los widgets se organizan según el orden en que se agregan al panel. Por ejemplo, considera los siguientes botones agregados a un panel:

Editor de código (JavaScript)

// Create a panel with vertical flow layout.
var panel = ui.Panel({
  layout: ui.Panel.Layout.flow('vertical'),
  style: {width: '300px'}
});

// Add a bunch of buttons.
for (var i = 0; i < 30; i++) {
  panel.add(ui.Button({label: 'Button ' + i, style: {stretch: 'horizontal'}}));
}

ui.root.clear();
ui.root.add(panel);

El diseño vertical debería verse de la siguiente manera:

ui_flow_layout.png

Ten en cuenta que el width del panel se establece en 300 píxeles y el stretch se establece en 'horizontal' con la propiedad style. La propiedad de estilo stretch se aplica a los widgets de un panel con diseño de flujo. Por ejemplo, {stretch: 'horizontal'} significa que el widget se expandirá para llenar el espacio horizontal disponible dentro del panel. En el ejemplo anterior, cambia el tipo de diseño de flujo a 'horizontal' para ver los botones organizados en una fila en lugar de una columna.

En un panel de flujo horizontal, un widget estirado horizontalmente se expande para llenar el espacio disponible después de que todos los demás widgets hayan ocupado sus anchos naturales. Si más de un widget se estira horizontalmente, el espacio horizontal disponible se divide entre ellos. Un widget estirado verticalmente se expande para ocupar la altura del panel.

En un panel de flujo vertical, un widget estirado verticalmente se expande para llenar el espacio disponible después de que todos los demás widgets hayan ocupado sus alturas naturales. Si se estira más de un widget verticalmente, el espacio vertical disponible se divide entre ellos. Un widget estirado horizontalmente se expande para ocupar el ancho del panel.

Absoluto

Un diseño absoluto posiciona los widgets según las posiciones en el panel. A diferencia del diseño de flujo, la posición de un widget está determinada por la propiedad position de la propiedad style del widget, no por el orden en el que se agrega al panel. En el siguiente ejemplo, se muestra cómo usar el panel root.ui con un diseño absoluto (el diseño del panel raíz es un flujo horizontal de forma predeterminada, pero se puede establecer con ui.root.setLayout()):

Editor de código (JavaScript)

ui.root.clear();
ui.root.setLayout(ui.Panel.Layout.absolute());

// A function to make buttons labeled by position.
function makeButton(position) {
  return ui.Button({
    label: position,
    style: {position: position}
  });
}

// Add labeled buttons to the panel.
ui.root.add(makeButton('top-left'));
ui.root.add(makeButton('top-center'));
ui.root.add(makeButton('top-right'));
ui.root.add(makeButton('middle-left'));
ui.root.add(makeButton('middle-right'));
ui.root.add(makeButton('bottom-left'));
ui.root.add(makeButton('bottom-center'));
ui.root.add(makeButton('bottom-right'));

El panel de diseño absoluto debería verse de la siguiente manera:

ui_absolute_layout.png

widgets()

Cuando agregas un widget a un panel, este se agrega a la lista de widgets del panel. Llamar a widgets() en el panel muestra el ui.data.ActiveList que puedes usar para manipular los widgets del panel. Considera el siguiente ejemplo, que agrega widgets a un panel, lo agrega al panel raíz y, luego, actualiza un gráfico cuando el usuario hace clic en el mapa:

Editor de código (JavaScript)

// Load and display NDVI data.
var ndvi = ee.ImageCollection('NOAA/VIIRS/001/VNP13A1')
    .filterDate('2021-01-01', '2022-01-01').select('NDVI');
Map.addLayer(
  ndvi.median(), {min: 0, max: 10000, palette: ['99c199', '006400']}, 'NDVI');

// Configure the map.
Map.setCenter(-94.84497, 39.01918, 8);
Map.style().set('cursor', 'crosshair');

// Create an empty panel in which to arrange widgets.
// The layout is vertical flow by default.
var panel = ui.Panel({style: {width: '400px'}})
    .add(ui.Label('Click on the map'));

// Set a callback function for when the user clicks the map.
Map.onClick(function(coords) {
  // Create or update the location label (the second widget in the panel)
  var location = 'lon: ' + coords.lon.toFixed(2) + ' ' +
                 'lat: ' + coords.lat.toFixed(2);
  panel.widgets().set(1, ui.Label(location));

  // Add a red dot to the map where the user clicked.
  var point = ee.Geometry.Point(coords.lon, coords.lat);
  Map.layers().set(1, ui.Map.Layer(point, {color: 'FF0000'}));

  // Create a chart of NDVI over time.
  var chart = ui.Chart.image.series(ndvi, point, ee.Reducer.mean(), 200)
      .setOptions({
        title: 'NDVI Over Time',
        vAxis: {title: 'NDVI'},
        lineWidth: 1,
        pointSize: 3,
      });

  // Add (or replace) the third widget in the panel by
  // manipulating the widgets list.
  panel.widgets().set(2, chart);
});

// Add the panel to the ui.root.
ui.root.add(panel);

En este ejemplo, observa que, en primer lugar, los widgets se agregan al panel con add(). En la función de devolución de llamada registrada para asignar clics, se modifica la lista de widgets de panel. Específicamente, el tercer widget (que puede existir o no) se configura de modo que se muestre un gráfico nuevo del NDVI a lo largo del tiempo. Obtén más información sobre las funciones de control de eventos en la página Eventos.