¿Cómo conectar un visor GIS con gadgets en un Dashboard?
- 1 Introducción
- 2 Generación de la Ontología
- 3 Carga de datos de la Ontología
- 4 Creación de la Capa espacial del visor
- 5 Creación del Visor web
- 6 Creación del DataSource
- 7 Creación del Dashboard
- 8 Creación del Gadget del diagrama de barras
- 9 Creación del Gadget del Visor web
- 10 Configuración del Visor web
- 10.1 Código del Visor
- 10.1.1 sendFilter()
- 10.2 ¿Qué hace la función?
- 10.3 Comprobación de parámetros del Visor
- 10.4 Descarga el código fuente del Visor
- 10.4.1 viewerCode.js
- 10.1 Código del Visor
- 11 Conexión entre gadgets
- 12 Estilismo
Introducción
En este tutorial se va a explicar cómo conectar un visor GIS generado en la plataforma con otro Gadget para que interactúen entre ellos en un Dashboard.
Concretamente, se va a crear un mapa a partir de una Ontología con datos de la población y densidad de población de las diferentes Comunidades Autónomas de España, y un Gadget de diagrama de barras que muestra la distribución de la población a nivel nacional, y a nivel de comunidad cuando en el mapa se pinche sobre una de las comunidades.
Como una imagen vale más que sesenta palabras, a continuación se muestra el resultado que se obtendrá.
Generación de la Ontología
Se empezará generando la Ontología de datos que contendrá la localización de los centroides de cada Comunidad Autónoma, así como los datos de población y densidad de población. Para este tutorial, se utilizarán los siguientes contenidos en el siguiente JSON: (GIS) Cómo conectar un visor GIS con gadgets en un Dashboard
Generación de la ontología
Si ya sabes cómo generar una ontología, puedes saltarte lo que viene a continuación y generarla por tu cuenta.
Para generar la ontología, en primer lugar habrá que navegar hasta el menú de Desarrollo, y selección la opción de Mis Ontologías.
Aparecerá una pantalla con todas las ontologías que se tengan disponibles. Para generar una nueva, se pulsará en el botón de Crear, situado en la parte superior derecha de la pantalla.
Con esto se lanzará el asistente de generación de ontologías, en donde se pregunta qué método de creación se quiere utilizar. Para este tutorial, se seleccionará la opción de Creación paso a paso.
La siguiente pantalla corresponde con el formulario de creación de la Ontología, en donde se deberán introducir la siguiente información:
Nombre de la ontología: nombre único de identificación de la ontología.
Meta-información: etiquetas que identifiquen a la ontología que se está creando.
Descripción: un pequeño texto que explique la ontología.
Activo: si la ontología se encuentra activa o no. Por defecto está en activa, y hay que dejarla así.
Pública: para permitir que la ontología sea accesible o no. Por defecto está desactivada, y hay que activar la opción.
Permitir la encriptación de campos: esta casilla se dejará como está, desactivada.
Tras introducir la información básica de la ontología, a continuación se seleccionará la plantilla de la Ontología. De entre las disponibles, se seleccionará la categoría de General, subcategoría de Plantilla Vacía.
Seleccionando esta plantilla, aparece el diseñador de esquemas, en donde se definirán los distintos campos con los que contará la Ontología.
Los campos a introducir serán los siguientes:
Propiedad | Tipo de dato | Requerido | Encriptado |
|---|---|---|---|
id | integer | Required | false |
ccaa_name | string | Required | false |
ccaa_name_alt | string | Required | false |
ccaa_pob_2018 | number | Required | false |
ccaa_den_2018 | number | Required | false |
geometry | geometry | Required | false |
Los datos introducidos deberían quedar por tanto tal como se muestra a continuación:
Hecho esto, se pulsará sobre el botón de Actualizar Esquema. La pantalla se desplazará automáticamente a un visor de código, en donde se podrá ver la estructura generada para la Ontología. Pulsando sobre el botón de Generar Instancia, se podrá ver un ejemplo de la estructura de la ontología con valores ficticios.
Si se está conforme con lo obtenido, se pulsará en el botón de Nuevo para generar la Ontología.
Carga de datos de la Ontología
Tras haber generado la Ontología, el siguiente paso consistirá en poblarla con datos.
Cargar datos en la ontología
Como en el apartado anterior, si ya sabes cómo cargar datos en una ontología, puedes saltarte este paso y hacerlo por tu cuenta.
Se empezará buscando la ontología recién creada en el listado de ontologías, el cual se encuentra en la pantalla inicial de Mis Ontologías.
Una vez que se haya localizado, se pulsará sobre el botón de CRUD, situado a la derecha del todo del registro de la Ontología.
Esto lanzará el asistente de Crear, Leer, Actualizar y Borrar (Create, Read, Update and Delete, CRUD) de la Ontología, lo que permitirá modificar su contenido, y particularmente en este caso, introducir los datos a la misma. Para ello, se pulsará en el botón Nuevo por cada registro que se quiera introducir.
En la pantalla que aparece se tendrá que ir introduciendo la información correspondiente a los diferentes campos definidos previamente en la estructura de la Ontología.
Esto se puede ir haciendo campo a campo, o copiando la estructura de cada elemento del JSON original en la ventana de Output.
Una vez introducidos los datos del primer elemento, se pulsará sobre el botón de Nuevo para generar el dato, quedando registrado en el listado de contenidos de la Ontología.
Esto habrá que repetirse con los diecinueve registros con los que se cuenta en total.
Una vez terminado de cargar los datos, la Ontología estará lista para su consumo.
Creación de la Capa espacial del visor
Una vez que se tiene la Ontología preparada, se procederá a crear a partir de ella una Capa Espacial, la cual se visualizará en el visor del mapa.
Para ello, se navegará hasta el menú de Visores Webmap, y se seleccionará la opción de Mis Capas.
Una vez en el gestor de capas, se pulsará sobre el botón de Crear para generar una nueva Capa.
Al igual que ocurría con las ontologías, se abrirá un asistente de generación, en donde se escogerá la opción de Crear Capa de Ontología.
Esto lanzará el generador de nueva Capa, en donde se tendrá que introducir en un primer lugar la siguiente información:
Identificación: nombre único de identificación de la capa de la ontología.
Ontología: la ontología a partir de la cual se crea la capa.
Pública: para permitir que la capa sea accesible o no. Por defecto está desactivada, y hay que activar la opción.
Descripción: un pequeño texto que explique la capa.
Una vez introducida la información básica de la Capa, habrá que definir tres propiedades más: geometría, simbología y el Info Box.
En la geometría se indicará el campo de la ontología con las coordenadas espaciales, así como indicar el tipo de geometría de la capa. Respecto a la opción de mapa de calor, se dejará desactivada.
Generar un mapa de calor (heatmap) en Cesium
¿Cómo? ¿Mapas de calor? Pues si, puedes generar mapas de calor con los datos de tus ontologías. ¿Interesado? Pues tenemos un tutorial que explica muy bien cómo crearlos.
Respecto a la simbología, en esta pestaña se indicará el aspecto que tendrán los puntos gráficos de la Capa. De momento la representación se hace mediante puntos de colores, los cuales se configuran con cuatro propiedades:
Color de línea exterior.
Color interior.
Grosor de la línea exterior.
Tamaño del punto.
Por último queda la pestaña de Info Box. Un infoBox o Popup es la ventanita que sale cuando en el mapa se pincha sobre uno de los elementos de la ontología, mostrando cierta información. En este caso en particular, se usarán los campos seleccionados para el infoBox como los campos a utilizar en los filtros del Gadget del Dashboard.
Introducir campos es tan sencillo como pulsar en el botón de Añadir Atributos, e ir seleccionando el campo que se quiere añadir, y el nombre que se quiere que tenga.
Para este ejemplo, se introducirán los campos de:
ccaa_name
ccaa_name_alt
ccaa_pob_2018
ccaa_den_2018
Para evitar complicaciones, el nombre a asignar será el mismo que el del campo.
Una vez seleccionados los campos a introducir, se pulsará en el botón de Nuevo para crear la Capa.
Visualización de la capa
Si quieres echar un ojo rápido a tu capa para ver cómo es, desde el gestor de capas, busca la capa que acabas de crear y pulsando en el botón de CRUD podrás visualizar los datos con sus coordenadas en una tabla, y en la parte de abajo un mapa con los datos representados.
De todos modos en el siguiente punto se va a generar un visor web donde se meterá la capa que se acaba de crear. Esta sugerencia sirve también para dar a conocer la opción de visualización de datos sin requerir de un visor web.
Creación del Visor web
Ya se tiene la Capa. Ahora se va a generar un Visor web en donde visualizarla.
Nuevamente hay que ir hasta el menú de Visores Webmap, pero seleccionar esta vez la opción de Mis Visores.
Como en casos anteriores, se pulsará en el botón de Crear, para lanzar el asistente de creación del Visor web.
En el asistente que aparece, será necesario rellenar los siguientes campos:
Identificación: nombre único de identificación del visor web.
Pública: para permitir que el visor sea accesible o no. Por defecto está desactivada, y hay que activar la opción.
Descripción: un pequeño texto que explique el visor.
Tecnología: del tipo de visor a utilizar. De momento sólo se puede escoger la opción de Cesium.
Mapa base: corresponde al 'lienzo' que aparece de fondo en el mapa. Se puede escoger entre una imagen de ciudad vectorial, o imagen de satélite (imagery).
Capas: la capa o capas a visualizar en el mapa.
Una vez completados los campos, y más concretamente escogido el mapa base, aparecerá una ventana partida en la parte inferior, donde a la derecha se tendrá el Visor web, y a la izquierda el código fuente del Visor.
Más adelante en este tutorial habrá que volver al Visor y modificar el código del mismo para incluir ciertos elementos, pero de momento con esto ya se tiene listo el Visor web que será metido posteriormente en el Dashboard.
Creación del DataSource
A la hora de trabajar con los gadgets, es necesario generar un DataSource de la Ontología.
Para ello, se navegará en el menú de Visualización hasta Mis DataSources.
Se abrirá la página de gestión de dataSources, en donde habrá que pulsar en el botón de Crear situado en la parte superior derecha para lanzar el formulario de creación de DataSources.
En dicho formulario habrá que rellenar los siguientes campos:
Identificación: nombre único de identificación del DataSource.
Modo de acceso: que por defecto y única opción será 'Query'.
Fuente de base de datos: que por defecto y única opción será 'RTDB'.
Tiempo de refresco: por defecto es '0', y que puede dejarse como está.
Seleccionar ontología: aquí se seleccionará la ontología a partir de la cual se quiere crear el DataSource.
Descripción: un pequeño texto que explique el DataSource.
Seguidamente hay que configurar la llamada a la base de datos. Por defecto se genera la siguiente llamada:
Sin embargo, esta llamada no sirve para lo que se busca hacer, puesto que el uso del asterisco genera ciertos problemas. Por ello, es necesario modificar dicha llamada manualmente para pasarle todos los parámetros que interesan. Dicha llamada seguiría el siguiente patrón:
select nombreOntologia.nombreOntologia.PROPIEDAD as PROPIEDAD from nombreOntologia
En el caso del ejemplo, dicha llamada sería:
Llamada a la base de datos
select ont_ccaa_population_2018.ont_ccaa_population_2018.id as id, ont_ccaa_population_2018.ont_ccaa_population_2018.name as name, ont_ccaa_population_2018.ont_ccaa_population_2018.ccaa_name as ccaa_name, ont_ccaa_population_2018.ont_ccaa_population_2018.ccaa_name_alt as ccaa_name_alt, ont_ccaa_population_2018.ont_ccaa_population_2018.ccaa_pob_2018 as ccaa_pob_2018, ont_ccaa_population_2018.ont_ccaa_population_2018.ccaa_den_2018 as ccaa_den_2018 from ont_ccaa_population_2018Pulsando en el botón de Ejecutar Solicitud, aparecería la respuesta de la llamada, en la que se puede ver el JSON con cada una de las Comunidades Autónomas junto a sus datos asociados.
Si se está conforme con el resultado obtenido, pulsando en el botón de Nuevo se generará el DataSource, dando por finalizado este apartado.
Creación del Dashboard
Generado el DataSource de la Ontología, ya es posible crear los gadgets asociados a dicho DataSource. Sin embargo, antes de generar dichos gadgets, se procederá a crear el Dashboard que los contendrá.
Para crear el Dashboard se navegará en el menú de Visualización hasta la opción de Mis Dashboards.
Como en casos anteriores, se accederá al gestor de contenidos, correspondiente en este caso a los dashboards. Allí habrá que pulsar en el botón de Crear para lanzar el formulario de creación de dashboards.
En dicho formulario, habrá que introducir la siguiente información:
Identificación: nombre único de identificación del Dashboard.
Descripción: un pequeño texto que explique el Dashboard.
Pública: para permitir que el visor sea accesible o no. Por defecto está desactivada, y hay que activar la opción.
Estilo inicial: por defecto sale la opción de estilo por defecto, y se dejará como está.
Imagen: imagen para reconocer el Dashboard. Se puede seleccionar una imagen si se quiere, pero no es necesario hacerlo.
Categoría: para categorizar el Dashboard. No será necesario escoger ninguna opción si no se quiere.
Subcategoría: para categorizar aun más el Dashboard. Tampoco será necesario escoger ninguna opción si no se quiere.
Una vez que se haya introducido toda la información, se pulsará sobre el botón de Nuevo para generar el Dashboard, lo que lo abrirá automáticamente, mostrándolo vacío y listo para rellenar con los gadgets.
Creación del Gadget del diagrama de barras
Ya se tiene el Dashboard generado, por lo que el siguiente paso será crear los dos gadgets que contendrá. Se empezará con el Gadget del diagrama de barras, y posteriormente se hará el del mapa.
Se puede generar el Gadget de diferentes maneras. En este ejemplo, y puesto que ya se tiene el Dashboard generado, se creará desde ahí. Para ello, en el Dashboard, habrá que pulsar sobre el botón de Añadir Elemento, situado en la parte superior derecha del Dashboard.
Esto abrirá en la parte inferior de la pantalla un carrusel de gadgets, en donde se seleccionará el de diagramas de barras y se arrastrará al Dashboard:
Seguidamente aparecerá una pantalla preguntando si se quiere cargar un Gadget ya existente, o si se desea generar uno nuevo.
En este caso, se seleccionará la opción de Nuevo Gadget, lo que lanzará el asistente de creación, en donde habrá que introducir inicialmente dos datos:
Nombre del Gadget: nombre único de identificación del Gadget.
Seleccionar la Ontología o DataSource: donde se seleccionará el DataSource antes generado a partir de la Ontología.
Una vez introducidos estos dos datos, el contenido del asistente se actualizará apareciendo una gran variedad de opciones de personalización del diagrama, entre las cuales se encuentra los campos a mostrar en el diagrama, con un ejemplo en vivo de los cambios realizados en la parte inferior del asistente.
La configuración utilizada para este ejemplo es la siguiente:
Una vez que se ha definido la estética y contenidos del diagrama, se pulsará el botón de Nuevo para generar el Gadget. Éste entonces aparecerá sobre el Dashboard, en donde se podrá modificar su tamaño y posición.
Hecho esto, el Gadget está listo. Más adelante se verá la personalización del Gadget, pero de momento se dejará así. Se salvará el Dashboard para no perder el trabajo hecho hasta ahora.
Creación del Gadget del Visor web
Para meter el Visor web antes creado, no se puede meter directamente en el Dashboard, sino que hay que meterlo a través de un Gadget. Por ello, se repetirá el paso anterior para crear un nuevo Gadget, pero seleccionando en este caso el de Plantilla y arrastrándolo hasta el Dashboard.
Como en el caso del Gadget anterior, saldrá una pantalla preguntando si se quiere usar una plantilla para generar el Gadget. Puesto que se quiere meter un Visor que se tiene generado en la Plataforma, se seleccionará la opción de URLGADGET.
Esto hará que se actualice la ventana, solicitando dos parámetros:
DataSource: a partir del cual funcionará el Gadget, que en este caso será el mismo utilizado para el otro Gadget.
URL: donde se tendrá que introducir la URL del Visor web que previamente se ha generado.
Recuperar la URL del Visor web
¿No sabes cual es la URL del Visor web que se ha generado antes? Entra en el menú de Visores Webmap, y selecciona la opción de Mis Visores. En el listado de visores, busca el que hayas creado, y pulsa sobre el botón de URL.
Una vez introducidos los datos, el Gadget estará listo y aparecerá sobre el Dashboard, pudiendo modificar como en el caso anterior su posición y tamaño.
Hecho esto, el Gadget está listo. Sin embargo, pinchando sobre cualquiera de los puntos del mapa, no ocurre nada. Cómo conseguir esto se tratará en el siguiente apartado.
Antes de continuar, se guardarán los cambios realizados en el Dashboard.
Configuración del Visor web
Como se comentó previamente, se va a regresar al Visor web antes generado, para modificar su código y prepararlo para que pueda interactuar con los gadgets del Dashboard. Se navegará nuevamente hasta el gestor de visores.
Allí, se buscará el Visor que se ha generado y se seleccionará la opción de Editar.
Esto abrirá una pantalla que nos permitirá modificar el contenido del mapa. Aunque para este ejemplo se va a modificar el código para hacerlo compatible con el Dashboard, se podría modificar también parámetros básicos del mapa, como las capas que contenga, el mapa base, etc.
Código del Visor
Si en algún momento te pierdes con lo que se va a hacer, no te preocupes porque al final de esta sección se incluye el código del visor ya preparado.
En el código del Visor, se navegará hasta la parte inferior del mismo, justo antes del comentario de /** EJECUCIONES */, y se incluirá la siguiente función de JavaScript:
sendFilter()
function sendFilter() {
let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
handler.setInputAction(function() {
let entity
if (viewer.selectedEntity && viewer.selectedEntity.id != 'Loading...') {
entity = viewer.selectedEntity
parent.parent.postMessage({'eventMap':entity.ccaa_name},'*')
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}Introducido el código donde se indica, quedaría tal que así:
¿Qué hace la función?
Esta función lo que hace es generar un evento (línea 2) que escucha en el mapa cuando se hace clic (línea 3) sobre una entidad (línea 5; en este caso, en los puntos de las Comunidades Autónomas), y que emitirá un mensaje al iFrame del Dashboard desde el iFrame del Gadget (línea 7). El mensaje que se lanza será el nombre de la Comunidad Autónoma sobre la que se ha hecho clic; es decir, el campo 'ccaa_name' de la entidad seleccionada en el Visor.
Por último, no hay que olvidarse de incluir la ejecución de la función recién creada, lo que se hará bajo el comentario de /** EJECUCIONES */, por mantener un orden.
Por otro lado, es preciso de momento introducir manualmente ciertos campos de datos a las entidades que se van a crear. Hay que buscar la función de CreateLayer(), concretamente donde se especifica dataSource.entities.add, hay que incluir las siguientes propiedades:
ccaa_name: entity.properties.ccaa_name
ccaa_name_alt: entity.properties.ccaa_name_alt
ccaa_pob_2018: entity.properties.ccaa_pob_2018
ccaa_den_2018: entity.properties.ccaa_den_2018
Hecho esto, no habría que modificar nada más en el código del Visor, por lo que se pueden salvar los cambios pulsando en el botón de Editar.
Comprobación de parámetros del Visor
Como generar el Visor conlleva configurar muchas opciones, para asegurar la visualización correcta en el Gadget, hay que comprobar que:
Si existe una propiedad llamada infoBox en el código, ésta se encuentra en 'false'. En caso de no existir, en la definición del viewer, hay que añadir la propiedad de 'infoBox: false,' (el parámetro debe escribirse tal como se especifica).
Que las coordenadas del mapa correspondan con la localización de la capa. Aunque esto debería ser automático, es posible que por alguna razón no sea así, por lo que hay que modificar las coordenadas de inicio del mapa. Esto se puede configurar modificando los parámetros de las variables initialLongitude, initialLatitude e initialHeight.
Descarga el código fuente del Visor
Puedes descargarte el código del visor a continuación:
viewerCode.js
$(document).ready(function() {
if (viewer != undefined) {
var options = []
$.each(dataSourceLayers, function(k, v) {
options.push("<option value='" + v + "'>" + v + '</option>')
})
$('#layers').html(options)
$('#layers').selectpicker('refresh')
$('#layers').val(dataSourceLayers)
$('#layers').selectpicker('refresh')
}
})
var dataSourceLayers = []
$('#layers').on('change', function() {
var datasources = dataSourceLayers
var imageryLayers = viewer.imageryLayers._layers
var dataSourcesViewer = viewer.dataSources._dataSources
var layersSelected = $('#layers').val()
var options = []
var layers = []
$.each(datasources, function(k, v) {
var layer = v
var dataSourceLayer = 'dataSource' + v
if (layersSelected.includes(layer)) {
options.push("<option value='" + layer + "'>" + layer + '</option>')
layers.push(layer)
$.each(dataSourcesViewer, function(index, value) {
if (
value.name.name == 'dataSource' + layer ||
value.name == 'dataSource' + layer
) {
value.show = true
}
})
$.each(imageryLayers, function(index, value) {
if (value.imageryProvider.name == 'dataSource' + layer) {
value.show = true
}
})
$.each(heatMapLayers, function(index, value) {
if (value.layer == layer) {
value.heatMap._layer.show = true
}
})
} else {
$.each(dataSourcesViewer, function(index, value) {
if (
value.name.name == 'dataSource' + layer ||
value.name == 'dataSource' + layer
) {
value.show = false
}
})
$.each(imageryLayers, function(index, value) {
if (value.imageryProvider.name == 'dataSource' + layer) {
value.show = false
}
})
$.each(heatMapLayers, function(index, value) {
if (value.layer == layer) {
value.heatMap._layer.show = false
}
})
}
})
$('#layers').val(layers)
$('#layers').selectpicker('refresh')
})
/** Variables con la extensión inicial del mapa y su altura/zoom */
var initialLongitude = -4.0
var initialLatitude = 40.0
var initialHeight = 2200000
/** Tokens para servicios de mapa base */
var accessTokenMapbox = ''
/** VISOR */
/** Se define el visor del mapa, junto a sus propiedades */
var viewer = new Cesium.Viewer('mapViewer', {
/** Desactiva el widget de la pelota inferior izquierda */
animation: false,
/** Botón de inicio */
homeButton: false,
/** Widget del selector de mapas base */
baseLayerPicker: false,
/** Botón de pantalla compvara */
fullscreenButton: false,
/** Cajetín del geocodificador */
geocoder: false,
/** Cajetín del infoBox */
infoBox: false,
/** Botón de ayuda a la navegación */
navigationHelpButton: false,
/** Botón de selección de modos 2D/2,5D/3D */
sceneModePicker: false,
/** Widget de la barra temporal inferior */
timeline: false,
/** Se fuerza el modo en 3D exclusivo */
sceneMode: Cesium.SceneMode.SCENE3D,
/** Recuadro verde que sale al seleccionar entidades */
selectionIndicator: false
})
/** Se elimina el mapa base por defecto, y el color azul del fondo */
viewer.scene.highDynamicRange = false
viewer.scene.imageryLayers.removeAll()
viewer.scene.globe.baseColor = Cesium.Color.WHITE
/** VARIABLES */
var dataSourceCollection = new Cesium.DataSourceCollection()
var baseMapsLayers = viewer.imageryLayers
var baseMap = null
/** FUNCIONES */
/** Función que calcula la altura a la que se encuentra la cámara del usuario */
function userCameraHeight() {
/** Se define la posición de la cámara del usuario */
let cameraPosition = viewer.scene.camera.positionWC
/** Se define el elipsoide tridimensional respecto a la posición de cámara */
let ellipsoid = viewer.scene.globe.ellipsoid.scaleToGeodeticSurface(
cameraPosition
)
/** Se define la altura de la cámara a partir del elipsoide */
let height = Cesium.Cartesian3.magnitude(
Cesium.Cartesian3.subtract(
cameraPosition,
ellipsoid,
new Cesium.Cartesian3()
)
)
/** La función devuelve la altura de la cámara */
return height
}
/** Función que aumenta el zoom */
function zoomIn() {
/** Se define una variable con la distancia */
let height = userCameraHeight()
/** Altitud mínima a partir de la que no se acerca más */
if (height <= 501) {
} else {
/** El zoom se acerca */
viewer.camera.zoomIn(500.0)
}
}
/** Función que disminuye el zoom */
function zoomOut() {
/** Se define una variable con la distancia */
userCameraHeight()
/** El zoom se aleja */
viewer.camera.zoomOut(500.0)
}
/** Función que atiende a la selección de entidades y escucha clicks */
function entityInteractuation() {
/** Se define una variable que tendrá el elemento seleccionado */
let selectedEntity
/** Otra variable con la posición dinámica del punto al moverse */
let newPosition
/** Una variable que controla cuando nos estamos moviendo */
let onMove = false
/** Se genera un controlador de eventos del visor */
let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
/** Esto se ejecutará cuando se haga click con el botón izquierdo */
handler.setInputAction(function(event) {
/** Si no nos estamos moviendo; es decir, seleccionamos una entidad... */
if (!onMove) {
/** Nos aseguramos de que existe una entidad seleccionada */
if (viewer._selectedEntity) {
/** Se mete la entidad seleccionad en la variable */
selectedEntity = viewer._selectedEntity
/** Se pasa a desplazamiento */
onMove = true
}
} else {
/** ... o si ya está seleccionada una entidad que movemos, entonces... */
/** Se recoge la posición del canvas sobre la que se pincha */
let canvasPosition = new Cesium.Cartesian2(
event.position.x,
event.position.y
)
/** Se define el elipsoide del mapa */
let ellipsoid = viewer.scene.globe.ellipsoid
/** Se transforman las coordenadas del canvas al elipsoide */
let cartesian = viewer.camera.pickEllipsoid(canvasPosition, ellipsoid)
/** Se definen las coordenadas de la entidad donde se ha pinchado */
selectedEntity.position.setValue(cartesian)
let id = selectedEntity.id
/** Se elimina la entidad seleccionada, para volver a empezar */
selectedEntity = undefined
/** Se llama a la función updateAttribute, dándo la posibilidad de editar los campos*/
let cartographic = ellipsoid.cartesianToCartographic(cartesian)
let longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(4)
let latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(4)
editAttribute(null, id, longitude, latitude)
/** Se pasa a estático */
onMove = false
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
/** Esto se ejecutará cuando se desplaze el cursor del ratón */
handler.setInputAction(function(event) {
/** Se comprueba si la entidad seleccionada es correcta */
if (Cesium.defined(selectedEntity)) {
/** Se define una nueva posición según donde esté el ratón */
newPosition = viewer.camera.pickEllipsoid(event.endPosition)
/** Se comprueba si este nuevo punto es válido */
if (Cesium.defined(newPosition)) {
/** Se reasignan valores de coordenadas de la entidad seleccionada*/
selectedEntity.position.setValue(newPosition)
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
/** Esto se ejecutará cuando se haga click con el botón izquierdo + CONTROL */
handler.setInputAction(
function(click) {
/** Se define una variable que almacene lo que se pinche */
let editSelectedEntity = viewer.scene.pick(click.position)
/** Si se pincha en una entidad */
if (Cesium.defined(editSelectedEntity)) {
console.log(editSelectedEntity.primitive)
/**
* AQUÍ ES DONDE PUEDES METER TU CÓDIGO. LA ENTIDAD SELECCIONADA ES
* 'editSelectedEntity', LA CUAL TIENE LA INFORMACIÓN QUE NECESITAS
* EN LA PROPIEDAD 'primitive'. EL IDENTIFICADOR DE LA ENTIDAD SERÁ
* 'editSelectedEntity.primitive.id'.
*
* SI PREFIERES QUE SEA CON EL BOTÓN DERECHO EN VEZ DE CON CONTROL +
* BOTÓN IZQUIERDO, CAMBIA TODA LA LÍNEA DE ABAJO DEL TODO A:
* 'Cesium.ScreenSpaceEventType.RIGHT_CLICK'
*/
}
},
Cesium.ScreenSpaceEventType.LEFT_CLICK,
Cesium.KeyboardEventModifier.CTRL
)
}
/** Función que pinta puntos al hacer click en el visor del mapa */
function drawPointClick() {
/** Variable con la URL de la imagen */
let imagePoint =
'http://localhost:18000/controlpanel/static/images/viewerIcons/point.png'
/** El ratón cambia de puntero, para indicar que se puede poner un punto */
document.body.style.cursor = 'copy'
/** Se define una variable que escuchará los eventos de canvas */
let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
/** Se producirá este evento cuando se pinche en el visor */
handler.setInputAction(function(event) {
/** Se recoge la posición del canvas sobre la que se pincha */
let canvasPosition = new Cesium.Cartesian2(
event.position.x,
event.position.y
)
/** Se define el elipsoide del mapa */
let ellipsoid = viewer.scene.globe.ellipsoid
/** Se transforman las coordenadas del canvas al elipsoide */
let cartesian = viewer.camera.pickEllipsoid(canvasPosition, ellipsoid)
/** Se transforman las coordenadas cartesianas a cartográficas */
let cartographic = ellipsoid.cartesianToCartographic(cartesian)
let longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(4)
let latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(4)
/** Se añade un punto en el sitio donde se pincha */
var id = viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
billboard: {
image: imagePoint,
scale: 1.0
}
}).id
/** Se destruye la variable que escucha, para que pinte un único punto */
handler.destroy()
/** El ratón regresa al puntero básico */
document.body.style.cursor = 'auto'
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
/** Se producirá este evento cuando se pinche con el botón derecho */
handler.setInputAction(function(event) {
/** Se destruye la variable que escucha, para cancelar el evento */
handler.destroy()
/** El ratón regresa al puntero básico */
document.body.style.cursor = 'auto'
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
/** Función que pinta una línea al hacer click en el visor del mapa */
function drawLineClick() {
/** Se definen las variables a utilizar */
let colorPoint = Cesium.Color.PINK.withAlpha(0.6)
let colorPolyline = Cesium.Color.BLUE.withAlpha(0.6)
let entityCollection = new Cesium.EntityCollection()
let activeShapePoints = []
let activeShape
let floatingPoint
let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
/** El ratón cambia de puntero, para indicar que se puede poner un punto */
document.body.style.cursor = 'copy'
/** Función que genera la entidad de punto */
function createPoint(pointCoordinates) {
let point = viewer.entities.add({
name: 'temporalPoint',
position: pointCoordinates,
point: {
color: colorPoint,
pixelSize: 6
}
})
/** Se añade el punto a la colección de puntos, para controlarlo */
entityCollection.add(point)
/** Se devuelve el punto, para almacenarlo como punto temporal */
return point
}
/** Función que dibuja la polilínea */
function drawShapePolyline(positionData) {
/** Se define una variable con la forma de la entidad */
let shape
/** Se genera la entidad de la polilínea */
shape = viewer.entities.add({
polyline: {
positions: positionData,
material: colorPolyline,
width: 3
}
})
/** Se devuelve la polilínea */
return shape
}
/** Función que genera la polilínea definitiva, eliminando los temporales */
function generateFinalPolyline() {
activeShapePoints.pop()
var id = drawShapePolyline(activeShapePoints).id
/** Se eliminan las entidades generadas y se vacían las variables */
viewer.entities.remove(floatingPoint)
viewer.entities.remove(activeShape)
floatingPoint = undefined
activeShape = undefined
activeShapePoints = []
/** Se itera por la colección de puntos guía, y se eliminan */
for (entity of entityCollection.values) {
viewer.entities.remove(entity)
}
/** Se destruye la variable que escucha, para que pinte un único punto */
handler.destroy()
/** El ratón regresa al puntero básico */
document.body.style.cursor = 'auto'
}
/** Se producirá este evento cuando se pinche en el visor */
handler.setInputAction(function(event) {
/** Se extraen las coordenadas de donde se pincha con el ratón */
let position = viewer.camera.pickEllipsoid(event.position)
/** Se comprueba que donde se pincha está en el mapa */
if (Cesium.defined(position)) {
/** Se mira si se han definido puntos activos previamente */
if (activeShapePoints.length === 0) {
/** Con cada click, se genera un punto en el mapa */
floatingPoint = createPoint(position)
/** Se mete en el listado la posición del punto generado */
activeShapePoints.push(position)
/** Se define las posiciones hasta el momento */
let dynamicPositions = new Cesium.CallbackProperty(function() {
return activeShapePoints
}, false)
/** Se va pintando un polígono temporal con los puntos temporales */
activeShape = drawShapePolyline(dynamicPositions)
}
/** Se van añadiendo al listado las posiciones de los puntos generados */
activeShapePoints.push(position)
/** Y se van creando puntos */
createPoint(position)
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
/** Se producirá este evento cuando se mueva el cursor por el visor */
handler.setInputAction(function(event) {
/** Se comprueba si el punto flotante es correcto */
if (Cesium.defined(floatingPoint)) {
/** Se define una nueva posición (siguinte punto) */
let newPosition = viewer.camera.pickEllipsoid(event.endPosition)
/** Se comprueba si este nuevo punto es válido */
if (Cesium.defined(newPosition)) {
/** Se reasignan valores */
floatingPoint.position.setValue(newPosition)
activeShapePoints.pop()
activeShapePoints.push(newPosition)
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
/** Cuando el usuario quiera terminar, tocará el botón derecho */
handler.setInputAction(function(event) {
/** Se genera la polilínea definitiva */
generateFinalPolyline()
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
/** Función que pinta un polígono al hacer click en el visor del mapa */
function drawPolygonClick() {
/** Se definen las variables a utilizar */
let colorPoint = Cesium.Color.PINK.withAlpha(0.6)
let colorPolygon = Cesium.Color.RED.withAlpha(0.6)
let entityCollection = new Cesium.EntityCollection()
let activeShapePoints = []
let activeShape
let floatingPoint
let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
/** El ratón cambia de puntero, para indicar que se puede poner un punto */
document.body.style.cursor = 'copy'
/** Función que generará los puntos guía del polígono */
function createPoint(pointCoordinates) {
/** Se genera la entidad de punto */
let point = viewer.entities.add({
name: 'temporalPoint',
position: pointCoordinates,
point: {
color: colorPoint,
pixelSize: 6
}
})
/** Se añade el punto a la colección de entidades, para controlarlo */
entityCollection.add(point)
/** Se devuelve el punto, para almacenarlo como punto temporal */
return point
}
/** Función que dibuja el polígono */
function drawShapePolygon(positionData) {
/** Se define una variable con la forma de la entidad */
let shape
/** Se genera la entidad del polígono */
shape = viewer.entities.add({
polygon: {
hierarchy: positionData,
material: new Cesium.ColorMaterialProperty(colorPolygon)
}
})
/** Se devuelve la forma del polígono */
return shape
}
/** Función que genera el polígono definitivo, eliminando los temporales */
function generateFinalPolygon() {
activeShapePoints.pop()
drawShapePolygon(activeShapePoints)
/** Se eliminan las entidades generadas y se vacían las variables */
viewer.entities.remove(floatingPoint)
viewer.entities.remove(activeShape)
floatingPoint = undefined
activeShape = undefined
activeShapePoints = []
/** Se itera por la colección de puntos guía, y se eliminan */
for (entity of entityCollection.values) {
viewer.entities.remove(entity)
}
/** Se destruye la variable que escucha */
handler.destroy()
/** El ratón regresa al puntero básico */
document.body.style.cursor = 'auto'
}
/** Se producirá este evento cuando se pinche en el visor */
handler.setInputAction(function(event) {
/** Se extraen las coordenadas de donde se pincha con el ratón */
let position = viewer.camera.pickEllipsoid(event.position)
/** Se comprueba que donde se pincha está en el mapa */
if (Cesium.defined(position)) {
/** Se mira si se han definido puntos activos previamente */
if (activeShapePoints.length === 0) {
/** Con cada click, se genera un punto en el mapa */
floatingPoint = createPoint(position)
/** Se mete en el listado la posición del punto generado */
activeShapePoints.push(position)
/** Se define las posiciones hasta el momento */
let dynamicPositions = new Cesium.CallbackProperty(function() {
return activeShapePoints
}, false)
/** Se va pintando un polígono temporal con los puntos temporales */
activeShape = drawShapePolygon(dynamicPositions)
}
/** Se van añadiendo al listado las posiciones de los puntos generados */
activeShapePoints.push(position)
/** Y se van creando puntos */
createPoint(position)
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
/** Se producirá este evento cuando se mueva el cursor por el visor */
handler.setInputAction(function(event) {
/** Se comprueba si el punto flotante es correcto */
if (Cesium.defined(floatingPoint)) {
/** Se define una nueva posición (siguinte punto) */
let newPosition = viewer.camera.pickEllipsoid(event.endPosition)
/** Se comprueba si este nuevo punto es válido */
if (Cesium.defined(newPosition)) {
/** Se reasignan los valores */
floatingPoint.position.setValue(newPosition)
activeShapePoints.pop()
activeShapePoints.push(newPosition)
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
/** Cuando el usuario quiera terminar, tocará el botón derecho */
handler.setInputAction(function(event) {
/** Se genera la polilínea definitiva */
generateFinalPolygon()
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
/** Función que pinta dibuja polígonos a mano alzada en el visor del mapa */
function drawPolygonFreehand() {
/** Se definen las variables a utilizar */
let colorPolygon = Cesium.Color.fromCssColorString('#FF0000').withAlpha(0.6)
let drawing = false
let polyline
let positions = []
let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
/** El ratón cambia de puntero, para indicar que se puede poner un punto */
document.body.style.cursor = 'copy'
/** Se producirá este evento cuando se pinche en el visor */
handler.setInputAction(function(click) {
/** En caso de que no exista ningún polígono (primer uso) */
if (!drawing) {
/** Se define la polilínea siguiendo al puntero del ratón */
polyline = viewer.entities.add({
polyline: {
positions: new Cesium.CallbackProperty(function() {
return positions
}, false),
material: colorPolygon
}
})
/** Cuando se haya pintado el polígono que interesa */
} else {
/** Se define el polígono a partir de la polilínea */
viewer.entities.add({
polygon: {
hierarchy: {
positions: positions
},
material: colorPolygon,
outline: true
}
})
/** Se borra la polilínea generada durante el pintado */
viewer.entities.remove(polyline)
/** Se limpia el array de coordenadas usado por la polilínea */
positions = []
/** Se destruye la variable que escucha, para que pinte un único
* polígono */
handler.destroy()
/** El ratón regresa al puntero básico */
document.body.style.cursor = 'auto'
}
/** No hay verdad sin falsedad */
drawing = !drawing
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
/** Por si se usa el botón derecho para cerrar el polígono */
handler.setInputAction(function(click) {
viewer.entities.add({
polygon: {
hierarchy: {
positions: positions
},
material: colorPolygon,
outline: true
}
})
/** Se borra la polilínea generada durante el pintado */
viewer.entities.remove(polyline)
/** Se limpia el array de coordenadas usado por la polilínea */
positions = []
/** Se destruye la variable que escucha, para que pinte un único
* polígono */
handler.destroy()
/** El ratón regresa al puntero básico */
document.body.style.cursor = 'auto'
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
/** Se producirá este evento cuando se mueva el puntero por el visor */
handler.setInputAction(function(movement) {
/** Se define una variable con el punto final del movimiento */
let surfacePosition = viewer.camera.pickEllipsoid(movement.endPosition)
/** En caso de que exista el dibujo del polígono y su punto final */
if (drawing && Cesium.defined(surfacePosition)) {
/** Se añade al listado de posiciones el punto final del movimiento */
positions.push(surfacePosition)
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
}
/** Función que limpia TODO lo que se dibuje en el mapa */
function clearEntities() {
viewer.entities.removeAll()
}
/** Función que saca una regla de medida en el visor
* TODO: hay que hacer la etiqueta de medida dinámica (fjla)
*/
function measureRuler() {
/** Se definen las variables a utilizar */
let colorPoint = Cesium.Color.BROWN.withAlpha(0.6)
let colorPolyline = Cesium.Color.DARKORANGE.withAlpha(0.6)
let entityCollection = new Cesium.EntityCollection()
let activeShapePoints = []
let activeShape
let floatingPoint
let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
let counter = 0
/** Se comprueba si existe una 'regla' previa, y si es así la elimina */
for (entity of viewer.entities.values) {
if (entity.name === 'measurePolyline') {
viewer.entities.remove(entity)
}
}
/** Se comprueba si existe un etiquetado previo, y dado el caso lo elimina
* Esto se mete por separado porque en el mismo FOR peta */
for (entity of viewer.entities.values) {
if (entity.name === 'measureLabel') {
viewer.entities.remove(entity)
}
}
/** El ratón cambia de puntero, para indicar que se puede poner un punto */
document.body.style.cursor = 'copy'
/** Se genera la entidad de punto */
function createPoint(pointCoordinates) {
let point = viewer.entities.add({
name: 'temporalPoint',
position: pointCoordinates,
point: {
color: colorPoint,
pixelSize: 6
}
})
/** Se añade el punto a la colección de puntos, para controlarlo */
entityCollection.add(point)
/** Se devuelve el punto, para almacenarlo como punto temporal */
return point
}
/** Función que dibuja la polilínea */
function drawShapePolyline(positionData) {
/** Se define una variable con la forma de la entidad */
let shape
/** Se genera la entidad de la polilínea */
shape = viewer.entities.add({
name: 'measurePolyline',
polyline: {
positions: positionData,
material: new Cesium.PolylineDashMaterialProperty({
color: colorPolyline,
dashLength: 12.0
}),
width: 3
}
})
/** Se devuelve la polilínea */
return shape
}
/** Función que calcula la longitud de la polilínea */
function polylineLength(polyline) {
/** Se definen los puntos iniciales y finales de la polilínea */
let initialPosition = polyline.polyline.positions.getValue()[0]
let finalPosition = polyline.polyline.positions.getValue()[
polyline.polyline.positions.getValue().length - 1
]
/** Se genera el elipsoide geodésico a partir de las coordenadas */
let ellipsoidGeodesic = new Cesium.EllipsoidGeodesic(
Cesium.Ellipsoid.WGS84.cartesianToCartographic(initialPosition),
Cesium.Ellipsoid.WGS84.cartesianToCartographic(finalPosition)
)
let midPoint = ellipsoidGeodesic.interpolateUsingFraction(0.5)
/** Se define la etiqueta que aparecerá encima de la regla */
viewer.entities.add({
name: 'measureLabel',
position: new Cesium.Cartesian3.fromRadians(
midPoint.longitude,
midPoint.latitude,
midPoint.height
),
label: {
text: (ellipsoidGeodesic.surfaceDistance * 0.001).toFixed(2) + 'km',
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth: 2,
font: '18px sans-serif',
pixelOffset: new Cesium.Cartesian2(0.0, -20)
}
})
//entityCollection.add(measureLabel)
}
/** Función que elimina los puntos de guiado de la guía */
function clear() {
/** Se itera por la colección de puntos guía, y se eliminan */
for (entity of entityCollection.values) {
viewer.entities.remove(entity)
}
}
/** Se producirá este evento cuando se pinche en el visor */
handler.setInputAction(function(event) {
/** Se saca la posición respecto al elipsoide */
let position = viewer.camera.pickEllipsoid(event.position)
/** Se comprueba que donde se pincha está en el mapa */
if (Cesium.defined(position)) {
/** Se indica el número de puntos generados hasta el momento */
counter += 1
/** Se mira si se han definido puntos activos previamente */
if (activeShapePoints.length === 0) {
/** Con cada click, se genera un punto en el mapa */
floatingPoint = createPoint(position)
/** Se mete en el listado la posición del punto generado */
activeShapePoints.push(position)
/** Se define las posiciones hasta el momento */
let dynamicPositions = new Cesium.CallbackProperty(function() {
return activeShapePoints
}, false)
/** Se va pintando un polígono temporal con los puntos temporales */
activeShape = drawShapePolyline(dynamicPositions)
}
/** Se van añadiendo al listado las posiciones de los puntos generados */
activeShapePoints.push(position)
/** Y se van creando puntos */
createPoint(position)
/** Se cuenta si hay al menos dos puntos ya pintados */
if (counter > 1) {
/** Entonces se lanza la función que mide entre puntos */
polylineLength(activeShape)
/** Se destruye la variable que escucha, para que pinte un único punto */
handler.destroy()
/** Se limpia */
clear()
/** El ratón regresa al puntero básico */
document.body.style.cursor = 'auto'
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
/** Se producirá este evento cuando se mueva el cursor por el visor */
handler.setInputAction(function(event) {
/** Se comprueba si el punto flotante es correcto */
if (Cesium.defined(floatingPoint)) {
/** Se define una nueva posición (siguinte punto) */
let newPosition = viewer.camera.pickEllipsoid(event.endPosition)
/** Se comprueba si este nuevo punto es válido */
if (Cesium.defined(newPosition)) {
/** Se reasignan los valores */
floatingPoint.position.setValue(newPosition)
activeShapePoints.pop()
activeShapePoints.push(newPosition)
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
/** Cuando el usuario quiera terminar, tocará el botón derecho */
handler.setInputAction(function(event) {
/** Se indica el número de puntos generados hasta el momento */
counter += 1
if (counter > 1) {
/** Se lanza la función que mide entre puntos */
polylineLength(activeShape)
clear()
}
/** Se destruye la variable que escucha, para que pinte un único punto */
handler.destroy()
/** El ratón regresa al puntero básico */
document.body.style.cursor = 'auto'
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
/** Función que define la extensión inicial del mapa */
function defineViewerInitialExtent(longitude, latitude, altitud) {
viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, altitud)
})
}
/** Función que define el mapa base de inicio */
function initialBaseMap(nameBaseMap, accessToken = '', urlBase) {
/** Se clasifica el tipo de mapa base a utilizar */
baseMapType = nameBaseMap.split('.')[0]
baseMapName = nameBaseMap.split('.')[1]
baseMapStyle = nameBaseMap.split('.')[2]
/** Variable que hará referencia a la variable con la URL del mapa base */
let urlBaseMap = null
/** Se comprueba si el mapa base es de CartoDB */
if (baseMapType === 'cartodb') {
/** Se comprueba si el mapa será sin etiquetas */
if (baseMapStyle === 'NoLabels') {
if (baseMapName === 'Positron') {
urlBaseMap = urlBase
} else if (baseMapName === 'DarkMatter') {
urlBaseMap = urlBase
} else if (baseMapName === 'Voyager') {
urlBaseMap = urlBase
}
} else if (baseMapStyle === 'Labels') {
/** Se comprueba si el mapa será con etiquetas */
if (baseMapName === 'Positron') {
urlBaseMap = urlBase
} else if (baseMapName === 'DarkMatter') {
urlBaseMap = urlBase
} else if (baseMapName === 'Voyager') {
urlBaseMap = urlBase
}
} else if (baseMapStyle === 'OnlyLabels') {
/** Se comprueba si el mapa será únicamente de etiquetas */
if (baseMapName === 'Positron') {
urlBaseMap = urlBase
} else if (baseMapName === 'DarkMatter') {
urlBaseMap = urlBase
} else if (baseMapName === 'Voyager') {
urlBaseMap = urlBase
}
}
/** Se añade el mapa base al mapa */
baseMap = baseMapsLayers.addImageryProvider(
new Cesium.UrlTemplateImageryProvider({
url: urlBaseMap
})
)
} else if (baseMapType === 'esri') {
/** Se comprueba si el mapa base es de CartoDB */
/** Se comprueba si se está cargando un mapa base sin etiquetado */
if (baseMapStyle === 'NoLabels') {
if (baseMapName === 'DarkGray') {
urlBaseMap = urlBase
} else if (baseMapName === 'Gray') {
urlBaseMap = urlBase
} else if (baseMapName === 'Imagery') {
urlBaseMap = urlBase
} else if (baseMapName === 'ShadedRelief') {
urlBaseMap = urlBase
}
/** Se añade el mapa base */
baseMap = baseMapsLayers.addImageryProvider(
new Cesium.ArcGisMapServerImageryProvider({
url: urlBaseMap
})
)
} else if (baseMapStyle === 'Labels') {
/** Se comprueba si se está cargando un mapa base con etiquetado */
if (baseMapName === 'DarkGray') {
baseMap = baseMapsLayers.addImageryProvider(
new Cesium.ArcGisMapServerImageryProvider({
url: urlBase
})
)
baseMap = baseMapsLayers.addImageryProvider(
new Cesium.ArcGisMapServerImageryProvider({
url: urlBase
})
)
} else if (baseMapName === 'Gray') {
baseMap = baseMapsLayers.addImageryProvider(
new Cesium.ArcGisMapServerImageryProvider({
url: urlBase
})
)
baseMap = baseMapsLayers.addImageryProvider(
new Cesium.ArcGisMapServerImageryProvider({
url: urlBase
})
)
} else if (baseMapName === 'Imagery') {
baseMap = baseMapsLayers.addImageryProvider(
new Cesium.ArcGisMapServerImageryProvider({
url: urlBase
})
)
baseMap = baseMapsLayers.addImageryProvider(
new Cesium.ArcGisMapServerImageryProvider({
url: urlBase
})
)
} else if (baseMapName === 'ShadedRelief') {
baseMap = baseMapsLayers.addImageryProvider(
new Cesium.ArcGisMapServerImageryProvider({
url: urlBase
})
)
baseMap = baseMapsLayers.addImageryProvider(
new Cesium.ArcGisMapServerImageryProvider({
url: urlBase
})
)
} else if (baseMapName === 'Streets') {
baseMap = baseMapsLayers.addImageryProvider(
new Cesium.ArcGisMapServerImageryProvider({
url: urlBase
})
)
} else if (baseMapName === 'Topo') {
baseMap = baseMapsLayers.addImageryProvider(
new Cesium.ArcGisMapServerImageryProvider({
url: urlBase
})
)
}
} else if (baseMapStyle === 'OnlyLabels') {
/** Se comprueba si se está cargando un mapa base sólo de etiquetado */
if (baseMapName === 'DarkGray') {
urlBaseMap = urlBase
} else if (baseMapName === 'Gray') {
urlBaseMap = urlBase
} else if (baseMapName === 'Reference') {
urlBaseMap = urlBase
}
/** Se añade el mapa base */
baseMap = baseMapsLayers.addImageryProvider(
new Cesium.ArcGisMapServerImageryProvider({
url: urlBaseMap
})
)
}
} else if (baseMapType === 'osm') {
/** Se comprueba si el mapa base es de OSM */
/** Se comprueba si se está cargando un mapa base sin etiquetado */
if (baseMapStyle === 'NoLabels') {
} else if (baseMapStyle === 'Labels') {
/** Se comprueba si se está cargando un mapa base con etiquetado */
if (baseMapName === 'Mapnik') {
baseMap = baseMapsLayers.addImageryProvider(
Cesium.createOpenStreetMapImageryProvider({
url: urlBase
})
)
} else if (baseMapName === 'BlackAndWhite') {
baseMap = baseMapsLayers.addImageryProvider(
new Cesium.UrlTemplateImageryProvider({
url: urlBase
})
)
}
} else if (baseMapStyle === 'OnlyLabels') {
/** Se comprueba si se está cargando un mapa base sólo de etiquetado */
}
} else if (baseMapType === 'mapbox') {
/** Se comprueba si el mapa base es de OSM */
let mapId = null
/** Se comprueba si se está cargando un mapa base sin etiquetado */
if (baseMapStyle === 'NoLabels') {
if (baseMapName === 'Satellite') {
mapId = 'mapbox.satellite'
} else if (baseMapName === 'Outdoors') {
mapId = 'mapbox.outdoors'
} else if (baseMapName === 'Pencil') {
mapId = 'mapbox.pencil'
}
} else if (baseMapStyle === 'Labels') {
/** Se comprueba si se está cargando un mapa base con etiquetado */
if (baseMapName === 'Streets') {
mapId = 'mapbox.streets'
} else if (baseMapName === 'Light') {
mapId = 'mapbox.light'
} else if (baseMapName === 'Dark') {
mapId = 'mapbox.dark'
} else if (baseMapName === 'Pirates') {
mapId = 'mapbox.pirates'
} else if (baseMapName === 'Comic') {
mapId = 'mapbox.comic'
} else if (baseMapName === 'Emerald') {
mapId = 'mapbox.emerald'
}
} else if (baseMapStyle === 'OnlyLabels') {
/** Se comprueba si se está cargando un mapa base sólo de etiquetado */
}
baseMap = baseMapsLayers.addImageryProvider(
new Cesium.MapboxImageryProvider({
mapId: mapId,
accessToken: accessToken
})
)
}
}
/** Función que muestra las coordenadas del ratón */
function showMouseCartographicPosition() {
/** Se genera la escucha del canvas */
let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
/** Se genera una entidad 'invisible' que seguirá al ratón */
let fakeEntity = viewer.entities.add({
label: {
show: false,
showBackground: true,
font: '14px monospace',
horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
verticalOrigin: Cesium.VerticalOrigin.TOP,
pixelOffset: new Cesium.Cartesian2(15, 0)
}
})
/** Se producirá este evento cuando se mueva el cursor por el visor */
handler.setInputAction(function(movement) {
let cartesian = viewer.camera.pickEllipsoid(
movement.endPosition,
viewer.scene.globe.ellipsoid
)
if (cartesian) {
let cartographic = Cesium.Cartographic.fromCartesian(cartesian)
/** Se define la longitud y latitud, limitando los decimales a un par */
let longitudeString = Cesium.Math.toDegrees(
cartographic.longitude
).toFixed(2)
let latitudeString = Cesium.Math.toDegrees(cartographic.latitude).toFixed(
2
)
/** Se obtienen las coordenadas de la falsa entidad */
fakeEntity.position = cartesian
fakeEntity.label.show = true
/** Se incluye el texto de la ventanita de las coordenadas. */
fakeEntity.label.text =
'Longitude: ' +
(' ' + longitudeString).slice(-7) +
'\u00B0' +
'Latitude: ' +
(' ' + latitudeString).slice(-7) +
'\u00B0'
} else {
fakeEntity.label.show = false
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
}
/** Función que genera capas en el mapa */
function createLayer(layer) {
var layerName = layer.name
dataSourceLayers.push(layerName)
/** Variable con el nombre de la capa, definido en el objeto JSON */
/** Se genera un nombre propio para el dataSource */
var dataSourceName = 'dataSource' + layerName
/** Se comprueba si la capa es de tipo punto */
if (layer.typeGeometry === 'Point') {
/** Se genera un array con las entidades a representar */
var entities = []
entities = layer.features
/** Se comprueba que no haya otro dataSource existente con el mismo nombre
* TO-DO: dataSourceCollection.contains(dataSourceName) */
/** Se crea el dataSource personalizado, con su nombre propio */
var dataSource = new Cesium.CustomDataSource({
name: dataSourceName
})
/** Se mete el dataSource creado en la colección de dataSources */
dataSourceCollection.add(dataSourceName)
/** Se itera por las entidades, y se meten en el dataSource
* TO-DO: parsear TODOS los campos de la ontología --> pendiente de conocerlos */
for (var entity of entities) {
/** Variables con las propiedades de la entidad */
var entityId = entity.properties.id
var entityName = entity.properties.name
/** Variables con la longitud y latitud de la entidad */
var longitude = entity.geometry.coordinates[0]
var latitude = entity.geometry.coordinates[1]
/** Se comprueba si se va a simbolizar con un punto básico */
if (layer.symbology.name === 'simbPointBasic') {
/** Se rellenan las variables */
var pixelSize = layer.symbology.pixelSize
var innerColorTransformacion = new Cesium.Color.fromBytes(
layer.symbology.innerColorRGB.red,
layer.symbology.innerColorRGB.green,
layer.symbology.innerColorRGB.blue
)
var innerColor = new Cesium.Color.fromAlpha(
innerColorTransformacion,
layer.symbology.innerColorAlpha
)
var outlineColorTransformacion = new Cesium.Color.fromBytes(
layer.symbology.outlineColorRGB.red,
layer.symbology.outlineColorRGB.green,
layer.symbology.outlineColorRGB.blue
)
var outlineColor = new Cesium.Color.fromAlpha(
outlineColorTransformacion,
layer.symbology.outlineWidthAlpha
)
var outlineWidth = layer.symbology.outlineWidth
/** Se añade la entidad al dataSource, con las siguientes propiedades */
dataSource.entities.add({
id: entityId,
name: entityName,
description: fakeInfoBox(entity),
position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
point: {
color: innerColor,
pixelSize: pixelSize,
outlineColor: outlineColor,
outlineWidth: outlineWidth
}
})
} else if (layer.symbology.name === 'simbPointBillboard') {
/** En caso de que se vaya a simbolizar con una imagen */
/** Se rellenan las variables */
var image = layer.symbology.image
var scale = layer.symbology.scale
/** Se añade la entidad al dataSource, con las siguientes propiedades */
dataSource.entities.add({
id: entityId,
name: entityName,
ccaa_name: entity.properties.ccaa_name,
ccaa_name_alt: entity.properties.ccaa_name_alt,
ccaa_pob_2018: entity.properties.ccaa_pob_2018,
ccaa_den_2018: entity.properties.ccaa_den_2018,
position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
billboard: {
image: image,
scale: scale
}
})
}
}
/** Se añade el dataSource al visor, mostrando la capa */
viewer.dataSources.add(dataSource)
} else if (layer.typeGeometry === 'Polyline') {
/** Se comprueba si la capa es de tipo línea */
/** Se crea el dataSource personalizado, con su nombre propio */
var dataSource = new Cesium.GeoJsonDataSource({
name: dataSourceName
})
/** Se mete el dataSource creado en la colección de dataSources */
dataSourceCollection.add(dataSource)
/** Se preparan las variables de la simbología */
var innerColorTransformacion = new Cesium.Color.fromBytes(
layer.symbology.innerColorRGB.red,
layer.symbology.innerColorRGB.green,
layer.symbology.innerColorRGB.blue
)
var innerColor = new Cesium.Color.fromAlpha(
innerColorTransformacion,
layer.symbology.innerColorAlpha
)
var strokeWidth = layer.symbology.strokeWidth
/** Se añaden las entidades al dataSource automáticamente, con la siguiente
* configuración de simbología */
dataSource.load(layer, {
stroke: innerColor,
strokeWidth: strokeWidth
})
/** Se añade el dataSource al visor, mostrando la capa */
viewer.dataSources.add(dataSource)
} else if (layer.typeGeometry === 'Polygon') {
/** Se comprueba si la capa es de tipo línea */
/** Se crea el dataSource personalizado, con su nombre propio */
var dataSource = new Cesium.GeoJsonDataSource({
name: dataSourceName
})
/** Se mete el dataSource creado en la colección de dataSources */
dataSourceCollection.add(dataSource)
/** Se preparan las variables de la simbología */
var innerColorTransformacion = new Cesium.Color.fromBytes(
layer.symbology.innerColorRGB.red,
layer.symbology.innerColorRGB.green,
layer.symbology.innerColorRGB.blue
)
var innerColor = new Cesium.Color.fromAlpha(
innerColorTransformacion,
layer.symbology.innerColorAlpha
)
var outlineColorTransformacion = new Cesium.Color.fromBytes(
layer.symbology.outlineColorRGB.red,
layer.symbology.outlineColorRGB.green,
layer.symbology.outlineColorRGB.blue
)
var outlineColor = new Cesium.Color.fromAlpha(
outlineColorTransformacion,
layer.symbology.outerColorAlpha
)
var outlineWidth = layer.symbology.outlineWidth
/** Se añaden las entidades al dataSource automáticamente, con la siguiente
* configuración de simbología */
dataSource.load(layer, {
fill: innerColor,
stroke: outlineColor,
strokeWidth: outlineWidth
})
/** Se añade el dataSource al visor, mostrando la capa */
viewer.dataSources.add(dataSource)
} else {
/** En caso de que no se haya definido una geometría, por la razón que sea,
* se avisa con un registro en la consola.
*/
console.log(
'La ontología ' +
layerName +
' carece de geometría ' +
' definida, por lo que no se representará. Por favor, comprobar ' +
'el archivo fuente.'
)
}
}
function sendFilter() {
let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
handler.setInputAction(function() {
let entity
if (viewer.selectedEntity && viewer.selectedEntity.id != 'Loading...') {
entity = viewer.selectedEntity
parent.parent.postMessage({ eventMap: entity.ccaa_name }, '*')
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}Conexión entre gadgets
Configurado el Visor del mapa para mandar un parámetro concreto como filtro, a continuación se va a configurar el Dashboard para que tome ese elemento enviado desde el Gadget del mapa, y se lo pase al Gadget del diagrama de barras.
Para llevar esto a cabo se usará el Datalink, al cual se puede acceder desde su correspondiente botón situado en la parte superior derecha de la pantalla.
Aparecerá entonces una ventana en la que se definirá qué se conecta a qué, a partir de qué. Los datos a introducir serían:
Gadget de Origen: el Gadget del que partirá el dato, que en este caso será el del mapa.
Campo de Origen: extraído del DataSource, por el que conectará.
Gadget de Destino: el Gadget que recibirá el dato, que será por tanto el diagrama de barras.
Campo de Destino: extraído nuevamente del DataSource, por el que será conectado.
Una vez definidos los elementos de conexión, se pulsará sobre el botón de (+) para generar el filtro.
El siguiente paso consiste en introducir una serie de líneas de código en el Gadget del Visor. En un futuro se hará de manera transparente al usuario, pero de momento es necesario hacerlo a mano.
En primer lugar, hay que editar el Gadget del Visor, lo que hará mediante el botón de Edición del Gadget en cuestión:
Saldrá una nueva pantalla en la que poder editar el Gadget. En ella, hay dos pantallas de código; una de HTML a la izquierda, y otra de JavaScript a la derecha. En esta última habrá que introducir el siguiente código:
Código JS a introducir
var eventMethod = window.addEventListener ? 'addEventListener' : 'attachEvent'
var eventer = window[eventMethod]
var messageEvent = eventMethod === 'attachEvent' ? 'onmessage' : 'message'
vm.initLiveComponent = function() {
eventer(messageEvent, function(e) {
var message = ''
var messageString = ''
if (typeof e.data != 'undefined') {
try {
if (typeof e.data !== 'object') {
message = JSON.parse(e.data)
messageString = e.data
} else {
message = e.data
messageString = JSON.stringify(e.data)
}
} catch (e) {}
} else if (typeof e.message != 'undefined') {
try {
if (typeof e.message !== 'object') {
message = JSON.parse(e.message)
messageString = e.message
} else {
message = e.message
messageString = JSON.stringify(e.message)
}
} catch (e) {}
}
if (messageString.indexOf('eventMap') >= 0) {
$scope.sendFilter('ccaa_name', message.eventMap)
}
})
}
//This function will be call when data change. On first execution oldData will be null
vm.drawLiveComponent = function(newData, oldData) {}
//This function will be call on element resize
vm.resizeEvent = function() {}
//This function will be call when element is destroyed
vm.destroyLiveComponent = function() {}
Cuando se haya hecho, se pulsará en el botón de Compilar y Sincronizar, y se podrá cerrar la ventana de edición. Seguidamente se salvará el Dashboard para guardar los cambios.
El siguiente paso consistirá en probar el mapa y ver si, efectivamente, funciona todo lo que se ha hecho hasta el momento.
¿Funciona como debe? Pues buenas noticias; el Dashboard está listo, y este tutorial se termina. En caso contrario, comprobad que habéis seguido correctamente todos los pasos y no se ha omitido nada. Si aun así hay algo que falla, dejadnos un comentario.
Esperamos que lo hayáis encontrado útil.
Estilismo
La parte de diseño no es algo que se fuese a ver en este tutorial, pero por dejar un poco mejor el Dashboard, se va a proceder a dar cierto estilo a los gadgets utilizados.
Tanto para uno como para otro, para acceder a la configuración de estilos hay que pulsar en el botón de Estilos del menú desplegable del Gadget.
Aparecerá entonces una ventana de edición de estilos, en donde se podrá elegir diversos parámetros, como el texto del cajetín del Gadget, el color de la fuente de letra, el icono, etc. Para este ejemplo se han usado las siguientes propiedades:
El resultado es bastante agradecido.