Для создания пользовательских интерфейсов можно использовать различные виджеты. К ним относятся кнопки, флажки, ползунки, текстовые поля и меню выбора. Виджеты можно напечатать или добавить на панель только один раз. В следующих разделах описываются основные функции, внешний вид и поведение виджетов. Подробнее о том, как настроить стиль виджетов, рассказывается в разделе Стиль. В примерах ниже виджеты просто выводятся в консоль с помощью print(). Подробную информацию о добавлении виджетов на панели можно найти на странице Панели и макеты.
ui.Label
Ярлыки – это просто области, в которых показывается текст. Например, следующий код печатает этикетку:
Редактор кода (JavaScript)
var label = ui.Label('Cool label!'); print(label);
Это выглядит примерно так:
Разбивайте длинные ярлыки, вставляя символ новой строки (\n) и задавая для аргумента свойства стиля whiteSpace значение 'pre':
print(ui.Label('Here is a:\nnew line', {whiteSpace: 'pre'}));
ui.Button
Кнопка – это интерактивный виджет пользовательского интерфейса, на который можно нажать. Вы можете указать функцию, которая будет вызываться (функция обратного вызова), когда пользователь нажимает кнопку. Дополнительную информацию об обработке событий с помощью функций обратного вызова можно найти на странице событий. В примере ниже при нажатии кнопки выводится текущий центр карты.
Редактор кода (JavaScript)
var button = ui.Button({ label: 'Get Map Center', onClick: function() { print(Map.getCenter()); } }); print(button);
Это выглядит примерно так:
ui.Checkbox
Флажок – это виджет, который позволяет пользователю установить или снять флажок. При изменении состояния флажка обратным вызовам, зарегистрированным в виджете, передается логическое значение, указывающее, установлен ли флажок. Пример:
Редактор кода (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);
Флажок должен выглядеть примерно так:
Обратите внимание, что при установке флажка на карте появляется слой. Как и другими компонентами интерфейса, картой в редакторе кода можно управлять программно. Подробнее об объекте Map рассказывается в статье Панели и макеты.
ui.Slider
Ползунок – это виджет, который позволяет пользователю выбрать число в заданном диапазоне. Настройте диапазон с помощью конструктора или задав свойства ползунка. В следующем примере ползунок используется для настройки прозрачности первого слоя на карте:
Редактор кода (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);
Ползунок должен выглядеть примерно так:
Обратите внимание, что значение ползунка показано справа от него.
ui.DateSlider
Виджет DateSlider похож на виджет Slider, но работает с датами. Вот как выглядит элемент DateSlider, настроенный для выбора дня в июне 2018 года:
DateSlider удобно использовать для фильтрации коллекций, как показано в следующем примере, в котором создается годовой композит на основе DateRange, заданного в DateSlider:
Редактор кода (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
Текстовое поле – это место, где собирается текст, введенный пользователем. Пример:
Редактор кода (JavaScript)
var textbox = ui.Textbox({ placeholder: 'Enter text here...', onChange: function(text) { print('So what you are saying is ' + text + '?'); } }); print(textbox);
Текстовое поле должно выглядеть примерно так:
Обратите внимание, что обратный вызов активируется только после того, как пользователь закончит вводить текст и нажмет Ввод или щелкнет за пределами текстового поля.
ui.Select
Виджет выбора представляет собой раскрывающееся меню, из которого пользователь может выбрать один вариант. В примере ниже показано раскрывающееся меню, в котором пользователь может выбрать местоположение.
Редактор кода (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);
Виджет выбора должен выглядеть примерно так:
ui.Chart
Диаграммы в пакете ui.Chart ведут себя так же, как и в пакете Chart. В частности, ui.Chart – это тонкая оболочка вокруг экземпляра ChartWrapper API визуализации Google.
Дополнительную информацию о работе с объектами ChartWrapper можно найти в этом справочном руководстве. Дополнительную информацию о вспомогательных функциях диаграмм в Earth Engine можно найти в документации по диаграммам.
ui.Thumbnail
Виджет значка можно использовать для предварительного просмотра объектов ee.Image и ee.ImageCollection. Если в качестве входных данных используется ee.Image, виджет показывает статичное изображение. Если же используется ee.ImageCollection, виджет показывает анимацию, в которой каждому изображению соответствует один кадр. Как и в случае с ee.Image.getThumbURL() и ee.ImageCollection.getVideoThumbURL(), вы можете указать параметры, чтобы задать формат и размеры значка:
Редактор кода (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'} }));
Значок должен выглядеть примерно так:
ui.Map
ui.Map – это виджет карты. (По сути, объект Map в редакторе кода по умолчанию является экземпляром этого класса). Как и другие виджеты, карту можно вывести в консоль. Управлять контентом карты, очищая, получая или настраивая отдельные слои. В следующем примере в консоль выводится карта, на которой показаны границы карты редактора кода:
Редактор кода (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);
Врезная карта должна выглядеть примерно так:
В этом примере пользователю нужно нажать на большую карту, чтобы на маленькой карте появилась вставка.
Вы также можете управлять слоями на карте, вызывая метод layers() для экземпляра карты. layers() возвращает ui.data.ActiveList – объект, похожий на массив. При изменении этого значения слои на карте также меняются. Подробнее об этом рассказывается в разделе ui.Map.Layer.
ui.Map.Layer
Слой – это не виджет, стиль которого можно настраивать, как у ui.Button. Это просто представление данных слоя на карте. В примере ниже показано, как обновить карту, создав слой и изменив его свойства на основе ввода пользователя.
Редактор кода (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_HARMONIZED/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
Если вы хотите показать (например, в приложении) слой, требующий относительно больших вычислительных ресурсов, то в целях повышения производительности лучше экспортировать данные в сегмент Cloud Storage. Эти статические слои, предназначенные только для визуализации, могут повысить скорость отклика приложений и скриптов. Для этого можно создать статический слой отображения с помощью Export.map.toCloudStorage().
Чтобы использовать набор фрагментов, ранее экспортированный с помощью Export.map.toCloudStorage(), создайте новый объект ui.Map.Layer из указанного сегмента и пути Cloud Storage:
Map.add(ui.Map.CloudStorageLayer({ bucket: 'earthenginepartners-hansen', path: 'tiles/gfc_v1.4/loss_year', maxZoom: 12, suffix: '.png' }));
При запуске скрипта, загружающего слой Cloud Storage, может появиться следующее предупреждение:
ui.Map.DrawingTools
В редакторе кода есть набор инструментов для рисования геометрических фигур, который по умолчанию добавляется в Map. Вы можете изменить поведение этих инструментов в Map по умолчанию, вызвав Map.drawingTools(). Например, чтобы скрыть инструменты рисования:
Редактор кода (JavaScript)
Map.drawingTools().setShown(false);
По умолчанию на новых картах нет инструментов рисования, но их можно включить, вызвав для карты метод drawingTools():
Редактор кода (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]);
Слои геометрии, нарисованные с помощью инструментов рисования, помещаются в объект ui.data.ActiveList, к которому можно получить доступ, вызвав метод Map.drawingTools().layers(). Список слоев геометрии реагирует на события так же, как и другие активные списки, например список слоев на Map, возвращаемый Map.layers(). В следующем примере показано, как настроить видимость геометрических слоев, нарисованных инструментами (которые отображаются по умолчанию):
Редактор кода (JavaScript)
Map.drawingTools().layers().forEach(function(layer) { layer.setShown(false); });
Чтобы добавить слой в инструменты рисования программно, вызовите метод addLayer для инструментов рисования или добавьте слой непосредственно в список слоев:
Редактор кода (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);
Состояние инструментов рисования также переносится при публикации приложения. Если инструменты рисования показаны или скрыты, они также будут показаны или скрыты в вашем приложении. Геометрии в импортированных файлах также будут перенесены в ваше приложение.
ui.Map.GeometryLayer
GeometryLayer – это набор геометрических фигур, который действует как единый объект Geometry, GeometryCollection или FeatureCollection, добавляемый в раздел импорта в верхней части скрипта и доступный для ссылки в коде.
У GeometryLayer, созданных с помощью инструментов рисования, есть режим работы по умолчанию, который можно переопределить, указав новые функции обратного вызова. Например, вы хотите, чтобы интерактивные изменения геометрии вызывали событие. Чтобы реализовать определенное поведение, вы можете задать методы onEdit(), onErase() или onDraw() для инструментов, чтобы реагировать на действия пользователя.
В следующем примере показано, как запустить вычисление и обновить ярлык с результатом вычисления, когда пользователь добавляет, редактирует или стирает геометрию:
Редактор кода (JavaScript)
// Load elevation data. var srtm = ee.Image('NASA/NASADEM_HGT/001').select('elevation'); 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() используется для переключения связи между инструментами рисования геометрии и разделом Импорт редактора кода. В этом примере инструменты геометрии не связаны, чтобы предотвратить создание импорта. toGeometry используется для преобразования слоя в ee.Geometry. Если импортированный слой представляет собой Feature или FeatureCollection, вы можете получить базовый объект EE с помощью getEeObject(). Обратите внимание, что мы используем ui.util.debounce, чтобы функция обратного вызова не срабатывала при каждом перемещении геометрии. В частности, функция не будет выполняться, пока не пройдет 100 миллисекунд с момента последнего события. Это гарантирует, что функция будет выполняться только после того, как пользователь завершит редактирование.
Геометрический слой в импортируемых данных связан с Geometry или GeometryCollection, поэтому он может содержать только геометрии с одинаковым геодезическим состоянием, поскольку формат GeoJSON допускает только одно геодезическое состояние для набора геометрий (дополнительную информацию см. на странице Геодезическая и планарная геометрия). Чтобы добавить геодезические и планарные геометрические объекты на один слой, преобразуйте слой геометрии в FeatureCollection, нажав на значок шестеренки рядом с названием слоя. Однако при попытке преобразовать его обратно в Geometry возникнет ошибка. Чтобы избежать этого, преобразуйте слой в FeatureCollection или удалите геометрии, пока в слое не останется только одно геодезическое состояние.
ui.Map.Linker
Как и слой, связыватель не является виджетом, стиль которого можно настраивать. Это фоновая утилита, которая позволяет синхронизировать перемещение нескольких экземпляров ui.Map.
Редактор кода (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
ui.SplitPanel удобно использовать для сравнения. Преимущество ui.SplitPanel перед двумя обычными панелями заключается в том, что с помощью маркера можно добиться перехода между панелями в ui.SplitPanel. В следующем примере используется ui.SplitPanel, чтобы показать спектральные различия следов пожара:
Редактор кода (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]);
Обратите внимание, что в конструкторе ui.SplitPanel для параметра wipe задано значение true, чтобы пользователь мог перемещать ползунок между двумя визуализациями.
Виджеты стилей
Стиль виджета определяется словарем его свойств. Чтобы получить доступ к словарю, вызовите метод style() для виджета. Объект, возвращаемый методом style(), является экземпляром ui.data.ActiveDictionary. Это означает, что при изменении свойств словаря стилей автоматически обновляется внешний вид виджета. Допустимые ключи для словаря стилей каждого виджета подробно описаны в справочной документации по виджетам для вызова style().
Стили виджета можно задать с помощью конструктора, вызвав метод style().set() или style() с аргументом словаря. Пример:
Редактор кода (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);
Обратите внимание, что в этом примере стиль ярлыка сначала задается путем вызова style().set() с аргументами ключа и значения, а затем – путем вызова style().set() с аргументом словаря. Второй вызов не переопределяет первый, а добавляет и заменяет отдельные свойства стиля, а не весь словарь стилей.
Дополнительную информацию о вариантах оформления виджетов можно найти в справочнике по каскадным таблицам стилей (CSS) для стилей, перечисленных в документации style() для каждого виджета. Обратите внимание, что стили, допустимые для виджетов Earth Engine, отличаются от стилей CSS в нескольких местах, в частности fontSize и fontWeight для font-style и font-weight соответственно.
Словарь стилей также содержит ключи, которые управляют положением виджета. Дополнительную информацию об использовании свойств позиционирования можно найти на странице Панели и макеты.