¿Cómo crear un visor GIS con Cesium representando GeoJson servidos por un API REST del API Manager?
- 1 Introducción
- 2 Creación de API REST
- 3 Creación de un visor Cesium
- 3.1.1.1 Código básico de Cesium
- 3.1.1.2 Línea 11
- 3.1.1.3 Línea 13
- 3.1.1.4 Código inicial
- 3.1.1.5 Código final
- 3.1.1.6 Código final
- 3.1.1.7 Código básico de Cesium
- 3.1.1.8 Código de ajax
- 3.1.2 Token del usuario
- 3.1.3 Uso de $ y jQuery
- 3.2 Código completo del visor:
- 3.2.1 Código básico de Cesium
Introducción
Este tutorial se organiza en 2 partes:
En primer lugar, la creación de un API REST desde el API Manager que sirve puntos en formato GeoJSON
Y en segundo lugar, en cómo crear un visor Cesium que represente los puntos del API REST antes generado.
Como ejemplo de capa de puntos, se hará uso de una serie de árboles geolocalizados en Las Palmas.
El ejemplo se ha desarrollado en el Entorno CloudLab de la Plataforma con un usuario con rol Developer.
Creación de API REST
Paso 1: Generación de la ontología
En primer lugar, hay que generar una ontología que contenga la información, tanto geográfica como genérica, de los puntos que el servicio va a servir.
Como ejemplo para este tutorial, se va a crear una ontología que contenga una serie de árboles geolocalizados en Las Palmas.
En primer lugar, desde el "menú de desarrollo" se seleccionará la opción de "Mis Ontologías".
En "Mis Ontologías", se creará una nueva ontología pulsando sobre el botón de "Nuevo". De entre las distintas opciones que saldrán, se seleccionará la primera de ellas: "Creación paso a paso".
Esta opción lanzará el editor de ontologías, en donde se introducirán los datos de la ontología que se va a crear. Los datos requeridos son los siguientes:
Nombre: el nombre que tendrá la ontología en el registro de ontologías. Para este ejemplo se usará "ont_gis_arboles_palmas".
Meta-information: las etiquetas (tags) que se utilizan para definir la ontología y facilitar su posterior filtrado. En este caso se han utilizado las de "gis", "árboles" y "las palmas".
Activa: define si la ontología está activa o no. Por defecto está activa, y así se dejará.
Pública: define si la ontología es accesible o no. Por defecto está desactivada, por lo que hay que marcarla.
Descripción: texto resumen sobre de qué va la ontología.
Permite campos cifrados: opción que permite la existencia de campos cifrados en la ontología. Por defecto aparece desactivada, y así se dejará.
Más abajo en la página, en la parte de "Plantillas de ontología", se seleccionará dentro del grupo "General" la plantilla de "EMPTYBASE".
Seleccionando esta plantilla, saldrá una ventana avisando de que al cambiar la plantilla se perderán todos los cambios que hubiesen y que el esquema de la ontología se reiniciará. Se pulsará en "Confirmar" para continuar.
Tras cerrarse la ventana, en la parte de "Plantillas de ontología" y a la derecha de las plantillas por las que antes se navegó, ha aparecido una nueva tabla en la que poder definir las propiedades de la ontología que se está creando. Pulsando sobre "Nueva propiedad" se puede ir introduciendo el nombre de la propiedad, el tipo de dato, si es requerido o no, si se encuentra encriptado y su descripción.
Para la ontología de árboles se han definido tres propiedades: un campo identificador único, un campo que indique si el árbol está sano o enfermo, y otro campo con las coordenadas de cada árbol. Formateando esta información a lo que necesita la ontología se tendría:
Propiedad | Tipo de dato | Requerido | Encriptado | Descripción |
|---|---|---|---|---|
oid | number | Required | false | Campo único |
estado | string | Required | false | Estado: sano/enfermo |
geometry | geometry | Required | false | Geometría |
Rellenados los campos que se quieren, en la parte inferior de la pantalla se pulsará sobre el botón de "Nuevo", generando así la ontología. Saldrá una ventana que indicará que la ontología se ha creado, preguntando qué hacer a continuación con ella. Aunque existe la opción de crear una nueva API Rest para la ontología, de momento no se hará, por lo que se cerrará la ventana.
Paso 2: Cargar datos en la ontología
Regresando al "Listado de ontologías", la ontología recién creada debería poder visualizarse en el listado. Sin embargo, ésta se encuentra vacía, pues sólo se ha definido su plantilla de formato, pero no se han introducido datos. Para ello, en la parte derecha de la ontología se encuentra el acceso directo al "CRUD", que será desde donde se introducirán los datos de los árboles.
Tras acceder al "CRUD", pulsando en el botón de "Nuevo" aparecerá una ventana en la que se podrá ir introduciendo los datos de cada campo definido a la hora de crear la ontología. En la parte derecha de la pantalla se presenta un "Output" del elemento que se está creando con los datos suministrados, para ir visualizando cómo quedará.
Una vez completado de rellenar los campos se pulsará en el botón de "Nuevo", situado en la parte inferior derecha. Tras ello, se regresará a la pantalla de registros de "CRUD", en donde se verá que lo que se acaba de hacer se encuentra registrado.
Pulsando nuevamente en el botón de "Nuevo" se podrá introducir otro registro nuevo. Todos los registros a introducir para el ejemplo de los árboles serían los siguientes:
oid | estado | item1 | item2 |
|---|---|---|---|
1 | Sano | -15.434542724575984 | 28.134485149616452 |
2 | Sano | -15.434373993571144 | 28.134506947504082 |
3 | Enfermo | -15.434218159203619 | 28.134506947504082 |
4 | Sano | -15.434051577638332 | 28.13452211124939 |
5 | Enfermo | -15.433886070792816 | 28.134551490999808 |
6 | Sano | -15.433729161705513 | 28.134552438733564 |
Como nota aclaratoria, nótese que el campo "Item1" hace referencia a la longitud, y el campo "Item2" a la latitud, según el formato EPSG:4326 (WGS84).
Una vez que se han generado todos los registros se da por finalizada la ontología, por lo que se puede proceder a generar la API.
Paso 3: Generación del API REST que disponibiliza los datos de la ontología
Una vez creada la ontología, se va a proceder a generar el servicio de API Rest que consuma dicha ontología y la sirva vía web.
En primer lugar es preciso conocer cuál es el "token" personal del usuario para poder autorizarse en el uso del servicio Rest. Para conocer dicho dato, se navegará desde el "menú de desarrollo" hasta la opción de "Mis APIs".
En la parte superior derecha de la pantalla hay un botón que indica "Tokens usuario". Pulsando sobre él se acceder a una ventana donde se encuentra el "token" del usuario. En caso de no existir ninguno, es posible generar uno mediante el botón de "token". Este código se copiará y guardará para aplicarse más adelante.
Volviendo a "Mis APIs", se procederá a crear uno nuevo pulsando el botón de "Nuevo", lo que lanzará el configurador del API. Al igual que en el caso de las ontologías, se procederá a rellenar los datos solicitados.
Los datos requeridos son los siguientes:
Identificación: el nombre que tendrá el API en el registro de APIs. Para este ejemplo se usará "api_gis_arboles_palmas", siguiendo el estilo de la ontología.
Versión: valor numérico con la versión del API. No es posible modificarlo inicialmente, por lo que se dejará como está.
Categoría: se seleccionará en el combobox de categorías una en la que la API tenga cabida. Para este ejemplo se ha escogido la de "social".
Tipo de API: de momento sólo existe la posibilidad de "Publicar Ontología como API Rest".
Ontología: nombre de la ontología con la que trabajará el API. Se seleccionará la ontología previamente creada: "ont_gis_arboles_palmas".
Peticiones por minuto: limitador del número de peticiones que aceptará el API por minuto. Por defecto no se encuentra activa, y así se dejará.
Público: define si el API es accesible o no. Por defecto está desactivado, por lo que hay que marcarlo.
Endpoint Base: este campo se genera automáticamente, por lo que no hay que interactuar con él.
Descripción: texto resumen sobre de qué va el API.
Meta-information: las etiquetas (tags) que se utilizan para definir el API y facilitar su posterior filtrado. En este caso se han utilizado las de "api", "gis", "árboles", "las palmas" y "api rest".
Rellenados los campos solicitados, en la parte inferior de la página se pregunta por el tipo de operación que realizará el API. Para este caso, se seleccionará la opción de "Query (Custom)", lo que lanzará una ventana en donde configurar dicho "query", que se hará con los siguientes datos:
Método: GET (el único seleccionable de momento).
Nombre: de la función del método. Para este ejemplo se llamará "getArboles".
Query: qué se quiere seleccionar de la ontología. Para este caso se seleccionará todo el contenido mediante "SELECT * from ont_gis_arboles_palmas".
Tipo Query: SQLLIKE (valor por defecto).
Target BD: BD Tiempo Real (valor por defecto).
Descripción: texto descriptivo de la función query que se está creando.
Este API REST devolverá la información de la ontología en formato JSON. Como necesito que esta se devuelva en formato GeoJSON, necesito procesar la salida del API, por lo que se marcará la opción de "Activar procesado", lo que desplegará una pequeña pantalla en donde introducir código. En dicha ventana se preparará el código de salida tal como se define a continuación:
Activar procesado
// data is a string variable containing the query output
var dataArray = JSON.parse(data);
var features= [];
dataArray.forEach(function(arboles) {
var feature = {
"type": "Feature",
"properties":{
"oid": arboles.ont_gis_arboles_palmas.oid,
"estado": arboles.ont_gis_arboles_palmas.estado
},
geometry: arboles. .ont_gis_arboles_palmas.geometry
}
features.push(feature)
});
var geoJsonResult={
"type": "FeatureCollection",
"name": "Árboles de la calle",
"features": features
};
// A string result must be returned
return (JSON.stringify(geoJsonResult));
Una vez introducido el código, se guardarán los cambios pulsando en el botón de "Save Changes", y seguidamente en el de "Nuevo", para crear el nuevo API. Regresando a "Mis APIs", la nueva API deberá aparecer listada.
El último paso es autorizarla con el "token" de usuario que antes se obtuvo. Para hacerlo, en la parte derecha de la API creada hay un botón llamado "</> Swagger". Pulsando sobre él se abre la ventana de "Invocación del API". Bajando por la pantalla se llega hasta la pestaña "default", que desplegándola muestra otro botón llamado "Try it out", el cual permite introducir el "token" de usuario en un campo llamado X-OP-APIKey.
Una vez introducido, se pulsará sobre el botón de "Execute", generándose el Curl y la URL de llamada a la API.
Creación de un visor Cesium
Seguidamente, se va a generar un visor web en el que poder visualizar la ontología de árboles creada consumiendo la información proporcionada por el servicio Rest.
El visor se creará mediante Cesium, una biblioteca gratuita y de código abierto de JavaScript para globos y mapas 3D de clase mundial.
A la hora de trabajar con este visor, existen dos posibilidades:
Descargarlo y desplegarlo en un servidor local: en la página web hay un tutorial que explica cómo generar un servidor local con Node para trabajar con el mapa.
Generar un visor independiente: que es lo que se usará en este tutorial por rapidez y facilidad.
Para generar el visor independiente, se partirá del código HTML, CSS y JavaScript de la versión de descarga y despliegue local. Dicho código, que se copiará en un nuevo documento HTML es el siguiente:
Código básico de Cesium
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Use correct character set. -->
<meta charset="utf-8">
<!-- Tell IE to use the latest, best version. -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<title>Hello World!</title>
<script src="../Build/Cesium/Cesium.js"></script>
<style>
@import url(../Build/Cesium/Widgets/widgets.css);
html, body, #cesiumContainer {
width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden;
}
</style>
</head>
<body>
<div id="cesiumContainer"></div>
<script>
var viewer = new Cesium.Viewer('cesiumContainer');
</script>
</body>
</html>Si se trata de ejecutar el archivo HTML, no saldrá nada pues no es capaz de encontrar las referencias a los archivos de JavaScript ni la plantilla de estilos CSS. Por ello, se modificarán las líneas 11 y 13 para enlazar los archivos con los servidores de Cesium del siguiente modo:
Línea 11
// <script src="../Build/Cesium/Cesium.js"></script>
<script src="https://cesiumjs.org/Cesium/Build/Cesium/Cesium.js"></script>Línea 13
/* @import url(../Build/Cesium/Widgets/widgets.css); */
@import url(https://cesiumjs.org/Cesium/Build/Cesium/Widgets/widgets.css);Cambiando estas líneas, el visor del mapa ya funciona.
El siguiente paso será configurar un poco el visor, para adaptarlo a lo que se va a necesitar conforme los datos a consumir. Para ello, en el código HTML, dentro de las etiquetas de <script> localizadas en <body>, se modificarán algunas propiedades del "viewer", que es el elemento en el que se representa el mapa.
Entre otras opciones, se van a eliminar los widgets del reloj de abajo a la izquierda ("animation") y la barra temporal de abajo del todo ("timeline"), para facilitar la visualización del mapa; y se va definir como mapa base por defecto el de Open Street Map ("imageryProvider").
Para ello, se modificará el código de como está ahora a como se define a continuación:
Código inicial
<script>
var viewer = new Cesium.Viewer('cesiumContainer');
</script>Código final
<script>
var viewer = new Cesium.Viewer('cesiumContainer', {
// Desactivar el widget de la pelota inferior izquierda.
animation: false,
// OMS como ,apa base por defecto.
imageryProvider : new Cesium.createOpenStreetMapImageryProvider({
url : 'https://a.tile.openstreetmap.org/'
}),
// Desactivar el widget de la barra temporal inferior.
timeline: false,
});
</script>Hecho esto se consigue configurar un poco el visor del mapa. Sin embargo, al ejecutar el visor, la vista inicial se encuentra enfocada en los Estados Unidos de América a nivel planetario, cuando los datos a consumir se encuentran en la isla de Gran Canaria, a nivel de calle. Por tanto, es preciso modificar la extensión inicial así como la escala visual.
Esto se consigue añadiendo a la variable del "viewer" la propiedad de definir vista ("setView") a la cámara ("camera").
Código final
<script>
var viewer = new Cesium.Viewer('cesiumContainer', {
// Desactivar el widget de la pelota inferior izquierda.
animation: false,
// OMS como ,apa base por defecto.
imageryProvider : new Cesium.createOpenStreetMapImageryProvider({
url : 'https://a.tile.openstreetmap.org/'
}),
// Desactivar el widget de la barra temporal inferior.
timeline: false,
});
viewer.camera.setView({
// Coordenadas de Las Palmas de Gran Canaria en longitud y latitud, en grados decimales, y altura en metros.
destination : Cesium.Cartesian3.fromDegrees(-15.4351002359, 28.1285417072, 7000.0)
});
</script>Tras actualizar el código, el visor debería verse de una manera similar a la siguiente imagen:
Una vez que se tiene el mapa preparado, es momento de introducir los datos servidos por la API.
Cesium utiliza, entre otros formatos de datos, el JSON para representar la información en el mapa. El servicio Rest configurado previamente se ha configurado con un procesado para ofrecer la información de los árboles de tal forma que Cesium lo acepte sin problemas. Sin embargo, Cesium requiere una URL de un archivo .json para poder introducir la información en el mapa, mientras que la API generaba un enlace con un encabezado con el "token", algo que Cesium no acepta como enlace.
Por ello, para pasar el "token" de autentificación al API Rest es preciso introducir un poco más de código. Para empezar, se cargará la biblioteca de jQuery en el <head>
Código básico de Cesium
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>Seguidamente, en el <body>, se añadirá la siguiente llamada de ajax, tras la configuración de la extensión de cámara inicial:
Código de ajax
jQuery.ajax({
// URL al servicio Rest.
url : 'http://www.onesaitplatform.online/api-manager/server/api/v1/api_gis_arboles_palmas/getArboles',
// Encabezado con la token de acceso al API.
headers: { "Content-Type":"application/json","Accept": "application/json", "X-OP-APIKey": "token_del_usuario" },
// Tipo de servicio del API.
type : 'GET',
// Contenido que ofrece la API; en este caso es un JSON.
contentType: "application/json",
// En caso de que el token sea válido, se recupera la información.
success : function (data) {
// Se añade el JSON como capa de puntos en el visor.
viewer.dataSources.add(Cesium.GeoJsonDataSource.load(data, {
// Se simbolizan los puntos con arbolitos.
markerSymbol: "park"
}));
},
// En caso de que el token no sea válido, se lanza el error.
error : function (data, errorThrown) {
alert(3);
}
});
Token del usuario
Es importante asignar el token del usuario en la propiedad "X-OP-APIKey". Cambiar "token_del_usuario" por el valor alfanumérico correspondiente al usuario.
Uso de $ y jQuery
Debido a que Cesium suele utilizar "$", es recomendable utilizar "jQuery" en su lugar.
Tras añadir esto último, en el visor se visualizaría ya la capa de puntos con los árboles de la ontología, consumidos desde un servicio Rest. Pulsando en alguno de los árboles, se accedería a la tabla de atributos, donde se vería su campo de identificación único "oid" y el de su salud "estado".
Código completo del visor:
Código básico de Cesium
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Use correct character set. -->
<meta charset="utf-8">
<!-- Tell IE to use the latest, best version. -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<title>Visor de árboles de Las Palmas</title>
<script src="https://cesiumjs.org/Cesium/Build/Cesium/Cesium.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<style>
@import url(https://cesiumjs.org/Cesium/Build/Cesium/Widgets/widgets.css);
html, body, #cesiumContainer {
width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden;
}
</style>
</head>
<body>
<div id="cesiumContainer"></div>
<script>
var viewer = new Cesium.Viewer('cesiumContainer', {
// Desactivar el widget de la pelota inferior izquierda.
animation: false,
// OMS como mapa base por defecto.
imageryProvider : new Cesium.createOpenStreetMapImageryProvider({
url : 'https://a.tile.openstreetmap.org/'
}),
// Desactivar el widget de la barra temporal inferior.
timeline: false,
});
viewer.camera.setView({
// Coordenadas de Las Palmas de Gran Canaria en longitud, latitud y altura.
destination : Cesium.Cartesian3.fromDegrees(-15.4351002359, 28.1285417072, 8000.0)
});
jQuery.ajax({
// URL al servicio Rest.
url : 'http://www.onesaitplatform.online/api-manager/server/api/v1/api_gis_arboles_palmas/getArboles',
// Encabezado con la token de acceso al API.
headers: { "Content-Type":"application/json","Accept": "application/json", "X-OP-APIKey": "token_del_usuario" },
// Tipo de servicio del API.
type : 'GET',
// Contenido que ofrece la API; en este caso es un JSON.
contentType: "application/json",
// En caso de que el token sea válido, se recupera la información.
success : function (data) {
// Se añade el JSON como capa de puntos en el visor.
viewer.dataSources.add(Cesium.GeoJsonDataSource.load(data, {
// Se simbolizan los puntos con arbolitos.
markerSymbol: "park"
}));
},
// En caso de que el token no sea válido, se lanza el error.
error : function (data, errorThrown) {
alert(3);
}
});
</script>
</body>
</html>