---
title: "How to connect a GIS viewer with gadgets in a Dashboard?"
canonical: "https://onesaitplatform.refined.site/space/DOCT/2220798807/How%20to%20connect%20a%20GIS%20viewer%20with%20gadgets%20in%20a%20Dashboard%3F"
format: markdown
---
> Macro (toc)

# Intro

This tutorial will explain how to connect a **GIS viewer** generated on the platform with another **gadget** so that they interact with each other in a **dashboard.**

Specifically, we will create a map from an ontology with data on the population and population density of the different Autonomous Communities in Spain, and a gadget bar chart to shows the distribution of the population at the national level, and at the community level, when you click on one of the communities on the map.

As a picture is worth more than sixty words, the result that will be obtained is shown below.

# Ontology generation

We will start by generating the **ontology** of data that will contain the location of the centroids of each Autonomous Community, as well as their population and population density data. For this tutorial, the following contents will be used in the following JSON: [ccaa_population_2018.json](/wiki/download/attachments/2220798807/ccaa_population_2018.json?version=1&modificationDate=1631531165589&cacheVersion=1&api=v2)

> ℹ️ ### Ontology generation
> ℹ️ 
> ℹ️ If you already know how to generate an ontology, you can skip what comes next and generate it on your own.

To generate the ontology, you will first have to navigate to the **Development** menu, and select the **My Ontologies** option.

