@kalisio/kdk 2.1.9 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/.travis.test.sh +42 -10
  2. package/README.md +2 -2
  3. package/core/api/application.js +6 -1
  4. package/core/api/authentication.js +17 -1
  5. package/core/api/db.js +7 -2
  6. package/core/api/hooks/hooks.authentication.js +4 -2
  7. package/core/api/hooks/hooks.authorisations.js +12 -2
  8. package/core/api/hooks/hooks.model.js +5 -5
  9. package/core/api/hooks/hooks.organisations.js +0 -4
  10. package/core/api/services/account/account.hooks.js +10 -6
  11. package/core/api/services/account/account.service.js +1 -1
  12. package/{map/api/services/geocoder/geocoder.hooks.js → core/api/services/import-export/import-export.hooks.js} +7 -5
  13. package/core/api/services/import-export/import-export.service.js +11 -0
  14. package/core/api/services/index.js +13 -1
  15. package/core/api/services/users/users.hooks.js +2 -3
  16. package/core/client/api.js +16 -14
  17. package/core/client/capabilities.js +6 -2
  18. package/core/client/components/KContent.vue +11 -1
  19. package/core/client/components/KDialog.vue +17 -15
  20. package/core/client/components/KSponsor.vue +1 -1
  21. package/core/client/components/KTextArea.vue +5 -1
  22. package/core/client/components/app/KAbout.vue +1 -2
  23. package/core/client/components/app/KWelcome.vue +3 -5
  24. package/core/client/components/chart/KTimeSeriesChart.vue +24 -37
  25. package/core/client/components/collection/KColumn.vue +20 -17
  26. package/core/client/components/editor/KModalEditor.vue +0 -2
  27. package/core/client/components/form/KChipsField.vue +12 -2
  28. package/core/client/components/form/KColorField.vue +12 -2
  29. package/core/client/components/form/KColorScaleField.vue +12 -2
  30. package/core/client/components/form/KDateTimeRangeField.vue +12 -2
  31. package/core/client/components/form/KDatetimeField.vue +12 -2
  32. package/core/client/components/form/KEmailField.vue +12 -2
  33. package/core/client/components/form/KFileField.vue +12 -2
  34. package/core/client/components/form/KForm.vue +43 -9
  35. package/core/client/components/form/KIconField.vue +12 -2
  36. package/core/client/components/form/KItemField.vue +25 -4
  37. package/core/client/components/form/KNumberField.vue +12 -2
  38. package/core/client/components/form/KOptionsField.vue +12 -2
  39. package/core/client/components/form/KPasswordField.vue +12 -2
  40. package/core/client/components/form/KPhoneField.vue +13 -3
  41. package/core/client/components/form/KPropertyItemField.vue +12 -2
  42. package/core/client/components/form/KResolutionField.vue +126 -0
  43. package/core/client/components/form/KRoleField.vue +12 -2
  44. package/core/client/components/form/KSelectField.vue +14 -4
  45. package/core/client/components/form/KTextField.vue +12 -2
  46. package/core/client/components/form/KTextareaField.vue +13 -3
  47. package/core/client/components/form/KToggleField.vue +12 -2
  48. package/core/client/components/form/KTokenField.vue +12 -2
  49. package/core/client/components/form/KUnitField.vue +12 -2
  50. package/core/client/components/form/KUrlField.vue +12 -2
  51. package/core/client/components/input/KIconChooser.vue +10 -12
  52. package/core/client/components/input/KPalette.vue +2 -1
  53. package/core/client/components/layout/KPage.vue +5 -4
  54. package/core/client/components/layout/KWindow.vue +10 -10
  55. package/core/client/components/media/KColorScale.vue +26 -20
  56. package/core/client/components/media/KImageViewer.vue +57 -33
  57. package/core/client/components/media/KShape.vue +14 -103
  58. package/core/client/components/screen/KRegisterScreen.vue +0 -1
  59. package/core/client/components/screen/KScreenFooter.vue +0 -18
  60. package/core/client/components/team/KAddMember.vue +16 -22
  61. package/core/client/components/team/KGroupsActivity.vue +14 -0
  62. package/core/client/components/team/KMembersActivity.vue +12 -0
  63. package/core/client/components/team/KTagsActivity.vue +14 -0
  64. package/core/client/components/time/KDateTime.vue +23 -7
  65. package/core/client/components/time/KTimeControl.vue +142 -0
  66. package/core/client/components/tool/KExportTool.vue +57 -0
  67. package/core/client/composables/collection.js +0 -1
  68. package/core/client/composables/pwa.js +0 -1
  69. package/core/client/composables/schema.js +1 -1
  70. package/core/client/composables/session.js +30 -6
  71. package/core/client/exporter.js +141 -0
  72. package/core/client/i18n/core_en.json +91 -23
  73. package/core/client/i18n/core_fr.json +92 -23
  74. package/core/client/index.js +3 -0
  75. package/core/client/layout.js +34 -14
  76. package/core/client/local-storage.js +8 -6
  77. package/core/client/mixins/index.js +0 -1
  78. package/core/client/mixins/mixin.base-field.js +24 -2
  79. package/core/client/mixins/mixin.object-proxy.js +0 -1
  80. package/core/client/search.js +2 -1
  81. package/core/client/services/index.js +2 -1
  82. package/core/client/services/local-settings.service.js +4 -4
  83. package/core/client/theme.js +3 -3
  84. package/core/client/time.js +4 -0
  85. package/core/client/units.js +149 -4
  86. package/core/client/utils/index.js +13 -6
  87. package/core/client/utils/utils.account.js +1 -1
  88. package/core/client/utils/utils.colors.js +43 -0
  89. package/core/client/utils/utils.platform.js +0 -1
  90. package/core/client/utils/utils.pwa.js +14 -14
  91. package/core/client/utils/utils.session.js +1 -1
  92. package/core/client/utils/utils.shapes.js +270 -0
  93. package/core/client/utils/utils.time.js +37 -0
  94. package/core/common/permissions.js +3 -0
  95. package/core/common/schemas/settings.update.json +50 -29
  96. package/extras/css/core.variables.scss +3 -1
  97. package/extras/tours/map/navigation-bar.js +17 -15
  98. package/extras/tours/map/timeline.js +33 -33
  99. package/map/api/config/categories.cjs +4 -1
  100. package/map/api/hooks/hooks.catalog.js +39 -0
  101. package/map/api/hooks/hooks.features.js +23 -3
  102. package/map/api/hooks/hooks.query.js +31 -10
  103. package/map/api/models/projects.model.mongodb.js +8 -0
  104. package/map/api/services/catalog/catalog.hooks.js +5 -3
  105. package/map/api/services/features/features.hooks.js +18 -6
  106. package/map/api/services/index.js +22 -6
  107. package/map/api/services/projects/projects.hooks.js +118 -0
  108. package/map/client/capture.js +16 -0
  109. package/map/client/cesium/utils/index.js +3 -0
  110. package/map/client/cesium/utils/utils.events.js +30 -0
  111. package/map/client/cesium/utils/utils.popup.js +17 -0
  112. package/map/client/cesium/{utils.js → utils/utils.style.js} +53 -49
  113. package/map/client/components/KCapture.vue +50 -0
  114. package/map/client/components/KCaptureTextArea.vue +53 -0
  115. package/map/client/components/KCompass.vue +2 -2
  116. package/map/client/components/KFeaturesChart.vue +1 -1
  117. package/map/client/components/KFeaturesFilter.vue +2 -2
  118. package/map/client/components/KLayerStyleForm.vue +256 -430
  119. package/map/client/components/KLevelSlider.vue +1 -1
  120. package/map/client/components/KNorth.vue +31 -0
  121. package/map/client/components/KProjectMenu.vue +88 -0
  122. package/map/client/components/KTimezoneMap.vue +36 -23
  123. package/map/client/components/catalog/KAddLayer.vue +3 -4
  124. package/map/client/components/catalog/KConnectLayer.vue +16 -4
  125. package/map/client/components/catalog/KCreateLayer.vue +1 -2
  126. package/map/client/components/catalog/KCreateProject.vue +100 -0
  127. package/map/client/components/catalog/KCreateView.vue +25 -2
  128. package/map/client/components/catalog/KLayersPanel.vue +24 -27
  129. package/map/client/components/catalog/KLayersSelector.vue +1 -1
  130. package/map/client/components/catalog/KProjectEditor.vue +91 -0
  131. package/map/client/components/catalog/KProjectManager.vue +60 -0
  132. package/map/client/components/catalog/KProjectSelector.vue +38 -0
  133. package/map/client/components/catalog/KProjectsPanel.vue +153 -0
  134. package/map/client/components/catalog/KSelectLayers.vue +96 -0
  135. package/map/client/components/catalog/KSelectViews.vue +96 -0
  136. package/map/client/components/catalog/KViewsPanel.vue +66 -30
  137. package/map/client/components/form/KDirectionField.vue +24 -5
  138. package/map/client/components/form/KLayerCategoryField.vue +12 -2
  139. package/map/client/components/form/KLocationField.vue +20 -5
  140. package/map/client/components/form/KOwsLayerField.vue +12 -2
  141. package/map/client/components/form/KOwsServiceField.vue +12 -2
  142. package/map/client/components/form/KSelectLayersField.vue +159 -0
  143. package/map/client/components/form/KSelectViewsField.vue +121 -0
  144. package/map/client/components/form/KTimezoneField.vue +24 -17
  145. package/map/client/components/legend/KColorScaleLegend.vue +1 -1
  146. package/map/client/components/legend/KLayerLegend.vue +61 -0
  147. package/map/client/components/legend/KLegend.vue +45 -44
  148. package/map/client/components/legend/KLegendRenderer.vue +5 -3
  149. package/map/client/components/legend/KSymbolsLegend.vue +12 -10
  150. package/map/client/components/legend/KVariablesLegend.vue +78 -0
  151. package/map/client/components/location/KGeocodersFilter.vue +2 -4
  152. package/map/client/components/location/KLocationMap.vue +48 -17
  153. package/map/client/components/location/KLocationSearch.vue +13 -3
  154. package/map/client/components/tools/KSearchTool.vue +17 -12
  155. package/map/client/components/widget/KElevationProfile.vue +16 -19
  156. package/map/client/components/widget/KMapillaryViewer.vue +21 -22
  157. package/map/client/components/widget/KTimeSeries.vue +35 -23
  158. package/map/client/composables/activity.js +15 -2
  159. package/map/client/composables/catalog.js +66 -0
  160. package/map/client/composables/highlight.js +56 -20
  161. package/map/client/composables/index.js +2 -0
  162. package/map/client/composables/location.js +25 -18
  163. package/map/client/composables/project.js +122 -0
  164. package/map/client/geolocation.js +1 -1
  165. package/map/client/globe.js +2 -0
  166. package/map/client/i18n/map_en.json +123 -76
  167. package/map/client/i18n/map_fr.json +124 -72
  168. package/map/client/index.js +3 -0
  169. package/map/client/init.js +17 -0
  170. package/map/client/leaflet/GSMaPLayer.js +16 -17
  171. package/map/client/leaflet/ShapeMarker.js +40 -0
  172. package/map/client/leaflet/TiledFeatureLayer.js +1 -1
  173. package/map/client/leaflet/TiledMeshLayer.js +11 -15
  174. package/map/client/leaflet/TiledWindLayer.js +6 -10
  175. package/map/client/leaflet/utils/index.js +4 -0
  176. package/map/client/leaflet/utils/utils.events.js +41 -0
  177. package/map/client/leaflet/utils/utils.popup.js +21 -0
  178. package/map/client/leaflet/utils/utils.style.js +191 -0
  179. package/map/client/leaflet/utils/utils.tiles.js +87 -0
  180. package/map/client/map.js +2 -0
  181. package/map/client/mixins/globe/mixin.base-globe.js +29 -21
  182. package/map/client/mixins/globe/mixin.geojson-layers.js +132 -69
  183. package/map/client/mixins/globe/mixin.popup.js +2 -1
  184. package/map/client/mixins/globe/mixin.style.js +6 -4
  185. package/map/client/mixins/globe/mixin.tooltip.js +8 -3
  186. package/map/client/mixins/map/mixin.base-map.js +13 -11
  187. package/map/client/mixins/map/mixin.edit-layers.js +15 -15
  188. package/map/client/mixins/map/mixin.forecast-layers.js +3 -1
  189. package/map/client/mixins/map/mixin.geojson-layers.js +56 -20
  190. package/map/client/mixins/map/mixin.georaster-layers.js +4 -11
  191. package/map/client/mixins/map/mixin.heatmap-layers.js +1 -1
  192. package/map/client/mixins/map/mixin.popup.js +2 -1
  193. package/map/client/mixins/map/mixin.style.js +4 -67
  194. package/map/client/mixins/map/mixin.tiled-mesh-layers.js +2 -1
  195. package/map/client/mixins/map/mixin.tiled-wind-layers.js +4 -2
  196. package/map/client/mixins/map/mixin.tooltip.js +2 -1
  197. package/map/client/mixins/mixin.activity.js +66 -191
  198. package/map/client/mixins/mixin.catalog-panel.js +6 -6
  199. package/map/client/mixins/mixin.context.js +12 -9
  200. package/map/client/mixins/mixin.feature-service.js +29 -300
  201. package/map/client/mixins/mixin.weacast.js +11 -17
  202. package/map/client/pixi-utils.js +1 -1
  203. package/map/client/planets.js +58 -0
  204. package/map/client/utils/index.js +6 -0
  205. package/map/client/utils/utils.capture.js +176 -0
  206. package/map/client/utils/utils.catalog.js +149 -0
  207. package/map/client/utils/utils.features.js +364 -0
  208. package/map/client/utils/utils.js +0 -151
  209. package/map/client/utils/utils.layers.js +174 -0
  210. package/map/client/utils/utils.location.js +91 -23
  211. package/map/client/utils/utils.project.js +8 -0
  212. package/map/client/utils/utils.schema.js +0 -1
  213. package/map/client/utils/utils.style.js +297 -0
  214. package/map/client/utils.all.js +2 -2
  215. package/map/client/utils.globe.js +1 -1
  216. package/map/client/utils.map.js +1 -1
  217. package/map/common/permissions.js +2 -0
  218. package/map/common/schemas/capture.create.json +132 -0
  219. package/map/common/schemas/projects.create.json +52 -0
  220. package/map/common/schemas/projects.update.json +52 -0
  221. package/package.json +6 -5
  222. package/test/api/core/account.test.js +20 -0
  223. package/test/api/core/config/default.cjs +16 -3
  224. package/test/api/core/import-export.test.js +86 -0
  225. package/test/api/core/test-log-2024-01-04.log +14 -0
  226. package/test/api/map/catalog.test.js +164 -0
  227. package/test/api/map/index.test.js +25 -61
  228. package/test/api/map/test-log-2024-01-04.log +2 -0
  229. package/test/api/map/test-log-2024-01-11.log +1 -0
  230. package/test/api/map/test-log-2024-01-25.log +19 -0
  231. package/test/client/core/layout.js +25 -5
  232. package/test/client/core/utils.js +7 -0
  233. package/test/client/map/catalog.js +78 -1
  234. package/test/client/map/time.js +2 -1
  235. package/core/client/components/screen/KEndpointScreen.vue +0 -80
  236. package/core/client/mixins/mixin.account.js +0 -61
  237. package/extras/icons/kdk.png +0 -0
  238. package/map/api/services/geocoder/geocoder.service.js +0 -79
  239. package/map/client/components/KCaptureToolbar.vue +0 -155
  240. package/map/client/components/KColorLegend.vue +0 -349
  241. package/map/client/components/KTimeline.vue +0 -293
  242. package/map/client/components/KUrlLegend.vue +0 -122
  243. package/map/client/leaflet/utils.js +0 -246
