3

Is there a way to identify which ui.Map() instance a widget is located in when using multiple maps in Earth Engine?

For example, I have 2 maps, each having a textbox and a button. When a button is clicked, I want to print contents of a textbox from the same map with printAdjacentTextBoxValue() callback function. I deliberately use the same function for both buttons in order to use the same logic for multiple maps depending on their context.

This is an example code:

var left_map = ui.Map();
var right_map = ui.Map();

var left_textBox = ui.Textbox({value: 'left one'});
var right_textBox = ui.Textbox({value: 'right one'});

var left_button = ui.Button('click', printAdjacentTextBoxValue);
var right_button = ui.Button('click', printAdjacentTextBoxValue);


// universal function to provide same logic for both maps, 
// yeilding potentially different results based on a different state of elements 
function printAdjacentTextBoxValue() {
  var value;
  // get value from a textBox from the same Map
  print(vlaue);
}


ui.root.clear();

ui.root.add(left_map);
ui.root.add(right_map);

left_map.add(left_textBox);
right_map.add(right_textBox);

left_map.add(left_button);
right_map.add(right_button);

EE script version

4

You don't have to use the same function to reuse logic; you can create different functions from the same code, by doing it inside another function. Example:

function putButtonAndTextBox(map, initialValue) {
  var textBox = ui.Textbox({value: initialValue});

  function printAdjacentTextBoxValue() {
    var value = textBox.getValue();
    print(value);
  }
  var button = ui.Button('click', printAdjacentTextBoxValue);

  map.add(textBox);
  map.add(button);
}

var left_map = ui.Map();
var right_map = ui.Map();

ui.root.clear();

ui.root.add(left_map);
ui.root.add(right_map);

putButtonAndTextBox(left_map, 'left one');
putButtonAndTextBox(right_map, 'right one');

https://code.earthengine.google.com/140822cb1f5481539eb8bc5af43b7c85

In this example I assumed that you would want the same button and text box setup, for both maps but that you would be configuring each map separately, so the map creation is outside the function. If you wanted to create the text box differently for each side and only have a common button setup, you could do things like that too (partial example):

function makeButtonForTextBox(textBox) {
  function printAdjacentTextBoxValue() {
    var value = textBox.getValue();
    print(value);
  }
  return ui.Button('click', printAdjacentTextBoxValue);
}

var left_button = makeButtonForTextBox(left_textBox);
var right_button = makeButtonForTextBox(right_textBox);
left_map.add(left_button);
right_map.add(right_button);

There are lots of possible variations. Which one best suits depends on exactly what you're doing; the general principle is: to avoid repeating code, put it in a function, even if the code is itself a function.

2

Interesting question. You should add some data to each button to find back which button is clicked by a user.

Although I don't think it is very convenient, this might lead you into a right direction. There is no UserData argument in the ui.Button to add (maybe a feature request to add?), but I found out you could set for example the fontWeight argument in style without seriously effecting your ui.Button. That fontWeight property can be found and so you can determine which button is actually clicked. Hope this will get you somehow in the right direction:

// set a property to the Button indicating the index of the map 
var left_button = ui.Button('click', printAdjacentTextBoxValue, false, {fontWeight: 0}); // left
var right_button = ui.Button('click', printAdjacentTextBoxValue, false, {fontWeight: 1}); // right

// universal function to provide same logic for both maps, 
// yeilding potentially different results based on a different state of elements 
function printAdjacentTextBoxValue(value) {
  // get style property from a button
  var mapIndex = Number(value.style().get('font-weight'));
  print('index of Map',mapIndex);

  // make a list of the maps(placing left map at 0, right at 1)
  var listMaps = [left_map.widgets(), right_map.widgets()];

  // now get the map we want
  var mapCurrent = listMaps[mapIndex];
  // set the new texts in the textBox of that map (textbox has index 0, button index 1)
  mapCurrent.set(0, ui.Textbox({value: mapCurrent.get(0).getValue(), 
                                style: mapCurrent.get(0).style()})); 

  // print the new text
  print(mapCurrent.get(0).getValue())

}

Note that the position is changed to the default place, as you will make a new ui.Textbox. I didn't find a way to easily overwrite the current textbox (but probably there should be). You could set a position of some other argument in the style of the textBox, and copy its style properties as I have done in this example.

Link code

1
  • Thank you, thant's an interesting way to experiment! – Basile Mar 13 '20 at 8:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.