![image](media://5e18247b-3efb-4b4b-b7e8-a4155117180c)

A screen will appear with all available ontologies. To generate a new one, click on the **Create** button, in the upper right part of the screen.

> Macro (inline-media-image)

This will launch the ontology generation wizard, where you ask what creation method you want to use. For this tutorial, select the option **Creation Step by Step**

![image](media://d2801102-e2f8-455a-a3b9-da52017bb3e7)

The following screen corresponds to the Ontology creation form, where the following information must be entered:

- <u>**Name of the ontology**</u>: unique identification name of the ontology.
- <u>**Meta-information:**</u> tags that identify the ontology that is being created.
- <u>**Description:**</u> a short text explaining the ontology.
- <u>**Active:**</u> whether the ontology is active or not. By default it is active, and it must be left that way.
- <u>**Public:**</u> to allow the ontology to be accessible or not. By default it is disabled, and you must enable this option.
- <u>**Allow encryption of fields:**</u> this box will be left as is, unchecked.

![image](media://3368c54d-62a7-41c4-a707-366bbfea83b4)

After entering the basic information of the ontology, you must select a template for the ontology. From among those available, go to the category of **General,** subcategory of **Empty Template**, and select the later.

![image](media://400c1b47-c658-479b-bada-d7400654b491)

By selecting this template, the schema designer appears. There, you must define the different fields that the Ontology will have.

![image](media://05ce2e75-2bbc-4e9d-8c70-a80e2a4a5522)

The fields to enter will be these:

| Property | Data type | Required | Encrypted |
| --- | --- | --- | --- |
| 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 |

  


The data entered should therefore be as shown below:

![image](media://a0b2c80c-e776-48f7-afea-325b8a7973e1)

Having done this, click on the **Update Schema** button. The screen will automatically scroll to a code viewer, where you can see the structure generated for the ontology. By clicking on the **Generate Instance** button, you can see an example of the structure of the ontology with fictional values.

![image](media://b669f223-bd29-48fc-9c60-58dc4fdc7fdf)

If you agree with the results, click on the button **New** to generate the Ontology.

# Ontology data load

After generating the Ontology, the next step will be to populate it with data.

> ℹ️ ### Loading data in the ontology
> ℹ️ 
> ℹ️ As in the previous section, if you already know how to load data into an ontology, you can skip this step and do it on your own.

  


You will start looking for the newly-created ontology in the ontology list, which is in the initial screen of **My Ontologies.**

![image](media://1be12e1f-0089-4e06-8bc9-9374e604a04a)

Once you've found it, click on the **CRUD** button, to the right of the whole ontology record.

![image](media://db316e16-d813-47e4-ade7-c183e9700f1b)

This will launch the **Create, Read, Update and Delete** (CRUD) wizard of the Ontology, which will allow you to modify its content and, particularly in this case, enter data in it. To do this, click on the **New** button for each record you want to enter.

![image](media://d64e7bc7-d0a5-4ef1-85cf-31719d447773)

In the next screen, you will have to enter the information corresponding to the different fields that were defined previously in the ontology structure.

![image](media://14fd3ea8-8a3f-43ab-84d7-f69948b1acbb)

You can do this field by field, or by copying the structure of each element of the original JSON in the **Output** window.

![image](media://a5cadc1a-0e88-486d-b686-56a8c93e6049)

Once you have entered the data for the first element, click on the **New** button to generate the data. It will be registered in the ontology contents list.> Macro (inline-media-image)



You have to repeat this with the nineteen available records.

![image](media://acb6c6bc-3a31-4a9d-8d2f-5c5e26f74a03)

Once you have finished loading the data, the ontology will be ready for consumption.

# Viewer Space Layer Creation

Once your Ontology is ready, you can create a Space **Layer** from it. the Layer will be displayed in the map viewer.

To do this, navigate to the **Webmap Viewer** menu, and select **My Layers** option.

![image](media://a85cd405-36fb-47d4-8c7c-956a0b544bfa)

Once in the layer manager, click on the **Create** button to generate a new layer.

![image](media://52ec34eb-a9bf-4a8d-bc5f-faf03dcdc4c8)

As with the ontologies, a generation wizard will open, where you must choose the option to **Create Ontology Layer**.

  


![image](media://5a60c849-613a-426f-bed8-4dabff22c2f2)

This will launch the new layer generator, where you must first enter the following information:

- <u>**Identification:**</u> unique identification name for the ontology layer.
- <u>**Ontologies:**</u> the ontology from which the layer is created.
- <u>**Public:**</u> to allow the layer to be accessible or not. By default it is disabled, and the option must be enabled.
- <u>**Description:**</u> a short text explaining the layer.

![image](media://72534993-50a9-4268-8423-6d15e8799d6d)

Once the basic information of the layer has been introduced, you must define three more properties: **geometry, symbology** and the **Info Box**.

The **geometry** will specify the ontology field including the spatial coordinates, and it will also indicate the layer's geometry type. Regarding the heat map option, leave it disabled.

  


![image](media://914a8345-7242-4d1b-b90c-02175b2303bb)

> ℹ️ ### Genearting a heat map in Cesium
> ℹ️ 
> ℹ️ What? Heat maps? Yes, you can generate heat maps with your ontology data. Interested? Well, we happen to have a tutorial that **[earnestly explains how to create them](https://onesaitplatform.atlassian.net/wiki/spaces/DOCT/pages/2220798727)**.

  
About **symbology**, this tab indicates how the graphic points of the Layer will look like. Currently the representation is done by means of colored points, which are configured with four properties:

- **Outer line color.**
- **Inner color.**
- **Outer line thickness.**
- **Size** of the point.

![image](media://e3bf0ed7-fc11-4362-b0a9-9e7c84ace76f)

Lastly, we have the **Info Box** tab. An Info Box or Pop-up is the window that appears when you click on one of the elements of the ontology in the map, and it shows certain information. In this particular case, the fields selected for the Info Box will be used as the fields to be used in the dashboard's gadget filters.

Entering fields is as simple as clicking on the **Add Attribute** button, and selecting the field you want to add, and the name you want it to have.

![image](media://bbc7536f-3bfe-4f8c-8711-5e9cf11ffa95)

For this example, you will insert these fields:

- **ccaa_name**
- **ccaa_name_alt**
- **ccaa_pob_2018**
- **ccaa_den_2018**

![image](media://1c238478-c081-4c2f-8164-9ef0d3d66f2c)

To avoid complications, the name to be assigned will be the same as the field's.

Once the fields to be entered have been selected, click on the **New** button to create the Layer.


> ✅ ### Layer viewing
> ✅ 
> ✅ If you want to have a glance at your layer to see how it is: From the layer manager, look for the layer you just created and, by clicking on the **CRUD** button, you can visualize the data with its coordinates in a table and, in the lower part, a map with the represented data.
> ✅ 
> ✅ Anyway, in the next point, a web viewer will be generated where the layer that has just been created will be inserted. This suggestion also serves to publicize the data visualization option without requiring a web viewer.

# Web Viewer Creation

You already have the Layer. Now you will generate a Web **Viewer** where to view it.

Again, go to the **Webmap Viewers** menu, but select the **My Viewers** option this time.

![image](media://324d7b31-e49d-4da9-9cf7-28044cb6515a)

As in previous cases, click on the **Create** button to launch the Web Viewer creation wizard.

![image](media://52ec34eb-a9bf-4a8d-bc5f-faf03dcdc4c8)

In the wizard that appears, you will need to fill in the following fields:

- <u>**Public:**</u> to allow the viewer to be accessible or not. By default it is disabled, and the option must be enabled.
- <u>**Description:**</u> a short text explaining the viewer.
- <u>**Technology:**</u> technology of the viewfinder type to use. At the moment, the only available option is Cesium.
- <u>**Base map:**</u> corresponds to the 'canvas' that appears in the map's background. You can choose between a vector city image, or satellite image (imagery).
- <u>**Layers:**</u> the layer or layers to be displayed on the map.

![image](media://0d3f9322-d7f1-4658-af07-92318f5aaef6)

Once the fields are completed, and more specifically the base map is chosen, a split window will appear at the bottom, where the Web Viewer will be on the right, and the Viewer's source code on the left.

![image](media://c5d8bf57-8f2d-47e2-8a05-213f53ef04ff)

  
Later in this tutorial, you will have to go back to the Viewer and modify the code of the same to include certain elements, but for now, with this you already have the Web Viewer that you will later put in the dashboard. 

# DataSource Creation

When working with gadgets, it is necessary to generate an Ontology **DataSource.**

To do this, you will navigate in the **Visualization** menu to **My DataSources.**

![image](media://feb9e1fa-95c7-44a5-aaf3-c7fbd75f7c30)

The dataSources management page will open. There, you will have to click on the **Create** button, in the upper right, to launch the DataSources creation form.

![image](media://73db13c5-2d24-4a72-8ba2-7e69254ba64f)

You must fill in the following fields in this form:

- <u>**Identification:**</u> unique identification name of the DataSource.
- <u>**Access mode:**</u> by default and only option will be 'Query'.
- <u>**Source database:**</u> by default and only option will be 'RTDB'.
- <u>**Max Value**</u>: by default it is '100', and it can be left as is.
- <u>**Refresh time:**</u> by default it is '0', and it can be left as is.
- <u>**Select ontology:**</u> here you will select the ontology from which you want to create the DataSource.
- <u>**Description:**</u> a short text explaining the DataSource.

![image](media://c286c7ed-2840-426e-bf3e-7c44bc180101)

Then you have to set up the call to the database. By default, the following call is generated:

![image](media://c8efc0ac-3208-40db-ad0a-8efa31bac1ee)

This call, however, does not work for what we want to do, since the use of the asterisk creates certain problems. Therefore, you need to manually modify this call to pass all the parameters that you require. That call would follow the following pattern:

- select ontologyName.ontologyName.PROPERTY as PROPERTY from ontologyName

In the example case, said call would be:

##### **Data base call**

```sql
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_2018
```

By clicking on the **Execute Query **button, the response of the call will appear, where you can see the JSON with each of the Autonomous Communities next to its associated data.

![image](media://5c52368b-dd32-45f6-976a-0cd43e92ea25)

If you are satisfied with the obtained result, by clicking on the **New** button you will generate the DataSource, ending this section.

# Dashboard Creation

Once the Ontology DataSource has been generated, you can now create the gadgets associated with said DataSource. However, before generating these gadgets, you have to create the **Dashboard** that will contain them.

To create the Dashboard, navigate in the **Visualization** menu to the **My Dashboards** option.

![image](media://9bc154e2-7637-4e15-9f5f-cf4bba2f4dc2)

As in previous cases, access the content manager, corresponding in this case to the dashboards. There, click on the **Create** button to launch the dashboard creation form.

![image](media://466329ba-a978-48eb-8ba9-6ae32a381486)

In this form, you must enter the following information:

- <u>**Identification:**</u> unique identification name of the Dashboard.
- <u>**Description:**</u> a short text explaining the Dashboard.
- <u>**Public:**</u> to allow the viewer to be accessible or not. By default it is disabled, and the option must be enabled.
- <u>**Initial style:**</u> the default style option is *default style*, and it will be left as is.
- <u>**Image:**</u> image to recognize the dashboard. An image can be selected if desired, but it is not necessary to do so.
- <u>**Category:**</u> to categorize the dashboard. This is optional, you do not need to choose any category if you don't want to.
- <u>**Subcategory:**</u> to further categorize the Dashboard. This is also optional, you do not need to choose any subcategory if you don't want to.

![image](media://ca51c34b-c548-41f6-84dc-a326147c1f6e)

Once all the information has been entered, click on the **New** button to generate the dashboard, which will open it automatically. It will appear empty and ready to be filled with the gadgets.

![image](media://2dd4a8e1-e912-4435-b668-e8dedc4a45ba)

# Bar chart gadget creations

The dashboard is already generated, so the next step will be to create the two gadgets it will contain. You will start with the the bar chart gadget, and then you will make the map.

You can generate the gadget in different ways. In this example, and since the dashboard is already generated, you will created it from there. To do this, in the dashboard, click on the **Add Element** button, in the dashboard's upper right part.

![image](media://5593aa41-3970-4b07-8cf9-f699ced08cba)

This will open, at the bottom of the screen, a carousel of gadgets, where you can select the bar chart and drag it to the dashboard:

![image](media://b9d979e0-7172-451c-892e-dac5a1d64374)

Then, a screen will appear asking whether you want to load an existing **gadget,** or to generate a new one.

![image](media://4a80ece5-ed36-4390-9540-d526bc371c9b)

In this case, select the **New Gadget** option. This will launch the creation wizard, where you will have to initially enter two data:

- <u>**Gadget name:**</u> unique identification name of the Gadget.
- <u>**Select the Ontology or DataSource:**</u> where you will select the DataSource previously generated from the Ontology.

![image](media://1d0b1b69-bb6c-44cf-b161-05f11c581544)

Once these two data have been entered, the wizard's content will be updated, showing a wide variety of options to customize the diagram. Among these you can see the fields to be shown in the diagram, with a live example of the changes made at the bottom of the assistant.

The configuration used for this example is as follows:

![image](media://13a592bf-25cc-4ad1-a280-5dfca714fee6)

Once the diagram's aesthetics and contents have been defined, press the **New** button to generate the gadget. The gadget will then appear on the dashboard, where you can change its size and position.

![image](media://5ac354d5-3b80-4842-9e38-a955028030e5)

Having done this, the Gadget is ready. Later, we will talk about gadget customization; but for now, leave it like this. Save the dashboard to not lose the work done so far.

![image](media://85bec2a0-4dd9-46fb-9c55-5ca305937550)

# Web Viewer Gadget creation

To insert the Web Viewer previously created, you can not insert it directly into the Dashboard. Insetad, you must insert it through a **gadget**. Therefore, the previous step will be repeated to create a new gadget, but in this case selecting the **Template** and dragging it to the Dashboard.

![image](media://a3e37116-c894-4980-80dd-99c904b43670)

As with the previous Gadget, you will be shown a screen asking whether you want to use a template to generate the gadget or not. Since you want to enter a Viewer that has been generated on the Platform, select the option **URLGADGET.**

![image](media://30adf84a-f2b9-4d16-8510-698ae801f4d1)

This will cause the window to be updated, requesting two parameters:

- <u>**DataSource:**</u> from which the Gadget will work. In this case, it will be the same one you used for the other gadget.
- <u>**URL:**</u> where you will enter the URL of the Web Viewer that had been  previously generated.

![image](media://beec21b6-6bc7-4843-b22d-efc7de7792b1)

> ℹ️ ### Recovering the Web Viewer's URL
> ℹ️ 
> ℹ️ You don't know the URL of the Web Viewer that had been generated before? Enter the **Webmap Viewers** menu, and select the option **My Viewers** . In the list of viewers, find the one you created, and click on the **URL** button.
> ℹ️ 
> ℹ️ ![image](media://8d384111-ec88-4e14-8e21-f2b430d4d2dd)
> ℹ️ 
> ℹ️ ![image](media://3a186819-b334-40d9-87fa-65f220bccbd1)

Once the data has been entered, the gadget will be ready and will appear on the dashboard. You can modify its position and size as in the previous case.

![image](media://35c1e6b0-f2e0-4ea4-bc59-090161a1cdf7)

Having done this, the gadget is ready. However, when you click on any of the points in the map, nothing happens. In the next section we will discuss how to solve this.

Before continuing, save the changes made to the dashboard.

![image](media://85bec2a0-4dd9-46fb-9c55-5ca305937550)

# Web Viewer set-up

As previously mentioned, you will return to the previously generated Web Viewer to modify your code and prepare it so that it can interact with the gadgets in the Dashboard. Navigate again to the **viewer manager**.

![image](media://324d7b31-e49d-4da9-9cf7-28044cb6515a)

There, find the Viewer that has been generated and select the **Edit** option.

![image](media://b12959dd-7fd0-4895-963a-6c8fa9a65864)

This will open a screen that will allow us to modify the content of the map. Although for this example the code will be modified to make it compatible with the dashboard, you can also modify basic map parameters, such as the layers it contains, the base map, etc.

![image](media://274dac88-8c93-4e24-83c8-f8b29ed2b6a8)

> ✅ ### Viewer Code
> ✅ 
> ✅ If at any time you get lost with what is going on in this section, do not worry: At the end of this section, the ready-made viewer code is included.


In the Viewer code, browse  to the bottom of it, just before the comment of **/** EXECUTION */,** and the following JavaScript function will be included:

##### **sendFilter()**

```javascript
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)
}
```

By entering the code where indicated, it would look like this:

![image](media://840716e1-fd02-43db-8b16-0fd46e4ab615)

> ℹ️ ### What does the function do?
> ℹ️ 
> ℹ️ What this function does is generating an event (line 2) that listens on the map when you click (line 3) on an entity (line 5; in this case, at the points of the Autonomous Communities), and which will emit a message to the dashboard's iFrame from the gadget's iFrame (line 7). The message that is launched will be the name of the Autonomous Community that has been clicked; that is, the 'ccaa_name' field of the entity selected in the Viewer.

Lastly do not forget to include the execution of the newly created function. This will be done under the comment of **/** EXECUTIONS */**, to keep an order.

![image](media://49501325-2f21-4eb4-9d83-bb09cea04e12)

On the other hand, currently you must manually enter certain data fields to the entities to be created. Find the **CreateLayer()** function, specifically where **dataSource.entities.add **is specified. The, include the following properties;

- **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**

![image](media://7290b427-c883-43d7-a6be-c888bb811034)

Once this is done, you don't need to change anything else in the Viewer code, so you can save the changes by clicking on the **Edit** button.


> ✅ ### Viewer parameter check
> ✅ 
> ✅ As generating the Viewer involves configuring many options, to ensure the correct display in the Gadget, you have to check that:
> ✅ 
> ✅ - If there is a property called **infoBox** in the code, it is in 'false'. If it does not exist, then, in the viewer definition, the property of 'infoBox: false,' must be added (the parameter must be written as specified).
> ✅ 
> ✅ ![image](media://55bf6ade-90e8-4573-840c-56315275c5e3)
> ✅ 
> ✅ - That the coordinates of the map correspond to the layer's location. Although this should be automatic, it is possible that for some reason it is not so, so you have to modify the map's starting coordinates. This can be configured by modifying the parameters of the **initialLongitude, initialLatitude **and **initialHeight** variables.
> ✅ 
> ✅ ![image](media://c867922d-a731-4c0e-988b-0eed86797c6e)

  


> ℹ️ ### Download the Viewer source code
> ℹ️ 
> ℹ️ You can download the viewer code below:
> ℹ️ 
> ℹ️ ##### **viewerCode.js**
> ℹ️ 
> ℹ️ ```javascript
> ℹ️ $(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 with the initial map extension and its height/ zoom */
> ℹ️ var initialLongitude = -4.0
> ℹ️ var initialLatitude = 40.0
> ℹ️ 
> ℹ️ var initialHeight = 2200000
> ℹ️ 
> ℹ️ /** Tokens for base map services */
> ℹ️ var accessTokenMapbox = ''
> ℹ️ 
> ℹ️ /** VIEWER */
> ℹ️ 
> ℹ️ /** The map viewer is defined, along with its properties */
> ℹ️ var viewer = new Cesium.Viewer('mapViewer', {
> ℹ️ 	/** Disable the widget on the lower left ball */
> ℹ️ 	animation: false,
> ℹ️ 	/** Start button */
> ℹ️ 	homeButton: false,
> ℹ️ 	/** Base map selector widget */
> ℹ️ 	baseLayerPicker: false,
> ℹ️ 	/** Hide screen button */
> ℹ️ 	fullscreenButton: false,
> ℹ️ 	/** Geocoding box */
> ℹ️ 	geocoder: false,
> ℹ️ 	/** Geocoder box */
> ℹ️ 	infoBox: false,
> ℹ️ 	/** Navigation help button */
> ℹ️ 	navigationHelpButton: false,
> ℹ️ 	/** 2D/2,5D/3D mode selection button */
> ℹ️ 	sceneModePicker: false,
> ℹ️ 	/** Lower time bar widget */
> ℹ️ 	timeline: false,
> ℹ️ 	/** Exclusive 3D mode is forced */
> ℹ️ 	sceneMode: Cesium.SceneMode.SCENE3D,
> ℹ️ 	/** Green box that comes out when selecting entities */
> ℹ️ 	selectionIndicator: false
> ℹ️ })
> ℹ️ 
> ℹ️ /** Remove the default base map and the background blue color */
> ℹ️ 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
> ℹ️ 
> ℹ️ /** FUNCTIONS */
> ℹ️ 
> ℹ️ /** Function that calculates the height of the user's camera */
> ℹ️ function userCameraHeight() {
> ℹ️ 	/** The position of the user's camera is defined */
> ℹ️ 	let cameraPosition = viewer.scene.camera.positionWC
> ℹ️ 
> ℹ️ 	/** Defien the three-dimensional ellipsoid with respect to the camera position */
> ℹ️ 	let ellipsoid = viewer.scene.globe.ellipsoid.scaleToGeodeticSurface(
> ℹ️ 		cameraPosition
> ℹ️ 	)
> ℹ️ 
> ℹ️ 	/** Define the height of the camera from the ellipsoid */
> ℹ️ 	let height = Cesium.Cartesian3.magnitude(
> ℹ️ 		Cesium.Cartesian3.subtract(
> ℹ️ 			cameraPosition,
> ℹ️ 			ellipsoid,
> ℹ️ 			new Cesium.Cartesian3()
> ℹ️ 		)
> ℹ️ 	)
> ℹ️ 
> ℹ️ 	/** The function returns the height of the camera */
> ℹ️ 	return height
> ℹ️ }
> ℹ️ 
> ℹ️ /** Function that increases the zoom */
> ℹ️ function zoomIn() {
> ℹ️ 	/** A variable is defined with the distance */
> ℹ️ 	let height = userCameraHeight()
> ℹ️ 
> ℹ️ 	/** Minimum height from which it does not come closer */
> ℹ️ 	if (height <= 501) {
> ℹ️ 	} else {
> ℹ️ 		/** Zoom approaches */
> ℹ️ 		viewer.camera.zoomIn(500.0)
> ℹ️ 	}
> ℹ️ }
> ℹ️ 
> ℹ️ /** Function that decreases the zoom */
> ℹ️ function zoomOut() {
> ℹ️ 	/** A variable is defined with the distance */
> ℹ️ 	userCameraHeight()
> ℹ️ 
> ℹ️ 	/** Zoom decreases */
> ℹ️ 	viewer.camera.zoomOut(500.0)
> ℹ️ }
> ℹ️ 
> ℹ️ /** Function that attends to the selection of entities and listens to clicks */
> ℹ️ function entityInteractuation() {
> ℹ️ 	/** Define a variable that will have the selected element */
> ℹ️ 	let selectedEntity
> ℹ️ 
> ℹ️ 	/** Another variable with the dynamic position of the point when moving */
> ℹ️ 	let newPosition
> ℹ️ 
> ℹ️ 	/** A variable that controls whenher we are moving or not */
> ℹ️ 	let onMove = false
> ℹ️ 
> ℹ️ 	/** A viewer event handler is generated */
> ℹ️ 	let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
> ℹ️ 
> ℹ️ 	/** This will be executed when the left button is clicked */
> ℹ️ 	handler.setInputAction(function(event) {
> ℹ️ 		/** If we are not moving; that is, we select an entity ... */
> ℹ️ 		if (!onMove) {
> ℹ️ 			/** We make sure there is a selected entity */
> ℹ️ 			if (viewer._selectedEntity) {
> ℹ️ 				/** The selected entity is inserted in the variable */
> ℹ️ 				selectedEntity = viewer._selectedEntity
> ℹ️ 
> ℹ️ 				/** It goes to displacement */
> ℹ️ 				onMove = true
> ℹ️ 			}
> ℹ️ 		} else {
> ℹ️ 
> ℹ️ 		/** ... or if a moving entity is already selected, then ... */
> ℹ️ 			/** The position of the canvas on which it is clicked is collected */
> ℹ️ 			let canvasPosition = new Cesium.Cartesian2(
> ℹ️ 				event.position.x,
> ℹ️ 				event.position.y
> ℹ️ 			)
> ℹ️ 
> ℹ️ 			/** The map ellipsoid is defined */
> ℹ️ 			let ellipsoid = viewer.scene.globe.ellipsoid
> ℹ️ 
> ℹ️ 			/** The coordinates of the canvas are transformed to the ellipsoid */
> ℹ️ 			let cartesian = viewer.camera.pickEllipsoid(canvasPosition, ellipsoid)
> ℹ️ 
> ℹ️ 			/** Define the coordinates of the entity where the click has been made */
> ℹ️ 			selectedEntity.position.setValue(cartesian)
> ℹ️ 			let id = selectedEntity.id
> ℹ️ 			/** The selected entity is deleted, to start over */
> ℹ️ 			selectedEntity = undefined
> ℹ️ 
> ℹ️ 			/** The updateAttribute function is called, giving the possibility to edit the fields */
> ℹ️ 			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)
> ℹ️ 
> ℹ️ 			/** It goes to static */
> ℹ️ 			onMove = false
> ℹ️ 		}
> ℹ️ 	}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
> ℹ️ 
> ℹ️ 	/** This will be executed whenever the mouse cursor moves */
> ℹ️ 	handler.setInputAction(function(event) {
> ℹ️ 		/** Check whether the selected entity is correct or not */
> ℹ️ 		if (Cesium.defined(selectedEntity)) {
> ℹ️ 			/** A new position is defined according to mouse position */
> ℹ️ 			newPosition = viewer.camera.pickEllipsoid(event.endPosition)
> ℹ️ 
> ℹ️ 			/** Check whether this new point is valid or not */
> ℹ️ 			if (Cesium.defined(newPosition)) {
> ℹ️ 				/** Coordinate values ​​of the selected entity are reallocated */
> ℹ️ 				selectedEntity.position.setValue(newPosition)
> ℹ️ 			}
> ℹ️ 		}
> ℹ️ 	}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
> ℹ️ 
> ℹ️ 	/** This will be executed when left click + CONTROL */
> ℹ️ 	handler.setInputAction(
> ℹ️ 		function(click) {
> ℹ️ 			/** Define a variable that stores whatever is clicked */
> ℹ️ 			let editSelectedEntity = viewer.scene.pick(click.position)
> ℹ️ 
> ℹ️ 			/** If you click on an entity */
> ℹ️ 			if (Cesium.defined(editSelectedEntity)) {
> ℹ️ 				console.log(editSelectedEntity.primitive)
> ℹ️ 
> ℹ️ 				/**
> ℹ️ 				 * YOU CAN INSERT YOUR CODE HERE. TEH SELECTED ENTITY IS
> ℹ️ 				 * 'editSelectedEntity', IT CONTAINS THE INFORMATION YOU NEED IN 
> ℹ️ 				 * THE PROPERTY 'primitive'. THE ENTITY'S IDENTIFIER WILL BE 
> ℹ️ 				 * 'editSelectedEntity.primitive.id'.
> ℹ️ 				 *
> ℹ️ 				 * IF YOU'D RATHER RIGHT-CLICK INSTEAD OF CONTROL + LEFT-CLICK,
> ℹ️ 				 * REPLACE THE LAST LINE WITH:
> ℹ️ 				 * 'Cesium.ScreenSpaceEventType.RIGHT_CLICK'
> ℹ️ 				 */
> ℹ️ 			}
> ℹ️ 		},
> ℹ️ 		Cesium.ScreenSpaceEventType.LEFT_CLICK,
> ℹ️ 		Cesium.KeyboardEventModifier.CTRL
> ℹ️ 	)
> ℹ️ }
> ℹ️ 
> ℹ️ /** Function that paints points by clicking on the map viewer */
> ℹ️ function drawPointClick() {
> ℹ️ 	/** Variable with the image URL */
> ℹ️ 	let imagePoint =
> ℹ️ 		'http://localhost:18000/controlpanel/static/images/viewerIcons/point.png'
> ℹ️ 
> ℹ️ 	/** The mouse changes pointer, to indicate that you can put a point */
> ℹ️ 	document.body.style.cursor = 'copy'
> ℹ️ 
> ℹ️ 	/** Define a variable that will listen to canvas events */
> ℹ️ 	let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
> ℹ️ 
> ℹ️ 	/** This event will occur whenever you click on the viewer */
> ℹ️ 	handler.setInputAction(function(event) {
> ℹ️ 		/** The position of the canvas on which it is clicked is collected */
> ℹ️ 		let canvasPosition = new Cesium.Cartesian2(
> ℹ️ 			event.position.x,
> ℹ️ 			event.position.y
> ℹ️ 		)
> ℹ️ 
> ℹ️ 		/** The map ellipsoid is defined */
> ℹ️ 		let ellipsoid = viewer.scene.globe.ellipsoid
> ℹ️ 
> ℹ️ 		/** The coordinates of the canvas are transformed to the ellipsoid */
> ℹ️ 		let cartesian = viewer.camera.pickEllipsoid(canvasPosition, ellipsoid)
> ℹ️ 
> ℹ️ 		/** Cartesian coordinates are converted to cartographic */
> ℹ️ 		let cartographic = ellipsoid.cartesianToCartographic(cartesian)
> ℹ️ 		let longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(4)
> ℹ️ 		let latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(4)
> ℹ️ 
> ℹ️ 		/** A point is added to the site where it is clicked */
> ℹ️ 		var id = viewer.entities.add({
> ℹ️ 			position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
> ℹ️ 			billboard: {
> ℹ️ 				image: imagePoint,
> ℹ️ 				scale: 1.0
> ℹ️ 			}
> ℹ️ 		}).id
> ℹ️ 
> ℹ️ 		/** The listening variable is destroyed, so that it paints a single point */
> ℹ️ 		handler.destroy()
> ℹ️ 
> ℹ️ 		/** The mouse returns to the basic pointer */
> ℹ️ 		document.body.style.cursor = 'auto'
> ℹ️ 	}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
> ℹ️ 
> ℹ️ 	/** This event will occur when you right-click*/
> ℹ️ 	handler.setInputAction(function(event) {
> ℹ️ 		/** The listening variable is destroyed, to cancel the event */
> ℹ️ 		handler.destroy()
> ℹ️ 
> ℹ️ 		/** The mouse returns to the basic pointer */
> ℹ️ 		document.body.style.cursor = 'auto'
> ℹ️ 	}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
> ℹ️ }
> ℹ️ 
> ℹ️ /** Function that paints a line by clicking on the map viewer */
> ℹ️ function drawLineClick() {
> ℹ️ 	/** The variables to be used are defined */
> ℹ️ 	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)
> ℹ️ 
> ℹ️ 	/** The mouse changes pointer, to indicate that you can put a point */
> ℹ️ 	document.body.style.cursor = 'copy'
> ℹ️ 
> ℹ️ 	/** Function generated by the point entity */
> ℹ️ 	function createPoint(pointCoordinates) {
> ℹ️ 		let point = viewer.entities.add({
> ℹ️ 			name: 'temporalPoint',
> ℹ️ 			position: pointCoordinates,
> ℹ️ 			point: {
> ℹ️ 				color: colorPoint,
> ℹ️ 				pixelSize: 6
> ℹ️ 			}
> ℹ️ 		})
> ℹ️ 
> ℹ️ 		/** The point is added to the point collection, to control it */
> ℹ️ 		entityCollection.add(point)
> ℹ️ 
> ℹ️ 		/** The point is returned, to be stored as a temporary point */
> ℹ️ 		return point
> ℹ️ 	}
> ℹ️ 
> ℹ️ 	/** Function that draws the polyline */
> ℹ️ 	function drawShapePolyline(positionData) {
> ℹ️ 		/** A variable is defined in the form of the entity */
> ℹ️ 		let shape
> ℹ️ 
> ℹ️ 		/** The polyline entity is generated */
> ℹ️ 		shape = viewer.entities.add({
> ℹ️ 			polyline: {
> ℹ️ 				positions: positionData,
> ℹ️ 				material: colorPolyline,
> ℹ️ 				width: 3
> ℹ️ 			}
> ℹ️ 		})
> ℹ️ 
> ℹ️ 		/** The polyline is returned */
> ℹ️ 		return shape
> ℹ️ 	}
> ℹ️ 
> ℹ️ 	/** Function that generates the definitive polyline, removing the temps */
> ℹ️ 	function generateFinalPolyline() {
> ℹ️ 		activeShapePoints.pop()
> ℹ️ 		var id = drawShapePolyline(activeShapePoints).id
> ℹ️ 
> ℹ️ 		/** The generated entities are removed and the variables are emptied */
> ℹ️ 		viewer.entities.remove(floatingPoint)
> ℹ️ 		viewer.entities.remove(activeShape)
> ℹ️ 		floatingPoint = undefined
> ℹ️ 		activeShape = undefined
> ℹ️ 		activeShapePoints = []
> ℹ️ 
> ℹ️ 		/** Iterate by the collection of guide points, and remove them */
> ℹ️ 		for (entity of entityCollection.values) {
> ℹ️ 			viewer.entities.remove(entity)
> ℹ️ 		}
> ℹ️ 
> ℹ️ 		/** The listening variable is destroyed, so that it paints a single point */
> ℹ️ 		handler.destroy()
> ℹ️ 
> ℹ️ 		/** The mouse returns to the basic pointer */
> ℹ️ 		document.body.style.cursor = 'auto'
> ℹ️ 	}
> ℹ️ 
> ℹ️ 	/** This event will occur when you click on the viewer */
> ℹ️ 	handler.setInputAction(function(event) {
> ℹ️ 		/** The coordinates of where you click with the mouse are extracted */
> ℹ️ 		let position = viewer.camera.pickEllipsoid(event.position)
> ℹ️ 
> ℹ️ 		/** Check that where you clicked is on the map */
> ℹ️ 		if (Cesium.defined(position)) {
> ℹ️ 			/** Look if previously active points have been defined */
> ℹ️ 			if (activeShapePoints.length === 0) {
> ℹ️ 				/** With each click, a point is generated on the map */
> ℹ️ 				floatingPoint = createPoint(position)
> ℹ️ 
> ℹ️ 				/** The position of the generated point is added to the list */
> ℹ️ 				activeShapePoints.push(position)
> ℹ️ 
> ℹ️ 				/** Define the positions so far */
> ℹ️ 				let dynamicPositions = new Cesium.CallbackProperty(function() {
> ℹ️ 					return activeShapePoints
> ℹ️ 				}, false)
> ℹ️ 
> ℹ️ 				/** A temporary polygon is painted with the time points */
> ℹ️ 				activeShape = drawShapePolyline(dynamicPositions)
> ℹ️ 			}
> ℹ️ 			** The positions of the generated points are added to the list */
> ℹ️ 			activeShapePoints.push(position)
> ℹ️ 
> ℹ️ 			/** And points are created */
> ℹ️ 			createPoint(position)
> ℹ️ 		}
> ℹ️ 	}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
> ℹ️ 
> ℹ️ 	/** This event will occur when the cursor moves through the viewer */
> ℹ️ 	handler.setInputAction(function(event) {
> ℹ️ 		/** Check whether the floating point is correct or not */
> ℹ️ 		if (Cesium.defined(floatingPoint)) {
> ℹ️ 			/** A new position is defined (next point) */
> ℹ️ 			let newPosition = viewer.camera.pickEllipsoid(event.endPosition)
> ℹ️ 
> ℹ️ 			/** Check if this new point is valid */
> ℹ️ 			if (Cesium.defined(newPosition)) {
> ℹ️ 				/** Values ​​are reallocated */
> ℹ️ 				floatingPoint.position.setValue(newPosition)
> ℹ️ 				activeShapePoints.pop()
> ℹ️ 				activeShapePoints.push(newPosition)
> ℹ️ 			}
> ℹ️ 		}
> ℹ️ 	}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
> ℹ️ 
> ℹ️ 	/** When the user wants to finish, she will touch the right button */
> ℹ️ 	handler.setInputAction(function(event) {
> ℹ️ 		/** The final polyline is generated */
> ℹ️ 		generateFinalPolyline()
> ℹ️ 	}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
> ℹ️ }
> ℹ️ 
> ℹ️ /** Function that paints a polygon by clicking on the map viewer */
> ℹ️ function drawPolygonClick() {
> ℹ️ 	/** The variables to be used are defined */
> ℹ️ 	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)
> ℹ️ 
> ℹ️ 	/** The mouse changes pointer, to indicate that you can put a point */
> ℹ️ 	document.body.style.cursor = 'copy'
> ℹ️ 
> ℹ️ 	/** Function that will generate the polygon guide points */
> ℹ️ 	function createPoint(pointCoordinates) {
> ℹ️ 		/** The point entity is generated */
> ℹ️ 		let point = viewer.entities.add({
> ℹ️ 			name: 'temporalPoint',
> ℹ️ 			position: pointCoordinates,
> ℹ️ 			point: {
> ℹ️ 				color: colorPoint,
> ℹ️ 				pixelSize: 6
> ℹ️ 			}
> ℹ️ 		})
> ℹ️ 
> ℹ️ 		/** The point is added to the entity collection, to control it */
> ℹ️ 		entityCollection.add(point)
> ℹ️ 
> ℹ️ 		/** The point is returned, to be stored as a temporary point */
> ℹ️ 		return point
> ℹ️ 	}
> ℹ️ 
> ℹ️ 	/** Function that draws the polygon */
> ℹ️ 	function drawShapePolygon(positionData) {
> ℹ️ 		/** A variable is defined in the form of the entity */
> ℹ️ 		let shape
> ℹ️ 
> ℹ️ 		/** The polygon entity is generated */
> ℹ️ 		shape = viewer.entities.add({
> ℹ️ 			polygon: {
> ℹ️ 				hierarchy: positionData,
> ℹ️ 				material: new Cesium.ColorMaterialProperty(colorPolygon)
> ℹ️ 			}
> ℹ️ 		})
> ℹ️ 
> ℹ️ 		/** The polygon shape is returned */
> ℹ️ 		return shape
> ℹ️ 	}
> ℹ️ 
> ℹ️ 	/** Function that generates the definitive polygon, removing the temps */
> ℹ️ 	function generateFinalPolygon() {
> ℹ️ 		activeShapePoints.pop()
> ℹ️ 		drawShapePolygon(activeShapePoints)
> ℹ️ 
> ℹ️ 		/** The generated entities are removed and the variables are emptied */
> ℹ️ 		viewer.entities.remove(floatingPoint)
> ℹ️ 		viewer.entities.remove(activeShape)
> ℹ️ 		floatingPoint = undefined
> ℹ️ 		activeShape = undefined
> ℹ️ 		activeShapePoints = []
> ℹ️ 
> ℹ️ 		/** Iterate by the collection of guide points, and remove them */
> ℹ️ 		for (entity of entityCollection.values) {
> ℹ️ 			viewer.entities.remove(entity)
> ℹ️ 		}
> ℹ️ 
> ℹ️ 		/** Destroy the listening variable */
> ℹ️ 		handler.destroy()
> ℹ️ 
> ℹ️ 		/** The mouse returns to the basic pointer */
> ℹ️ 		document.body.style.cursor = 'auto'
> ℹ️ 	}
> ℹ️ 
> ℹ️ 	/** This event will occur when you click on the viewer */
> ℹ️ 	handler.setInputAction(function(event) {
> ℹ️ 		/** The coordinates of where you click with the mouse are extracted */
> ℹ️ 		let position = viewer.camera.pickEllipsoid(event.position)
> ℹ️ 
> ℹ️ 		/** Check that where it is clicked is on the map */
> ℹ️ 		if (Cesium.defined(position)) {
> ℹ️ 			/** Look if previously active points have been defined */
> ℹ️ 			if (activeShapePoints.length === 0) {
> ℹ️ 				/** With each click, a point is generated on the map */
> ℹ️ 				floatingPoint = createPoint(position)
> ℹ️ 
> ℹ️ 				/** The position of the generated point is added to the list */
> ℹ️ 				activeShapePoints.push(position)
> ℹ️ 
> ℹ️ 				/** Define the positions so far */
> ℹ️ 				let dynamicPositions = new Cesium.CallbackProperty(function() {
> ℹ️ 					return activeShapePoints
> ℹ️ 				}, false)
> ℹ️ 
> ℹ️ 				/** A temporary polygon is painted with the time points */
> ℹ️ 				activeShape = drawShapePolygon(dynamicPositions)
> ℹ️ 			}
> ℹ️ 
> ℹ️ 			/** The positions of the generated points are added to the list */
> ℹ️ 			activeShapePoints.push(position)
> ℹ️ 
> ℹ️ 			/** And points are created */
> ℹ️ 			createPoint(position)
> ℹ️ 		}
> ℹ️ 	}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
> ℹ️ 
> ℹ️ 	/** This event will run when the cursor moves through the viewer */
> ℹ️ 	handler.setInputAction(function(event) {
> ℹ️ 		/** Check whether the floating point is correct */
> ℹ️ 		if (Cesium.defined(floatingPoint)) {
> ℹ️ 			/** A new position is defined (next point) */
> ℹ️ 			let newPosition = viewer.camera.pickEllipsoid(event.endPosition)
> ℹ️ 
> ℹ️ 			/** Check whether this new point is valid */
> ℹ️ 			if (Cesium.defined(newPosition)) {
> ℹ️ 				/** Values ​​are reallocated */
> ℹ️ 				floatingPoint.position.setValue(newPosition)
> ℹ️ 				activeShapePoints.pop()
> ℹ️ 				activeShapePoints.push(newPosition)
> ℹ️ 			}
> ℹ️ 		}
> ℹ️ 	}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
> ℹ️ 
> ℹ️ 	/** When the user wants to finish, she will touch the right button */
> ℹ️ 	handler.setInputAction(function(event) {
> ℹ️ 		/** The definitive polyline is generated */
> ℹ️ 		generateFinalPolygon()
> ℹ️ 	}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
> ℹ️ }
> ℹ️ 
> ℹ️ /** Function that paints or draws freehand polygons in the map viewer */
> ℹ️ function drawPolygonFreehand() {
> ℹ️ 	/** The variables to be used are defined */
> ℹ️ 	let colorPolygon = Cesium.Color.fromCssColorString('#FF0000').withAlpha(0.6)
> ℹ️ 	let drawing = false
> ℹ️ 	let polyline
> ℹ️ 	let positions = []
> ℹ️ 	let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
> ℹ️ 
> ℹ️ 	/** The mouse changes pointer, to indicate that you can put a point */
> ℹ️ 	document.body.style.cursor = 'copy'
> ℹ️ 
> ℹ️ 	/** This event will occur when you click on the viewer */
> ℹ️ 	handler.setInputAction(function(click) {
> ℹ️ 		/** If there is no polygon (first use) */
> ℹ️ 		if (!drawing) {
> ℹ️ 			/** The polyline is defined following the mouse pointer */
> ℹ️ 			polyline = viewer.entities.add({
> ℹ️ 				polyline: {
> ℹ️ 					positions: new Cesium.CallbackProperty(function() {
> ℹ️ 						return positions
> ℹ️ 					}, false),
> ℹ️ 					material: colorPolygon
> ℹ️ 				}
> ℹ️ 			})
> ℹ️ 
> ℹ️ 			/** When the polygon you want has been painted */
> ℹ️ 		} else {
> ℹ️ 			/** The polygon is defined from the polyline */
> ℹ️ 			viewer.entities.add({
> ℹ️ 				polygon: {
> ℹ️ 					hierarchy: {
> ℹ️ 						positions: positions
> ℹ️ 					},
> ℹ️ 					material: colorPolygon,
> ℹ️ 					outline: true
> ℹ️ 				}
> ℹ️ 			})
> ℹ️ 
> ℹ️ 			/** The polyline generated during painting is removed */
> ℹ️ 			viewer.entities.remove(polyline)
> ℹ️ 
> ℹ️ 			/** The coordinate array used by the polyline is cleaned */
> ℹ️ 			positions = []
> ℹ️ 
> ℹ️ 			/** The variable that listens is destroyed, so that it paints a single polygon */
> ℹ️ 			handler.destroy()
> ℹ️ 
> ℹ️ 			/** The mouse returns to the basic pointer */
> ℹ️ 			document.body.style.cursor = 'auto'
> ℹ️ 		}
> ℹ️ 
> ℹ️ 		/** There is no truth without falsehood */
> ℹ️ 		drawing = !drawing
> ℹ️ 	}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
> ℹ️ 
> ℹ️ 	/** If the right button is used to close the polygon */
> ℹ️ 	handler.setInputAction(function(click) {
> ℹ️ 		viewer.entities.add({
> ℹ️ 			polygon: {
> ℹ️ 				hierarchy: {
> ℹ️ 					positions: positions
> ℹ️ 				},
> ℹ️ 				material: colorPolygon,
> ℹ️ 				outline: true
> ℹ️ 			}
> ℹ️ 		})
> ℹ️ 
> ℹ️ 		/** The polyline generated during painting is removed */
> ℹ️ 		viewer.entities.remove(polyline)
> ℹ️ 
> ℹ️ 		/** The coordinate array used by the polyline is cleaned */
> ℹ️ 		positions = []
> ℹ️ 
> ℹ️ 		/** The variable that listens is destroyed, so that it paints a single polygon */
> ℹ️ 		handler.destroy()
> ℹ️ 
> ℹ️ 		/** The mouse returns to the basic pointer */
> ℹ️ 		document.body.style.cursor = 'auto'
> ℹ️ 	}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
> ℹ️ 
> ℹ️ 	/** This event will occur when the pointer moves through the viewer */
> ℹ️ 	handler.setInputAction(function(movement) {
> ℹ️ 		/** A variable is defined with the movement's endpoint*/
> ℹ️ 		let surfacePosition = viewer.camera.pickEllipsoid(movement.endPosition)
> ℹ️ 
> ℹ️ 		/** If there is a polygon drawing and its endpoint */
> ℹ️ 		if (drawing && Cesium.defined(surfacePosition)) {
> ℹ️ 			/** The movement's endpoint is added to the list of positions */
> ℹ️ 			positions.push(surfacePosition)
> ℹ️ 		}
> ℹ️ 	}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
> ℹ️ }
> ℹ️ 
> ℹ️ /** Function that cleans EVERYTHING that is drawn on the map */
> ℹ️ function clearEntities() {
> ℹ️ 	viewer.entities.removeAll()
> ℹ️ }
> ℹ️ 
> ℹ️ /** Function that takes a measurement rule in the viewer
> ℹ️  * TODO: the dynamic measurement label must be made (fjla)
> ℹ️  */
> ℹ️ function measureRuler() {
> ℹ️ 	/** The variables to be used are defined */
> ℹ️ 	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
> ℹ️ 
> ℹ️ 	/** Check whether there is a previous 'rule', and if so, remove it */
> ℹ️ 	for (entity of viewer.entities.values) {
> ℹ️ 		if (entity.name === 'measurePolyline') {
> ℹ️ 			viewer.entities.remove(entity)
> ℹ️ 		}
> ℹ️ 	}
> ℹ️ 
> ℹ️ 	/** Check whether there is a previous labeling; if necessary, remove it
> ℹ️ 	 * This is done separately because in the same FOR it won't work */
> ℹ️ 	for (entity of viewer.entities.values) {
> ℹ️ 		if (entity.name === 'measureLabel') {
> ℹ️ 			viewer.entities.remove(entity)
> ℹ️ 		}
> ℹ️ 	}
> ℹ️ 
> ℹ️ 	/** The mouse changes pointer, to indicate that you can put a point */
> ℹ️ 	document.body.style.cursor = 'copy'
> ℹ️ 
> ℹ️ 	/** The point entity is generated */
> ℹ️ 	function createPoint(pointCoordinates) {
> ℹ️ 		let point = viewer.entities.add({
> ℹ️ 			name: 'temporalPoint',
> ℹ️ 			position: pointCoordinates,
> ℹ️ 			point: {
> ℹ️ 				color: colorPoint,
> ℹ️ 				pixelSize: 6
> ℹ️ 			}
> ℹ️ 		})
> ℹ️ 
> ℹ️ 		/** The point is added to the collection of points, to control it  /
> ℹ️ 		entityCollection.add(point)
> ℹ️ 
> ℹ️ 		/** The point is returned, to be stored as a temporary point */
> ℹ️ 		return point
> ℹ️ 	}
> ℹ️ 
> ℹ️ /** Function that draws the polyline */
> ℹ️ 	function drawShapePolyline(positionData) {
> ℹ️ 		/** A variable is defined in the form of the entity */
> ℹ️ 		let shape
> ℹ️ 
> ℹ️ 		/** The polyline entity is generated */
> ℹ️ 		shape = viewer.entities.add({
> ℹ️ 			name: 'measurePolyline',
> ℹ️ 			polyline: {
> ℹ️ 				positions: positionData,
> ℹ️ 				material: new Cesium.PolylineDashMaterialProperty({
> ℹ️ 					color: colorPolyline,
> ℹ️ 					dashLength: 12.0
> ℹ️ 				}),
> ℹ️ 				width: 3
> ℹ️ 			}
> ℹ️ 		})
> ℹ️ 
> ℹ️ 		/** The polyline is returned */
> ℹ️ 		return shape
> ℹ️ 	}
> ℹ️ 
> ℹ️ 	/** Function that calculates the length of the polyline */
> ℹ️ 	function polylineLength(polyline) {
> ℹ️ 		/** The polyline's start and end points are defined */
> ℹ️ 		let initialPosition = polyline.polyline.positions.getValue()[0]
> ℹ️ 		let finalPosition = polyline.polyline.positions.getValue()[
> ℹ️ 			polyline.polyline.positions.getValue().length - 1
> ℹ️ 		]
> ℹ️ 
> ℹ️ 		/** The geodetic ellipsoid is generated from the coordinates */
> ℹ️ 		let ellipsoidGeodesic = new Cesium.EllipsoidGeodesic(
> ℹ️ 			Cesium.Ellipsoid.WGS84.cartesianToCartographic(initialPosition),
> ℹ️ 			Cesium.Ellipsoid.WGS84.cartesianToCartographic(finalPosition)
> ℹ️ 		)
> ℹ️ 
> ℹ️ 		let midPoint = ellipsoidGeodesic.interpolateUsingFraction(0.5)
> ℹ️ 
> ℹ️ 		/** The label that will appear above the rule is defined */
> ℹ️ 		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)
> ℹ️ 	}
> ℹ️ 
> ℹ️ 	/** Function that removes the guide points of the guide */
> ℹ️ 	function clear() {
> ℹ️ 		/** Iterated through the collection of guide points, and remove them */
> ℹ️ 		for (entity of entityCollection.values) {
> ℹ️ 			viewer.entities.remove(entity)
> ℹ️ 		}
> ℹ️ 	}
> ℹ️ 
> ℹ️ 	/** This event will occur when you click on the viewer */
> ℹ️ 	handler.setInputAction(function(event) {
> ℹ️ 		/** The position with respect to the ellipsoid is obtained */
> ℹ️ 		let position = viewer.camera.pickEllipsoid(event.position)
> ℹ️ 
> ℹ️ 		/** Verified the position the user clicked on is on the map */
> ℹ️ 		if (Cesium.defined(position)) {
> ℹ️ 			/** The number of points generated so far is counted */
> ℹ️ 			counter += 1
> ℹ️ 
> ℹ️ 			/** Check whether previously active points have been defined */
> ℹ️ 			if (activeShapePoints.length === 0) {
> ℹ️ 				/** With each click, a point is generated on the map */
> ℹ️ 				floatingPoint = createPoint(position)
> ℹ️ 
> ℹ️ 				/** The position of the generated point is added to the list */
> ℹ️ 				activeShapePoints.push(position)
> ℹ️ 
> ℹ️ 				/** Define the positions so far */
> ℹ️ 				let dynamicPositions = new Cesium.CallbackProperty(function() {
> ℹ️ 					return activeShapePoints
> ℹ️ 				}, false)
> ℹ️ 
> ℹ️ 				/** A temporary polygon is painted with the time points */
> ℹ️ 				activeShape = drawShapePolyline(dynamicPositions)
> ℹ️ 			}
> ℹ️ 
> ℹ️ 			/** The positions of the generated points are added to the list */
> ℹ️ 			activeShapePoints.push(position)
> ℹ️ 
> ℹ️ 			/** And points are created */
> ℹ️ 			createPoint(position)
> ℹ️ 
> ℹ️ 			/** Count whether there are at least two points already painted */
> ℹ️ 			if (counter > 1) {
> ℹ️ 				/** If so, then launch the function that measures between points */
> ℹ️ 				polylineLength(activeShape)
> ℹ️ 
> ℹ️ 				/** The listening variable is destroyed, so that it paints a single point */
> ℹ️ 				handler.destroy()
> ℹ️ 
> ℹ️ 				/** Clean */
> ℹ️ 				clear()
> ℹ️ 
> ℹ️ 				/** The mouse returns to the basic pointer */
> ℹ️ 				document.body.style.cursor = 'auto'
> ℹ️ 			}
> ℹ️ 		}
> ℹ️ 	}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
> ℹ️ 
> ℹ️ 	/** This event will occur when the cursor moves through the viewer */
> ℹ️ 	handler.setInputAction(function(event) {
> ℹ️ 		/** Check whether the floating point is correct */
> ℹ️ 		if (Cesium.defined(floatingPoint)) {
> ℹ️ 			/** Define a new position (next point) */
> ℹ️ 			let newPosition = viewer.camera.pickEllipsoid(event.endPosition)
> ℹ️ 
> ℹ️ 			/** Check whether this new point is valid */
> ℹ️ 			if (Cesium.defined(newPosition)) {
> ℹ️ 				/** Se reasignan los valores */
> ℹ️ 				floatingPoint.position.setValue(newPosition)
> ℹ️ 				activeShapePoints.pop()
> ℹ️ 				activeShapePoints.push(newPosition)
> ℹ️ 			}
> ℹ️ 		}
> ℹ️ 	}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
> ℹ️ 
> ℹ️ 	/** When the user wants to finish, she will right-click */
> ℹ️ 	handler.setInputAction(function(event) {
> ℹ️ 		/** The number of points generated so far is counted */
> ℹ️ 		counter += 1
> ℹ️ 
> ℹ️ 		if (counter > 1) {
> ℹ️ 			/** Launch the function that measures between points */
> ℹ️ 			polylineLength(activeShape)
> ℹ️ 			clear()
> ℹ️ 		}
> ℹ️ 
> ℹ️ 		/** The listening variable is destroyed, so that it paints a single point */
> ℹ️ 		handler.destroy()
> ℹ️ 
> ℹ️ 		/** The mouse returns to the basic pointer */
> ℹ️ 		document.body.style.cursor = 'auto'
> ℹ️ 	}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
> ℹ️ }
> ℹ️ 
> ℹ️ /** Function that defines the initial map extension */
> ℹ️ function defineViewerInitialExtent(longitude, latitude, altitud) {
> ℹ️ 	viewer.camera.setView({
> ℹ️ 		destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, altitud)
> ℹ️ 	})
> ℹ️ }
> ℹ️ 
> ℹ️ /** Function that defines the starting base map */
> ℹ️ function initialBaseMap(nameBaseMap, accessToken = '', urlBase) {
> ℹ️ 	/** The type of base map to be used is classified */
> ℹ️ 	baseMapType = nameBaseMap.split('.')[0]
> ℹ️ 	baseMapName = nameBaseMap.split('.')[1]
> ℹ️ 	baseMapStyle = nameBaseMap.split('.')[2]
> ℹ️ 
> ℹ️ 	/** Variable that refers the variable with the URL of the base map */
> ℹ️ 	let urlBaseMap = null
> ℹ️ 
> ℹ️ 	/** Check whether the base map is from CartoDB */
> ℹ️ 	if (baseMapType === 'cartodb') {
> ℹ️ 		/** Check whether the map is label-less */
> ℹ️ 		if (baseMapStyle === 'NoLabels') {
> ℹ️ 			if (baseMapName === 'Positron') {
> ℹ️ 				urlBaseMap = urlBase
> ℹ️ 			} else if (baseMapName === 'DarkMatter') {
> ℹ️ 				urlBaseMap = urlBase
> ℹ️ 			} else if (baseMapName === 'Voyager') {
> ℹ️ 				urlBaseMap = urlBase
> ℹ️ 			}
> ℹ️ 		} else if (baseMapStyle === 'Labels') {
> ℹ️ 
> ℹ️ 		/** Check whether the map has labels */
> ℹ️ 			if (baseMapName === 'Positron') {
> ℹ️ 				urlBaseMap = urlBase
> ℹ️ 			} else if (baseMapName === 'DarkMatter') {
> ℹ️ 				urlBaseMap = urlBase
> ℹ️ 			} else if (baseMapName === 'Voyager') {
> ℹ️ 				urlBaseMap = urlBase
> ℹ️ 			}
> ℹ️ 		} else if (baseMapStyle === 'OnlyLabels') {
> ℹ️ 
> ℹ️ 		/** Check whether the map is only labels */
> ℹ️ 			if (baseMapName === 'Positron') {
> ℹ️ 				urlBaseMap = urlBase
> ℹ️ 			} else if (baseMapName === 'DarkMatter') {
> ℹ️ 				urlBaseMap = urlBase
> ℹ️ 			} else if (baseMapName === 'Voyager') {
> ℹ️ 				urlBaseMap = urlBase
> ℹ️ 			}
> ℹ️ 		}
> ℹ️ 
> ℹ️ 		/** The base map is added to the map */
> ℹ️ 		baseMap = baseMapsLayers.addImageryProvider(
> ℹ️ 			new Cesium.UrlTemplateImageryProvider({
> ℹ️ 				url: urlBaseMap
> ℹ️ 			})
> ℹ️ 		)
> ℹ️ 	} else if (baseMapType === 'esri') {
> ℹ️ 
> ℹ️ 	/** Check whether the base map is from CartoDB */
> ℹ️ 		/** Check whether a base map is loaded without labeling */
> ℹ️ 		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
> ℹ️ 			}
> ℹ️ 
> ℹ️ 			/** The base map is added */
> ℹ️ 			baseMap = baseMapsLayers.addImageryProvider(
> ℹ️ 				new Cesium.ArcGisMapServerImageryProvider({
> ℹ️ 					url: urlBaseMap
> ℹ️ 				})
> ℹ️ 			)
> ℹ️ 		} else if (baseMapStyle === 'Labels') {
> ℹ️ 
> ℹ️ 		/** Check whether a base map with labeling is loading */
> ℹ️ 			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') {
> ℹ️ 
> ℹ️ 		/** Check whether a label-only base map is being loaded */
> ℹ️ 			if (baseMapName === 'DarkGray') {
> ℹ️ 				urlBaseMap = urlBase
> ℹ️ 			} else if (baseMapName === 'Gray') {
> ℹ️ 				urlBaseMap = urlBase
> ℹ️ 			} else if (baseMapName === 'Reference') {
> ℹ️ 				urlBaseMap = urlBase
> ℹ️ 			}
> ℹ️ 
> ℹ️ 			/** The base map is added */
> ℹ️ 			baseMap = baseMapsLayers.addImageryProvider(
> ℹ️ 				new Cesium.ArcGisMapServerImageryProvider({
> ℹ️ 					url: urlBaseMap
> ℹ️ 				})
> ℹ️ 			)
> ℹ️ 		}
> ℹ️ 	} else if (baseMapType === 'osm') {
> ℹ️ 
> ℹ️ 	/** Check whether the base map is OSM */
> ℹ️ 		/** Check whether a base map without labeling is being loaded */
> ℹ️ 		if (baseMapStyle === 'NoLabels') {
> ℹ️ 		} else if (baseMapStyle === 'Labels') {
> ℹ️ 
> ℹ️ 		/** Check whether a base map with labeling is being loaded */
> ℹ️ 			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') {
> ℹ️ 
> ℹ️ 		/** Check whether a label-only base map is being loaded */
> ℹ️ 		}
> ℹ️ 	} else if (baseMapType === 'mapbox') {
> ℹ️ 
> ℹ️ 	/** Check whether the base map is from OSM */
> ℹ️ 		let mapId = null
> ℹ️ 
> ℹ️ 		/** Check whether a base map without labeling is being loaded */
> ℹ️ 		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') {
> ℹ️ 
> ℹ️ 		/** Check whether a base map with labeling is being loaded */
> ℹ️ 			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') {
> ℹ️ 
> ℹ️ 		/** Check whether a label-only base map is being loaded */
> ℹ️ 		}
> ℹ️ 
> ℹ️ 		baseMap = baseMapsLayers.addImageryProvider(
> ℹ️ 			new Cesium.MapboxImageryProvider({
> ℹ️ 				mapId: mapId,
> ℹ️ 				accessToken: accessToken
> ℹ️ 			})
> ℹ️ 		)
> ℹ️ 	}
> ℹ️ }
> ℹ️ 
> ℹ️ /** Function that shows mouse coordinates */
> ℹ️ function showMouseCartographicPosition() {
> ℹ️ 	/** Canvas listening is generated */
> ℹ️ 	let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
> ℹ️ 
> ℹ️ 	/** A 'invisible' entity that will follow the mouse is generated */
> ℹ️ 	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)
> ℹ️ 		}
> ℹ️ 	})
> ℹ️ 
> ℹ️ 	/** This event will occur when the cursor moves through the viewer */
> ℹ️ 	handler.setInputAction(function(movement) {
> ℹ️ 		let cartesian = viewer.camera.pickEllipsoid(
> ℹ️ 			movement.endPosition,
> ℹ️ 			viewer.scene.globe.ellipsoid
> ℹ️ 		)
> ℹ️ 		if (cartesian) {
> ℹ️ 			let cartographic = Cesium.Cartographic.fromCartesian(cartesian)
> ℹ️ 
> ℹ️ 			/** Longitude and latitude are defined, limiting decimals to 2 */
> ℹ️ 			let longitudeString = Cesium.Math.toDegrees(
> ℹ️ 				cartographic.longitude
> ℹ️ 			).toFixed(2)
> ℹ️ 			let latitudeString = Cesium.Math.toDegrees(cartographic.latitude).toFixed(
> ℹ️ 				2
> ℹ️ 			)
> ℹ️ 
> ℹ️ 			/** The coordinates of the false entity are obtained */
> ℹ️ 			fakeEntity.position = cartesian
> ℹ️ 			fakeEntity.label.show = true
> ℹ️ 
> ℹ️ 			/** The text of the coordinate window is included. */
> ℹ️ 			fakeEntity.label.text =
> ℹ️ 				'Longitude: ' +
> ℹ️ 				('   ' + longitudeString).slice(-7) +
> ℹ️ 				'\u00B0' +
> ℹ️ 				'Latitude: ' +
> ℹ️ 				('   ' + latitudeString).slice(-7) +
> ℹ️ 				'\u00B0'
> ℹ️ 		} else {
> ℹ️ 			fakeEntity.label.show = false
> ℹ️ 		}
> ℹ️ 	}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
> ℹ️ }
> ℹ️ 
> ℹ️ /** Function that generates layers on the map */
> ℹ️ function createLayer(layer) {
> ℹ️ 	var layerName = layer.name
> ℹ️ 	dataSourceLayers.push(layerName)
> ℹ️ 	/** Variable with the layer name, defined in the JSON object */
> ℹ️ 
> ℹ️ 	/** A proper name for the dataSource is generated */
> ℹ️ 	var dataSourceName = 'dataSource' + layerName
> ℹ️ 
> ℹ️ 	/** Check whether the layer is of type: point */
> ℹ️ 	if (layer.typeGeometry === 'Point') {
> ℹ️ 		/** An array is generated with the entities to beed represent */
> ℹ️ 		var entities = []
> ℹ️ 		entities = layer.features
> ℹ️ 
> ℹ️ 		/** Check that there is no other existing dataSource with the same name
> ℹ️ 		 * TO-DO: dataSourceCollection.contains(dataSourceName) */
> ℹ️ 
> ℹ️ 		/** The custom dataSource is created, with its own proper name */
> ℹ️ 		var dataSource = new Cesium.CustomDataSource({
> ℹ️ 			name: dataSourceName
> ℹ️ 		})
> ℹ️ 
> ℹ️ 		/** The created dataSource is insterted in the dataSources collection */
> ℹ️ 		dataSourceCollection.add(dataSourceName)
> ℹ️ 
> ℹ️ 		/** /** Iterate by the entities, and insert them into the dataSource
> ℹ️ 		 * TO-DO: parse ALL fields of ontology -> pending to know them */
> ℹ️ 		for (var entity of entities) {
> ℹ️ 			/** Variables with the entity's properties */
> ℹ️ 			var entityId = entity.properties.id
> ℹ️ 			var entityName = entity.properties.name
> ℹ️ 
> ℹ️ 			/** Variables with the entity's longitude and latitude */
> ℹ️ 			var longitude = entity.geometry.coordinates[0]
> ℹ️ 			var latitude = entity.geometry.coordinates[1]
> ℹ️ 
> ℹ️ 			/** Check whether it will be symbolized with a basic point */
> ℹ️ 			if (layer.symbology.name === 'simbPointBasic') {
> ℹ️ 				/** Fill in the 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
> ℹ️ 
> ℹ️ 				/** The entity is added to the dataSource, with the following properties */
> ℹ️ 				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') {
> ℹ️ 
> ℹ️ 			/** If an image will be used to symbolize it */
> ℹ️ 				/** The variables are filled in */
> ℹ️ 				var image = layer.symbology.image
> ℹ️ 				var scale = layer.symbology.scale
> ℹ️ 
> ℹ️ 				/** The entity is added to the dataSource, with the following properties */
> ℹ️ 				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
> ℹ️ 					}
> ℹ️ 				})
> ℹ️ 			}
> ℹ️ 		}
> ℹ️ 
> ℹ️ 		/**  The dataSource is added to the viewer, showing the layer */
> ℹ️ 		viewer.dataSources.add(dataSource)
> ℹ️ 	} else if (layer.typeGeometry === 'Polyline') {
> ℹ️ 
> ℹ️ 	/**  Check whether the layer is of type line */
> ℹ️ 		/**  The custom dataSource is created, with its own name */
> ℹ️ 		var dataSource = new Cesium.GeoJsonDataSource({
> ℹ️ 			name: dataSourceName
> ℹ️ 		})
> ℹ️ 
> ℹ️ 		/**  The created dataSource is inserted in the dataSources collection */
> ℹ️ 		dataSourceCollection.add(dataSource)
> ℹ️ 
> ℹ️ 		/**  Symbology variables are prepared */
> ℹ️ 		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
> ℹ️ 
> ℹ️ 		/**  Entities are added to the dataSource automatically, with the following
> ℹ️ 		 * symbology settings */
> ℹ️ 		dataSource.load(layer, {
> ℹ️ 			stroke: innerColor,
> ℹ️ 			strokeWidth: strokeWidth
> ℹ️ 		})
> ℹ️ 		/**  The dataSource is added to the viewer, showing the layer */
> ℹ️ 		viewer.dataSources.add(dataSource)
> ℹ️ 	} else if (layer.typeGeometry === 'Polygon') {
> ℹ️ 
> ℹ️ 	/**  Check whether the layer is of type line */
> ℹ️ 		/**  The custom dataSource is created, with its own name */
> ℹ️ 		var dataSource = new Cesium.GeoJsonDataSource({
> ℹ️ 			name: dataSourceName
> ℹ️ 		})
> ℹ️ 
> ℹ️ 		/**  The created dataSource is inserted in the dataSources collection */
> ℹ️ 		dataSourceCollection.add(dataSource)
> ℹ️ 
> ℹ️ 		/**  Symbology variables are prepared */
> ℹ️ 		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
> ℹ️ 
> ℹ️ 		/**  Entities are automatically added to the dataSource, with the following
> ℹ️ 		* symbology settings */
> ℹ️ 		dataSource.load(layer, {
> ℹ️ 			fill: innerColor,
> ℹ️ 			stroke: outlineColor,
> ℹ️ 			strokeWidth: outlineWidth
> ℹ️ 		})
> ℹ️ 
> ℹ️ 		/**  The dataSource is added to the viewer, showing the layer */
> ℹ️ 		viewer.dataSources.add(dataSource)
> ℹ️ 	} else {
> ℹ️ 
> ℹ️ 	/**  If a geometry has not been defined, for whatever reason, then this
> ℹ️ 	 * is notified with a record in the console.
> ℹ️ 	 */
> ℹ️ 		console.log(
> ℹ️ 			'The ontología ' +
> ℹ️ 				layerName +
> ℹ️ 				' lacks defined ' +
> ℹ️ 				'geometry, thus will not be shown. Please check ' +
> ℹ️ 				'source file.'
> ℹ️ 		)
> ℹ️ 	}
> ℹ️ }
> ℹ️ 
> ℹ️ 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)
> ℹ️ }
> ℹ️ ```

# Connection between gadgets

Now that the Map Viewer is configured to send a specific parameter as a filter, we will configure the Dashboard to take that item that was sent from the Map Gadget, and pass it to the bar chart gadget.

To do this, we will use the **Datalink.** You can access it from its corresponding button, in the upper right of the screen.

> Macro (inline-media-image)

You will then be shown a window, where you will define what connects to what and from what. The data to be entered are:

- <u>**Source Gadget:**</u> the Gadget from which the data will start. In this case it will be that of the map.
- <u>**Source Field:**</u> taken from the DataSource, through which it will connect.
- <u>**Target Gadget:**</u> the Gadget that will receive the data, which will be here the bar chart.
- <u>**Target Field:**</u> taken again from the DataSource, through which it will be connected.

![image](media://0fba95bf-d234-469b-8cde-12eb5050a3ce)

Once the connection elements are defined, click the **(+)** button to generate the filter.

The next step is to enter a number of code lines in the Viewer Gadget. In the future, this will be transparent to the user, but for now it is necessary to do it manually.

Firstly, the Viewer Gadget must be edited. This will be done using the Edit button of that Gadget:

![image](media://41adcc65-013d-4e2b-aeca-039179acb160)

A new screen will appear where you can **edit the Gadget**. In it, there are two code screens: one from HTML on the left, and another from JavaScript on the right. In the latter, the following code must be entered:

##### **JS code to be added**

```javascript
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() {}


```

  


![image](media://b71a6fa2-1c97-4841-be2a-63509ad17b29)

When done, click on the **Compile & Synchronize** button, and the editing window can be closed. Then, save the Dashboard to save the changes.

![image](media://85bec2a0-4dd9-46fb-9c55-5ca305937550)

  


The next step will be to test the map and see whether everything that has been done so far indeed works or not.

![image](media://b97e185c-14a9-426a-9b83-35aa9dbe6f9c)

Does it work as it should? Then, that's good news: The Dashboard is ready, and this tutorial is over. Otherwise, check that you have followed all the steps correctly and nothing has been omitted. If there is still something wrong, leave us a comment.

We hope you found this useful.

# Styling

The design part is not something originally intended to be seen in this tutorial, but aiming to leave the Dashboard a little better, we will give some style to the used gadgets.

Both for one and the other, to access the style settings, click on the **Styling** button in the drop-down menu of the Gadget.

![image](media://5dc543d2-d8cd-4c78-b1bf-8c9d295609b3)

A style editing window will appear. There you can choose among several parameters, such as the text of the Gadget box, the font color, the icon, etc. For this example, the following properties have been used:

![image](media://e15cfd02-87c4-469f-9e5d-a3cdecc7b85b)

The result is quite nice.

![image](media://17c56278-49f4-41d3-b221-3f9cc72ba7ee)