@@ -1,25 +1,75 @@
1
1
  import Cesium from 'cesium/Source/Cesium.js'
2
2
  import _ from 'lodash'
3
+ import logger from 'loglevel'
3
4
  import sift from 'sift'
4
5
  import { Time } from '../../../../core/client/time.js'
5
- import { fetchGeoJson, getFeatureId } from '../../utils.js'
6
+ import { fetchGeoJson, getFeatureId, processFeatures, getFeatureStyleType, isInMemoryLayer } from '../../utils.js'
7
+ import { convertSimpleStyleToPointStyle, convertSimpleStyleToLineStyle, convertSimpleStyleToPolygonStyle } from '../../utils/utils.style.js'
8
+ import { convertToCesiumFromSimpleStyle, getPointSimpleStyle, getLineSimpleStyle, getPolygonSimpleStyle } from '../../cesium/utils/utils.style.js'
9
+
10
+ function getWallEntityId (id) {
11
+ return id + '-wall'
12
+ }
13
+
14
+ function updateGeoJsonEntity(source, destination) {
15
+ destination.position = source.position
16
+ destination.orientation = source.orientation
17
+ destination.properties = source.properties
18
+ destination.description = source.description
19
+ // Points
20
+ if (source.billboard) destination.billboard = source.billboard
21
+ // Lines
22
+ if (source.polyline) destination.polyline = source.polyline
23
+ // Polygons
24
+ if (source.polygon) destination.polygon = source.polygon
25
+ }
6
26
 
