Информационные окна

Информационные окна (InfoBox) в CesiumJS предназначены для отображения сведений о выбранном объекте сцены. Они позволяют выводить текст, HTML-разметку, ссылки, таблицы, изображения и другие данные, связанные с сущностью (Entity). Информационные окна являются важным элементом интерфейса геоинформационных приложений, поскольку обеспечивают удобное взаимодействие пользователя с объектами на глобусе.

В стандартной конфигурации CesiumJS информационное окно автоматически появляется при выборе сущности мышью и отображает содержимое свойства description.


Автоматическое создание InfoBox

При создании объекта Viewer компонент информационного окна включён по умолчанию:

const viewer = new Cesium.Viewer("cesiumContainer");

В этом случае интерфейс содержит:

  • панель выбора объектов;
  • окно описания объекта;
  • кнопку закрепления окна;
  • кнопку закрытия окна.

Если пользователь выбирает сущность, имеющую описание, оно автоматически отображается в информационном окне.

Пример создания объекта:

viewer.entities.add({
    name: "Город Алматы",
    position: Cesium.Cartesian3.fromDegrees(76.8897, 43.2389),
    point: {
        pixelSize: 12,
        color: Cesium.Color.RED
    },
    description: "Крупнейший город Казахстана."
});

После щелчка по точке появится окно с указанным текстом.


Свойство description

Основным источником данных для информационного окна является свойство description.

Простейший вариант:

viewer.entities.add({
    name: "Объект",
    description: "Описание объекта"
});

Описание может быть:

  • строкой;
  • объектом Property;
  • динамически вычисляемым значением.

Например:

viewer.entities.add({
    name: "Башня",
    description: new Cesium.ConstantProperty(
        "Высота сооружения: 120 метров"
    )
});

Использование HTML-разметки

InfoBox поддерживает HTML-контент.

Пример:

viewer.entities.add({
    name: "Метеостанция",
    description: `
        <h2>Метеостанция №1</h2>
        <p>Температура: <b>18°C</b></p>
        <p>Влажность: <b>72%</b></p>
    `
});

Результат включает форматированный текст с заголовками и выделениями.

Допустимо использовать:

<h1>
<h2>
<h3>
<p>
<div>
<span>
<ul>
<li>
<table>
<img>
<a>

Формирование сложного описания

Часто информация представляется в виде таблиц.

Пример:

viewer.entities.add({
    name: "Спутник",
    description: `
        <table border="1">
            <tr>
                <th>Параметр</th>
                <th>Значение</th>
            </tr>
            <tr>
                <td>Высота</td>
                <td>550 км</td>
            </tr>
            <tr>
                <td>Скорость</td>
                <td>7.8 км/с</td>
            </tr>
        </table>
    `
});

Подобный подход широко применяется в системах мониторинга, диспетчерских приложениях и цифровых картах.


Добавление изображений

В описании можно размещать изображения.

Пример:

viewer.entities.add({
    name: "Озеро",
    description: `
        <h2>Озеро Балхаш</h2>
        <img
            src="images/balkhash.jpg"
            width="300"
        >
    `
});

Изображения могут загружаться:

  • из локального каталога проекта;
  • по URL;
  • из CDN.

Пример:

<img src="https://example.com/photo.jpg">

Добавление ссылок

Информационные окна поддерживают гиперссылки.

viewer.entities.add({
    name: "Документация",
    description: `
        <a href="https://cesium.com/learn/"
           target="_blank">
           Открыть документацию
        </a>
    `
});

Ссылки часто используются для перехода:

  • на страницы объектов;
  • в административные панели;
  • к отчётам;
  • к внешним сервисам.

Динамическое содержимое

Информация может формироваться в момент отображения.

Для этого используется CallbackProperty.

const aircraft = viewer.entities.add({
    position: Cesium.Cartesian3.fromDegrees(70, 50),
    point: {
        pixelSize: 10
    }
});

aircraft.description =
    new Cesium.CallbackProperty(function() {

        const altitude =
            Math.floor(Math.random() * 10000);

        return `
            <h3>Самолёт</h3>
            <p>Высота: ${altitude} м</p>
        `;

    }, false);

При каждом обновлении интерфейса содержимое пересчитывается.

Такой механизм полезен для:

  • телеметрии;
  • мониторинга транспорта;
  • отображения показаний датчиков;
  • отображения состояния оборудования.

Использование Entity Properties

Описание может содержать данные самой сущности.

const entity = viewer.entities.add({
    name: "Датчик",
    position: Cesium.Cartesian3.fromDegrees(75, 42)
});

entity.description =
    new Cesium.CallbackProperty(function() {

        const cartographic =
            Cesium.Cartographic.fromCartesian(
                entity.position.getValue(
                    Cesium.JulianDate.now()
                )
            );

        return `
            <p>Широта:
                ${Cesium.Math.toDegrees(
                    cartographic.latitude
                ).toFixed(4)}
            </p>
        `;
    }, false);

В результате данные внутри окна всегда соответствуют текущему состоянию объекта.


Выбор сущности программно

Информационное окно может открываться без участия пользователя.

Для этого используется свойство:

viewer.selectedEntity = entity;