7
27
  export const geojsonLayers = {
8
28
  methods: {
9
- convertFromSimpleStyleSpecOrDefaults (properties) {
10
- let { stroke, strokeWidth, fill } = this.convertFromSimpleStyleSpec(properties)
29
+ convertFromSimpleStyleOrDefaults (properties) {
30
+ let { stroke, strokeWidth, fill } = convertToCesiumFromSimpleStyle(properties)
11
31
  if (!stroke) stroke = Cesium.GeoJsonDataSource.stroke
12
32
  if (!strokeWidth) strokeWidth = Cesium.GeoJsonDataSource.strokeWidth
13
33
  if (!fill) fill = Cesium.GeoJsonDataSource.fill
14
34
  return { stroke, strokeWidth, fill }
15
35
  },
16
- async loadGeoJson (dataSource, geoJson, cesiumOptions) {
17
- // Clean any previous data as otherwise it seems
18
- // data is not correctly updated in viewer
19
- dataSource.entities.removeAll()
20
- await dataSource.load(geoJson, cesiumOptions)
36
+ async loadGeoJson (dataSource, geoJson, options, updateOptions = {}) {
37
+ const cesiumOptions = options.cesium
38
+ // Remove mode
39
+ if (_.get(updateOptions, 'remove', false)) {
40
+ let features = (geoJson.type === 'FeatureCollection' ? geoJson.features : [geoJson])
41
+ features.forEach(feature => {
42
+ const id = getFeatureId(feature, options)
43
+ const wallId = getWallEntityId(id)
44
+ if (dataSource.entities.getById(id)) dataSource.entities.removeById(id)
45
+ // Take care that in case of a wall entity we add it in addition to the original line
46
+ if (dataSource.entities.getById(wallId)) dataSource.entities.removeById(wallId)
47
+ })
48
+ return
49
+ }
50
+ // We use a separated source in order to load data otherwise Cesium will replace previous ones, causing flickering
51
+ const loadingDataSource = new Cesium.GeoJsonDataSource()
52
+ loadingDataSource.notFromDrop = true
53
+ await loadingDataSource.load(geoJson, cesiumOptions)
54
+ // Now we process loaded entities to merge with existing ones if any or add new ones
55
+ let entities = loadingDataSource.entities.values
56
+ entities.forEach(entity => {
57
+ const previousEntity = dataSource.entities.getById(entity.id)
58
+ if (previousEntity) updateGeoJsonEntity(entity, previousEntity)
59
+ else dataSource.entities.add(entity)
60
+ })
61
+ // Remove any entity not existing anymore
62
+ if (_.get(updateOptions, 'removeMissing', cesiumOptions.removeMissing)) {
63
+ dataSource.entities.values.forEach(entity => {
64
+ const id = entity.id
65
+ const wallId = getWallEntityId(id)
66
+ if (!loadingDataSource.entities.getById(id)) dataSource.entities.removeById(id)
67
+ // Take care that in case of a wall entity we add it in addition to the original line
68
+ if (dataSource.entities.getById(wallId)) dataSource.entities.removeById(wallId)
69
+ })
70
+ }
21
71
  // Process specific entities
22
- const entities = dataSource.entities.values
72
+ entities = dataSource.entities.values
23
73
  const entitiesToAdd = []
24
74
  const entitiesToRemove = []
25
75
  for (let i = 0; i < entities.length; i++) {
@@ -29,7 +79,7 @@ export const geojsonLayers = {
29
79
  const radius = _.get(properties, 'radius')
30
80
  const geodesic = _.get(properties, 'geodesic')
31
81
  if (radius && geodesic) {
32
- const { stroke, strokeWidth, fill } = this.convertFromSimpleStyleSpecOrDefaults(properties)
82
+ const { stroke, strokeWidth, fill } = this.convertFromSimpleStyleOrDefaults(properties)
33
83
  // This one will replace the original point
34
84
  entitiesToAdd.push({
35
85
  id: entity.id,
@@ -51,13 +101,14 @@ export const geojsonLayers = {
51
101
  // Walls
52
102
  const wall = _.get(properties, 'wall')
53
103
  if (wall && entity.polyline) {
54
- const { stroke, strokeWidth, fill } = this.convertFromSimpleStyleSpecOrDefaults(properties)
104
+ const { stroke, strokeWidth, fill } = this.convertFromSimpleStyleOrDefaults(properties)
55
105
  // Simply push the entity, other options like font will be set using styling options
56
106
  // This one will come in addition to the original line
107
+ const wallId = getWallEntityId(entity.id)
57
108
  entitiesToAdd.push({
58
- id: entity.id + '-wall',
109
+ id: wallId,
59
110
  parent: entity,
60
- name: entity.name,
111
+ name: entity.name ? entity.name : wallId,
61
112
  description: entity.description.getValue(0),
62
113
  properties: entity.properties.getValue(0),
63
114
  wall: {
@@ -72,13 +123,13 @@ export const geojsonLayers = {
72
123
  // Labels
73
124
  const text = _.get(properties, 'icon-text')
74
125
  if (text) {
75
- const { stroke, strokeWidth, fill } = this.convertFromSimpleStyleSpecOrDefaults(properties)
126
+ const { stroke, strokeWidth, fill } = this.convertFromSimpleStyleOrDefaults(properties)
76
127
  // Simply push the entity, other options like font will be set using styling options
77
128
  // This one will replace the original point
78
129
  entitiesToAdd.push({
79
130
  id: entity.id,
80
131
  position: entity.position.getValue(0),
81
- name: entity.name,
132
+ name: entity.name ? entity.name : entity.id,
82
133
  description: entity.description.getValue(0),
83
134
  properties: entity.properties.getValue(0),
84
135
  label: {
@@ -94,52 +145,46 @@ export const geojsonLayers = {
94
145
  entitiesToRemove.forEach(entity => dataSource.entities.remove(entity))
95
146
  entitiesToAdd.forEach(entity => dataSource.entities.add(entity))
96
147
  },
97
- async updateGeoJsonData (dataSource, options, geoJson) {
148
+ async updateGeoJsonData (dataSource, options, geoJson, updateOptions = {}) {
149
+ // As we have async operations during the whole whole loading process avoid reentrance
150
+ // otherwise we might have interleaved calls leading to doublon entities being created
151
+ //if (dataSource.updatingGeoJsonData) return
152
+ //dataSource.updatingGeoJsonData = true
98
153
  const cesiumOptions = options.cesium
99
154
  const source = _.get(cesiumOptions, 'source')
100
155
  const sourceTemplate = _.get(cesiumOptions, 'sourceTemplate')
101
- // Update function to fetch for new data and update Cesium data source
102
- if (options.probeService) {
103
- // If the probe location is given by another service use it on initialization
104
- if (dataSource.entities.values.length === 0) {
105
- await this.loadGeoJson(dataSource, this.getProbeFeatures(options), cesiumOptions)
106
- }
107
- // Then get last available measures
108
- const measureSource = new Cesium.GeoJsonDataSource()
109
- await this.loadGeoJson(measureSource, this.getFeatures(options), cesiumOptions)
110
- // Then merge with probes
111
- const probes = dataSource.entities.values
112
- for (let i = 0; i < probes.length; i++) {
113
- const probe = probes[i]
114
- const measure = measureSource.entities.getById(probe.id)
115
- if (measure) {
116
- probe.properties = measure.properties
117
- probe.description = measure.description
156
+ try {
157
+ if (geoJson) {
158
+ if (options.processor) processFeatures(geoJson, options.processor)
159
+ await this.loadGeoJson(dataSource, geoJson, options, updateOptions)
160
+ } else if (options.probeService) {
161
+ await this.loadGeoJson(dataSource, this.getProbeFeatures(options), options, updateOptions)
162
+ await this.loadGeoJson(dataSource, this.getFeatures(options), options, updateOptions)
163
+ } else if (options.service) { // Check for feature service layers only, in this case update in place
164
+ // If no probe reference, nothing to be initialized
165
+ await this.loadGeoJson(dataSource, this.getFeatures(options), options, updateOptions)
166
+ } else if (sourceTemplate) {
167
+ const sourceToFetch = dataSource.sourceCompiler({ time: Time.getCurrentTime() })
168
+ if (!dataSource.lastFetchedSource || (dataSource.lastFetchedSource !== sourceToFetch)) {
169
+ dataSource.lastFetchedSource = sourceToFetch
170
+ await this.loadGeoJson(dataSource, fetchGeoJson(sourceToFetch, options), options, updateOptions)
118
171
  }
172
+ } else if (!_.isNil(source)) {
173
+ // Assume source is an URL returning GeoJson
174
+ await this.loadGeoJson(dataSource, fetchGeoJson(source, options), options, updateOptions)
119
175
  }
120
- } else if (options.service) { // Check for feature service layers only, in this case update in place
121
- // If no probe reference, nothing to be initialized
122
- await this.loadGeoJson(dataSource, this.getFeatures(options), cesiumOptions)
123
- } else if (geoJson) {
124
- await this.loadGeoJson(dataSource, geoJson, cesiumOptions)
125
- } else if (sourceTemplate) {
126
- const sourceToFetch = dataSource.sourceCompiler({ time: Time.getCurrentTime() })
127
- if (!dataSource.lastFetchedSource || (dataSource.lastFetchedSource !== sourceToFetch)) {
128
- dataSource.lastFetchedSource = sourceToFetch
129
- await this.loadGeoJson(dataSource, fetchGeoJson(sourceToFetch, options), cesiumOptions)
130
- }
131
- } else if (!_.isNil(source)) {
132
- // Assume source is an URL returning GeoJson
133
- await this.loadGeoJson(dataSource, fetchGeoJson(source, options), cesiumOptions)
176
+ this.applyStyle(dataSource.entities, options)
177
+ if (typeof this.applyTooltips === 'function') this.applyTooltips(dataSource.entities, options)
178
+ } catch (error) {
179
+ logger.error(error)
134
180
  }
135
- this.applyStyle(dataSource.entities, options)
136
- if (typeof this.applyTooltips === 'function') this.applyTooltips(dataSource.entities, options)
181
+ //delete dataSource.updatingGeoJsonData
137
182
  },
138
183
  async createCesiumRealtimeGeoJsonLayer (dataSource, options) {
139
184
  const cesiumOptions = options.cesium
140
185
  // Add update capabilities
141
- dataSource.updateGeoJson = async (geoJson) => {
142
- await this.updateGeoJsonData(dataSource, options, geoJson)
186
+ dataSource.updateGeoJson = async (geoJson, updateOptions) => {
187
+ await this.updateGeoJsonData(dataSource, options, geoJson, updateOptions)
143
188
  }
144
189
  // Add source compiler if required
145
190
  if (_.has(cesiumOptions, 'sourceTemplate')) {
@@ -150,22 +195,34 @@ export const geojsonLayers = {
150
195
  const cesiumOptions = options.cesium
151
196
  // Check for valid type
152
197
  if (cesiumOptions.type !== 'geoJson') return
153
- // Cesium expect id to be in a 'id' property
198
+ const engine = _.get(this, 'activityOptions.engine')
154
199
  options.processor = (feature) => {
200
+ // Cesium expect id to be in a 'id' property
155
201
  feature.id = getFeatureId(feature, options)
202
+ // We cannot access data outside the properties object of a feature in Cesium
203
+ // As a consequence we copy back any style information inside
204
+ const styleType = getFeatureStyleType(feature)
205
+ // We need to convert to simple-style spec as cesium manages this only
206
+ let simpleStyle
207
+ if (styleType === 'point') simpleStyle = getPointSimpleStyle(feature, options, engine)
208
+ else if (styleType === 'line') simpleStyle = getLineSimpleStyle(feature, options, engine)
209
+ else simpleStyle = getPolygonSimpleStyle(feature, options, engine)
210
+ if (!feature.properties) feature.properties = simpleStyle
211
+ else Object.assign(feature.properties, simpleStyle)
156
212
  }
157
213
  // For activities
158
214
  if (_.has(this, 'activityOptions.engine.cluster')) {
159
215
  if (cesiumOptions.cluster) Object.assign(cesiumOptions.cluster, _.get(this, 'activityOptions.engine.cluster'))
160
216
  else cesiumOptions.cluster = Object.assign({}, _.get(this, 'activityOptions.engine.cluster'))
161
217
  }
162
- // Merge generic GeoJson options and layer options
163
- const geoJsonOptions = this.getGeoJsonOptions(options)
164
- Object.keys(geoJsonOptions).forEach(key => {
165
- // If layer provided do not override
166
- if (!_.has(cesiumOptions, key)) _.set(cesiumOptions, key, geoJsonOptions[key])
167
- })
168
218
  // Optimize templating by creating compilers up-front
219
+ const layerStyleTemplate = _.get(cesiumOptions, 'template')
220
+ if (layerStyleTemplate) {
221
+ // We allow to template style properties according to feature, because it can be slow you have to specify a subset of properties
222
+ cesiumOptions.template = layerStyleTemplate.map(property => ({
223
+ property, compiler: _.template(_.get(cesiumOptions, property))
224
+ }))
225
+ }
169
226
  const entityStyleTemplate = _.get(cesiumOptions, 'entityStyle.template')
170
227
  if (entityStyleTemplate) {
171
228
  // We allow to template style properties according to feature, because it can be slow you have to specify a subset of properties
@@ -181,7 +238,16 @@ export const geojsonLayers = {
181
238
  if (tooltipTemplate) {
182
239
  cesiumOptions.tooltip.compiler = _.template(tooltipTemplate)
183
240
  }
184
- this.convertFromSimpleStyleSpec(cesiumOptions, 'update-in-place')
241
+ // Convert and store the style
242
+ if (cesiumOptions.style) {
243
+ cesiumOptions.layerPointStyle = _.get(cesiumOptions.style, 'point')
244
+ cesiumOptions.layerLineStyle = _.get(cesiumOptions.style, 'line')
245
+ cesiumOptions.layerPolygonStyle = _.get(cesiumOptions.style, 'polygon')
246
+ } else {
247
+ cesiumOptions.layerPointStyle = convertSimpleStyleToPointStyle(cesiumOptions)
248
+ cesiumOptions.layerLineStyle = convertSimpleStyleToLineStyle(cesiumOptions)
249
+ cesiumOptions.layerPolygonStyle = convertSimpleStyleToPolygonStyle(cesiumOptions)
250
+ }
185
251
  // Perform required conversion from JSON to Cesium objects
186
252
  // If templating occurs we need to wait until it is performed to convert to Cesium objects
187
253
  if (cesiumOptions.entityStyle && !entityStyleTemplate) cesiumOptions.entityStyle = this.convertToCesiumObjects(cesiumOptions.entityStyle)
@@ -236,17 +302,17 @@ export const geojsonLayers = {
236
302
  getGeoJsonOptions (options) {
237
303
  return _.get(this, 'activityOptions.engine.featureStyle', {})
238
304
  },
239
- async updateLayer (name, geoJson) {
305
+ async updateLayer (name, geoJson, updateOptions = {}) {
240
306
  // Retrieve the layer
241
307
  const layer = this.getCesiumLayerByName(name)
242
308
  if (!layer) return // Cannot update invisible layer
243
- if (typeof layer.updateGeoJson === 'function') layer.updateGeoJson(geoJson)
309
+ if (typeof layer.updateGeoJson === 'function') layer.updateGeoJson(geoJson, updateOptions)
244
310
 
245
311
  // We keep geojson data for in memory layer in a cache since
246
312
  // these layers will be destroyed when hidden. We need to be able to restore
247
313
  // them when they get shown again
248
314
  const baseLayer = this.getLayerByName(name)
249
- if (this.isInMemoryLayer(baseLayer)) {
315
+ if (isInMemoryLayer(baseLayer)) {
250
316
  this.geojsonCache[name] = geoJson
251
317
  }
252
318
  },
@@ -274,7 +340,7 @@ export const geojsonLayers = {
274
340
  // Check if we have cached geojson data for this layer
275
341
  const cachedGeojson = this.geojsonCache[layer.name]
276
342
  if (cachedGeojson) {
277
- if (this.isInMemoryLayer(layer)) {
343
+ if (isInMemoryLayer(layer)) {
278
344
  // Restore geojson data for in-memory layers that was hidden
279
345
  this.updateLayer(layer.name, cachedGeojson)
280
346
  } else {
@@ -292,15 +358,12 @@ export const geojsonLayers = {
292
358
  },
293
359
  created () {
294
360
  this.registerCesiumConstructor(this.createCesiumGeoJsonLayer)
295
- // Perform required conversion from JSON to Cesium objects
296
- if (_.has(this, 'activityOptions.engine.featureStyle')) {
297
- Object.assign(Cesium.GeoJsonDataSource,
298
- this.convertFromSimpleStyleSpec(_.get(this, 'activityOptions.engine.featureStyle'), 'update-in-place'))
299
- }
300
361
  this.$events.on('time-current-time-changed', this.onCurrentTimeChangedGeoJsonLayers)
301
362
  this.$engineEvents.on('layer-shown', this.onLayerShownGeoJsonLayers)
302
363
  this.$engineEvents.on('layer-removed', this.onLayerRemovedGeoJsonLayers)
303
-
364
+ // Map of currently updated layers to avoid reentrance with real-time events as
365
+ // we are not able to perform in place update and required to pull the data
366
+ this.updatingGeoJsonData = {}
304
367
  // Cache where we'll store geojson data for in memory layers we'll hide
305
368
  this.geojsonCache = {}
306
369
  },
@@ -1,4 +1,5 @@
1
1
  import _ from 'lodash'
2
+ import moment from 'moment'
2
3
  import { Time, Units } from '../../../../core/client/index.js'
3
4
  import { getTextTable } from '../../utils.globe.js'
4
5
 
@@ -23,7 +24,7 @@ export const popup = {
23
24
  if (popupStyle.template) {
24
25
  const compiler = popupStyle.compiler
25
26
  // FIXME: the whole feature is lost by Cesium so that top-level properties have disappeared
26
- text = compiler({ feature: { properties }, properties, $t: this.$t, Units, Time })
27
+ text = compiler({ feature: { properties }, properties, $t: this.$t, Units, Time, moment })
27
28
  } else if (popupStyle.pick) {
28
29
  properties = _.pick(properties, popupStyle.pick)
29
30
  } else if (popupStyle.omit) {
@@ -1,7 +1,9 @@
1
1
  import Cesium from 'cesium/Source/Cesium.js'
2
2
  import _ from 'lodash'
3
3
  import chroma from 'chroma-js'
4
- import { convertToCesiumFromSimpleStyleSpec, convertToCesiumObjects, CesiumStyleMappings, CesiumEntityTypes } from '../../utils.globe.js'
4
+ import moment from 'moment'
5
+ import { Time, Units } from '../../../../core/client/index.js'
6
+ import { convertToCesiumFromSimpleStyle, convertToCesiumObjects, CesiumEntityTypes } from '../../utils.globe.js'
5
7
 
6
8
  export const style = {
7
9
  methods: {
@@ -35,8 +37,8 @@ export const style = {
35
37
  })
36
38
  },
37
39
  // Alias to ease development
38
- convertFromSimpleStyleSpec (style, inPlace) {
39
- return convertToCesiumFromSimpleStyleSpec (style, inPlace)
40
+ convertFromSimpleStyle (style, inPlace) {
41
+ return convertToCesiumFromSimpleStyle(style, inPlace)
40
42
  },
41
43
  // Alias to ease development
42
44
  convertToCesiumObjects (style) {
@@ -53,7 +55,7 @@ export const style = {
53
55
  const entityStyle = _.cloneDeep(cesiumOptions.entityStyle)
54
56
  entityStyleTemplate.forEach(entry => {
55
57
  // Perform templating, set using simple spec mapping first then raw if property not found
56
- let value = entry.compiler({ properties, chroma })
58
+ let value = entry.compiler({ properties, chroma, moment, Units, Time })
57
59
  const property = entry.property
58
60
  // Handle specific case of orientation
59
61
  if ((property === 'orientation') && entity.position) {
@@ -1,4 +1,5 @@
1
1
  import _ from 'lodash'
2
+ import moment from 'moment'
2
3
  import { Time, Units } from '../../../../core/client/index.js'
3
4
 
4
5
  export const tooltip = {
@@ -36,7 +37,7 @@ export const tooltip = {
36
37
  } else if (tooltipStyle.template) {
37
38
  const compiler = tooltipStyle.compiler
38
39
  // FIXME: the whole feature is lost by Cesium so that top-level properties have disappeared
39
- text = compiler({ feature: { properties }, properties, $t: this.$t, Units, Time })
40
+ text = compiler({ feature: { properties }, properties, $t: this.$t, Units, Time, moment })
40
41
  }
41
42
  }
42
43
  if (text) {
@@ -67,8 +68,12 @@ export const tooltip = {
67
68
  }
68
69
  },
69
70
  onTooltip (options, event) {
70
- // Nothing to do in this case
71
- if (options && _.get(options, 'cesium.tooltip.permanent)')) return
71
+ if (options) {
72
+ const cesiumOptions = options.cesium || options
73
+ const tooltipStyle = cesiumOptions.tooltip
74
+ // Nothing to do in this case
75
+ if (_.get(tooltipStyle, 'options.permanent')) return
76
+ }
72
77
  // FIXME: show/hide tooltip
73
78
  const entity = event.target
74
79
  if (this.overEntity) {
@@ -5,8 +5,6 @@ import L from 'leaflet'
5
5
  import Emitter from 'tiny-emitter'
6
6
  import 'leaflet/dist/leaflet.css'
7
7
  // This ensure we have all required plugins
8
- import 'leaflet-fa-markers/L.Icon.FontAwesome.css'
9
- import 'leaflet-fa-markers/L.Icon.FontAwesome.js'
10
8
  import 'leaflet-fullscreen'
11
9
  import 'leaflet-fullscreen/dist/leaflet.fullscreen.css'
12
10
  import 'leaflet.markercluster/dist/MarkerCluster.css'
@@ -16,6 +14,8 @@ import '@kalisio/leaflet.donutcluster/src/Leaflet.DonutCluster.css'
16
14
  import '@kalisio/leaflet.donutcluster'
17
15
  import 'leaflet.vectorgrid/dist/Leaflet.VectorGrid.bundled.js'
18
16
  import 'leaflet.geodesic'
17
+ import '@kalisio/leaflet-graphicscale'
18
+ import '@kalisio/leaflet-graphicscale/dist/Leaflet.GraphicScale.min.css'
19
19
  import 'leaflet.locatecontrol'
20
20
  import 'leaflet.locatecontrol/dist/L.Control.Locate.css'
21
21
  import iso8601 from 'iso8601-js-period' // Required by leaflet.timedimension
@@ -46,10 +46,6 @@ L.Icon.Default.mergeOptions({
46
46
  // Do not create geoman structs everywhere
47
47
  L.PM.setOptIn(true)
48
48
 
49
- // FontAwesome markers do not register a createShadow() function
50
- // so that they are added two times to the map
51
- L.Icon.FontAwesome.prototype.createShadow = function () { return null }
52
-
53
49
  export const baseMap = {
54
50
  emits: [
55
51
  'map-ready',
@@ -91,17 +87,23 @@ export const baseMap = {
91
87
  this.map.pm.setLang(getAppLocale())
92
88
  }
93
89
  bindLeafletEvents(this.map, LeafletEvents.Map, this, viewerOptions)
94
- if (_.get(viewerOptions, 'scale', true)) this.setupScaleControl()
95
- if (_.get(viewerOptions, 'geolocate', true)) this.setupGeolocateControl()
90
+ const scale = _.get(viewerOptions, 'scale', true)
91
+ if (scale) this.setupScaleControl(scale)
92
+ const geolocate = _.get(viewerOptions, 'geolocate', true)
93
+ if (geolocate) this.setupGeolocateControl(geolocate)
96
94
  this.onMapReady()
97
95
  },
98
96
  onMapReady () {
99
97
  this.$emit('map-ready', 'leaflet')
100
98
  this.$engineEvents.emit('map-ready', 'leaflet')
101
99
  },
102
- setupScaleControl () {
103
- // Add a scale control
104
- this.scaleControl = new L.control.scale() // eslint-disable-line
100
+ setupScaleControl (options) {
101
+ // Add a basic or enhanced scale control
102
+ if (typeof options === 'object') {
103
+ this.scaleControl = new L.control.graphicScale(options)
104
+ } else {
105
+ this.scaleControl = new L.control.scale() // eslint-disable-line
106
+ }
105
107
  this.scaleControl.addTo(this.map)
106
108
  },
107
109
  setupGeolocateControl () {
@@ -2,7 +2,10 @@ import _ from 'lodash'
2
2
  import L from 'leaflet'
3
3
  import { getType, getGeom } from '@turf/invariant'
4
4
  import { Dialog, uid } from 'quasar'
5
- import { bindLeafletEvents, unbindLeafletEvents } from '../../utils.map.js'
5
+ import {
6
+ bindLeafletEvents, unbindLeafletEvents,
7
+ getDefaultPointStyle, getDefaultLineStyle, getDefaultPolygonStyle, createMarkerFromPointStyle
8
+ } from '../../utils.map.js'
6
9
 
7
10
  // Events we listen while layer is in edition mode
8
11
  const mapEditEvents = ['pm:create']
@@ -68,12 +71,19 @@ export const editLayers = {
68
71
  onEachFeature,
69
72
  // Use default styling when editing as dynamic styling can conflict
70
73
  style: (feature) => {
71
- return Object.assign({},
72
- _.get(this, 'activityOptions.engine.editFeatureStyle', _.get(this, 'activityOptions.engine.featureStyle')))
74
+ if (['LineString', 'MultiLineString'].includes(feature.geometry.type)) {
75
+ return getDefaultLineStyle(feature, null, _.get(this, 'activityOptions.engine'), 'style.edition.line')
76
+ }
77
+ if (['Polygon', 'MultiPolygon'].includes(feature.geometry.type)) {
78
+ return getDefaultPolygonStyle(feature, null, _.get(this, 'activityOptions.engine'), 'style.edition.polygon')
79
+ } else {
80
+ logger.warn(`[KDK] the geometry of type of ${feature.geometry.type} is not supported`)
81
+ }
73
82
  },
74
83
  pointToLayer: (feature, latlng) => {
75
- return this.createMarkerFromStyle(latlng, Object.assign({ pmIgnore: false }, // Allow geoman edition
76
- _.get(this, 'activityOptions.engine.editPointStyle', _.get(this, 'activityOptions.engine.pointStyle'))))
84
+ const style = getDefaultPointStyle(feature, null, _.get(this, 'activityOptions.engine'), 'style.edition.point')
85
+ style.options = { pmIgnore: false } // Allow geoman edition
86
+ return createMarkerFromPointStyle(latlng, style)
77
87
  }
78
88
  }
79
89
  },
@@ -479,15 +489,5 @@ export const editLayers = {
479
489
  },
480
490
  created () {
481
491
  this.pendingOperations = []
482
- },
483
- // Need to be done after created as the activity mixin initializes options in it
484
- beforeMount () {
485
- // Perform required conversion for default feature styling
486
- if (_.has(this, 'activityOptions.engine.editFeatureStyle')) {
487
- this.convertFromSimpleStyleSpec(_.get(this, 'activityOptions.engine.editFeatureStyle'), 'update-in-place')
488
- }
489
- if (_.has(this, 'activityOptions.engine.editPointStyle')) {
490
- this.convertFromSimpleStyleSpec(_.get(this, 'activityOptions.engine.editPointStyle'), 'update-in-place')
491
- }
492
492
  }
493
493
  }
@@ -45,8 +45,10 @@ export const forecastLayers = {
45
45
  const leafletOptions = options.leaflet || options
46
46
  // Check for valid types
47
47
  if (!leafletOptions.type.startsWith('weacast')) return
48
+ // Check API to be used in case the layer is coming from a remote "planet"
49
+ const weacastApi = (typeof options.getPlanetApi === 'function' ? options.getPlanetApi() : this.getWeacastApi())
48
50
  // We need to add Weacast API object as argument before creating the layer
49
- leafletOptions.source = this.weacastApi
51
+ leafletOptions.source = weacastApi
50
52
  // Copy as well color map options
51
53
  const colorMap = _.get(options, 'variables[0].chromajs')
52
54
  if (colorMap) Object.assign(leafletOptions, colorMap)