Пример:

const city = viewer.entities.add({
    name: "Астана",
    description: "Столица Казахстана"
});

viewer.selectedEntity = city;

После выполнения кода окно автоматически откроется.


Закрытие информационного окна

Для скрытия окна необходимо сбросить выбранную сущность.

viewer.selectedEntity = undefined;

Или:

viewer.selectedEntity = null;

После этого окно исчезнет.


Получение выбранной сущности

Текущий выбранный объект хранится в свойстве:

viewer.selectedEntity

Пример:

if (viewer.selectedEntity) {

    console.log(
        viewer.selectedEntity.name
    );

}

Это позволяет организовать дополнительную бизнес-логику после выбора объекта.


Событие выбора объекта

Для отслеживания выбора используется событие:

viewer.selectedEntityChanged

Пример:

viewer.selectedEntityChanged.addEventListener(
    function(entity) {

        if (entity) {
            console.log(
                "Выбран объект:",
                entity.name
            );
        }

    }
);

Событие срабатывает:

  • при выборе;
  • при смене выбранного объекта;
  • при закрытии окна.

Настройка Viewer без InfoBox

Компонент можно отключить при создании Viewer.

const viewer = new Cesium.Viewer(
    "cesiumContainer",
    {
        infoBox: false
    }
);

После этого стандартное окно отсутствует.

Такой подход применяется при разработке собственного пользовательского интерфейса.


Работа с отдельным виджетом InfoBox

Компонент информационного окна существует как самостоятельный виджет.

Создание:

const infoBox = new Cesium.InfoBox(
    document.getElementById("infoBox")
);

После создания появляется независимое окно, не связанное напрямую с Viewer.

Это позволяет:

  • размещать окно в любой части страницы;
  • создавать несколько окон;
  • интегрировать Cesium в сложные интерфейсы.

Настройка содержимого через ViewModel

Внутри InfoBox используется объект InfoBoxViewModel.

Пример:

infoBox.viewModel.titleText =
    "Информация";

infoBox.viewModel.description =
    "<p>Содержимое окна</p>";

Изменение свойств приводит к автоматическому обновлению интерфейса.

Основные свойства:

Свойство Назначение
titleText Заголовок
description HTML-содержимое
showInfo Видимость
enableCamera Кнопка перехода
isCameraTracking Режим слежения

Кнопка перехода к объекту

Стандартное информационное окно содержит кнопку камеры.

Она позволяет быстро перейти к выбранному объекту.

При выборе сущности:

viewer.selectedEntity = entity;

нажатие на кнопку вызывает перемещение камеры к объекту.

Этот механизм особенно полезен при работе с большим количеством сущностей.


Слежение за объектом

После выбора объекта возможно включение режима слежения.

viewer.trackedEntity = entity;

Теперь камера будет автоматически сопровождать объект.

Информационное окно продолжит отображать данные выбранной сущности.

Отключение:

viewer.trackedEntity = undefined;

Использование CSS для оформления

Внешний вид содержимого можно полностью контролировать через CSS.

HTML:

description: `
<div class="station-info">
    <h2>Станция</h2>
    <p>Статус: активна</p>
</div>
`

CSS:

.station-info {
    font-family: Arial;
    padding: 10px;
}

.station-info h2 {
    color: #2c6cb0;
}

Это позволяет привести окно к стилю всего приложения.


Ограничения безопасности

Содержимое description вставляется как HTML.

При работе с внешними источниками данных необходимо учитывать риск внедрения вредоносного кода.

Опасный пример:

description =
    serverResponse;

Безопаснее выполнять предварительную очистку данных:

description =
    sanitize(serverResponse);

Особенно это важно для:

  • пользовательского контента;
  • данных из API;
  • загружаемых документов;
  • внешних веб-сервисов.

Генерация описания из объекта данных

Распространённым приёмом является автоматическое формирование HTML.

Исходные данные:

const station = {
    id: 10,
    name: "Станция А",
    temperature: 21,
    humidity: 65
};

Генерация:

const html = `
    <h2>${station.name}</h2>
    <p>ID: ${station.id}</p>
    <p>Температура: ${station.temperature}</p>
    <p>Влажность: ${station.humidity}%</p>
`;

Использование:

viewer.entities.add({
    description: html
});

Подобная техника позволяет быстро строить интерфейсы мониторинга и аналитические панели.


Практический пример

const airport = viewer.entities.add({
    name: "Аэропорт",
    position: Cesium.Cartesian3.fromDegrees(
        71.466,
        51.022
    ),
    point: {
        pixelSize: 12,
        color: Cesium.Color.ORANGE
    },
    description: `
        <h2>Международный аэропорт</h2>

        <table border="1">
            <tr>
                <td>Статус</td>
                <td>Открыт</td>
            </tr>
            <tr>
                <td>Рейсов сегодня</td>
                <td>128</td>
            </tr>
        </table>

        <br>

        <img
            src="images/airport.jpg"
            width="280"
        >
    `
});

viewer.selectedEntity = airport;

Данный пример объединяет большинство возможностей информационных окон: программное открытие, форматированный HTML, таблицу данных и встроенное изображение.