@kalisio/kdk 2.1.9 → 2.2.1

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 (272) hide show
  1. package/.travis.test.sh +42 -10
  2. package/README.md +2 -2
  3. package/core/api/application.js +7 -2
  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/KModal.vue +1 -1
  21. package/core/client/components/KSponsor.vue +1 -1
  22. package/core/client/components/KTextArea.vue +5 -1
  23. package/core/client/components/app/KAbout.vue +1 -2
  24. package/core/client/components/app/KWelcome.vue +3 -5
  25. package/core/client/components/chart/KTimeSeriesChart.vue +24 -37
  26. package/core/client/components/collection/KColumn.vue +20 -17
  27. package/core/client/components/editor/KModalEditor.vue +0 -2
  28. package/core/client/components/form/KChipsField.vue +12 -2
  29. package/core/client/components/form/KColorField.vue +12 -2
  30. package/core/client/components/form/KColorScaleField.vue +12 -2
  31. package/core/client/components/form/KDateTimeRangeField.vue +12 -2
  32. package/core/client/components/form/KDatetimeField.vue +12 -2
  33. package/core/client/components/form/KEmailField.vue +12 -2
  34. package/core/client/components/form/KFileField.vue +12 -2
  35. package/core/client/components/form/KForm.vue +47 -9
  36. package/core/client/components/form/KIconField.vue +12 -2
  37. package/core/client/components/form/KItemField.vue +25 -4
  38. package/core/client/components/form/KNumberField.vue +12 -2
  39. package/core/client/components/form/KOptionsField.vue +12 -2
  40. package/core/client/components/form/KPasswordField.vue +12 -2
  41. package/core/client/components/form/KPhoneField.vue +13 -3
  42. package/core/client/components/form/KPropertyItemField.vue +12 -2
  43. package/core/client/components/form/KResolutionField.vue +126 -0
  44. package/core/client/components/form/KRoleField.vue +12 -2
  45. package/core/client/components/form/KSelectField.vue +14 -4
  46. package/core/client/components/form/KTextField.vue +12 -2
  47. package/core/client/components/form/KTextareaField.vue +13 -3
  48. package/core/client/components/form/KToggleField.vue +12 -2
  49. package/core/client/components/form/KTokenField.vue +12 -2
  50. package/core/client/components/form/KUnitField.vue +12 -2
  51. package/core/client/components/form/KUrlField.vue +12 -2
  52. package/core/client/components/input/KIconChooser.vue +10 -12
  53. package/core/client/components/input/KPalette.vue +2 -1
  54. package/core/client/components/layout/KPage.vue +5 -4
  55. package/core/client/components/layout/KWindow.vue +10 -10
  56. package/core/client/components/media/KColorScale.vue +25 -19
  57. package/core/client/components/media/KImageViewer.vue +57 -33
  58. package/core/client/components/media/KShape.vue +14 -103
  59. package/core/client/components/screen/KRegisterScreen.vue +0 -1
  60. package/core/client/components/screen/KScreenFooter.vue +0 -18
  61. package/core/client/components/team/KAddMember.vue +16 -22
  62. package/core/client/components/team/KGroupsActivity.vue +14 -0
  63. package/core/client/components/team/KMembersActivity.vue +12 -0
  64. package/core/client/components/team/KTagsActivity.vue +14 -0
  65. package/core/client/components/time/KDateTime.vue +23 -7
  66. package/core/client/components/time/KTimeControl.vue +142 -0
  67. package/core/client/components/tool/KExportTool.vue +57 -0
  68. package/core/client/composables/collection.js +0 -1
  69. package/core/client/composables/pwa.js +0 -1
  70. package/core/client/composables/schema.js +1 -1
  71. package/core/client/composables/session.js +30 -6
  72. package/core/client/exporter.js +147 -0
  73. package/core/client/i18n/core_en.json +91 -23
  74. package/core/client/i18n/core_fr.json +92 -23
  75. package/core/client/index.js +3 -0
  76. package/core/client/layout.js +34 -14
  77. package/core/client/local-storage.js +8 -6
  78. package/core/client/mixins/index.js +0 -1
  79. package/core/client/mixins/mixin.base-field.js +24 -2
  80. package/core/client/mixins/mixin.object-proxy.js +0 -1
  81. package/core/client/search.js +2 -1
  82. package/core/client/services/index.js +2 -1
  83. package/core/client/services/local-settings.service.js +4 -4
  84. package/core/client/theme.js +3 -3
  85. package/core/client/time.js +4 -0
  86. package/core/client/units.js +150 -5
  87. package/core/client/utils/index.js +13 -6
  88. package/core/client/utils/utils.account.js +1 -1
  89. package/core/client/utils/utils.colors.js +43 -0
  90. package/core/client/utils/utils.platform.js +0 -1
  91. package/core/client/utils/utils.pwa.js +14 -14
  92. package/core/client/utils/utils.session.js +1 -1
  93. package/core/client/utils/utils.shapes.js +270 -0
  94. package/core/client/utils/utils.time.js +37 -0
  95. package/core/common/permissions.js +3 -0
  96. package/core/common/schemas/settings.update.json +50 -29
  97. package/extras/css/core.variables.scss +3 -1
  98. package/extras/icons/wind-speed-0.svg +8 -0
  99. package/extras/icons/wind-speed-10.svg +8 -0
  100. package/extras/icons/wind-speed-100.svg +12 -0
  101. package/extras/icons/wind-speed-105.svg +13 -0
  102. package/extras/icons/wind-speed-15.svg +9 -0
  103. package/extras/icons/wind-speed-20.svg +9 -0
  104. package/extras/icons/wind-speed-25.svg +10 -0
  105. package/extras/icons/wind-speed-30.svg +10 -0
  106. package/extras/icons/wind-speed-35.svg +11 -0
  107. package/extras/icons/wind-speed-40.svg +11 -0
  108. package/extras/icons/wind-speed-45.svg +12 -0
  109. package/extras/icons/wind-speed-5.svg +9 -0
  110. package/extras/icons/wind-speed-50.svg +9 -0
  111. package/extras/icons/wind-speed-55.svg +10 -0
  112. package/extras/icons/wind-speed-60.svg +10 -0
  113. package/extras/icons/wind-speed-65.svg +11 -0
  114. package/extras/icons/wind-speed-70.svg +11 -0
  115. package/extras/icons/wind-speed-75.svg +12 -0
  116. package/extras/icons/wind-speed-80.svg +12 -0
  117. package/extras/icons/wind-speed-85.svg +13 -0
  118. package/extras/icons/wind-speed-90.svg +13 -0
  119. package/extras/icons/wind-speed-95.svg +14 -0
  120. package/extras/tours/map/navigation-bar.js +17 -15
  121. package/extras/tours/map/timeline.js +33 -33
  122. package/map/api/config/categories.cjs +4 -1
  123. package/map/api/hooks/hooks.catalog.js +39 -0
  124. package/map/api/hooks/hooks.features.js +23 -3
  125. package/map/api/hooks/hooks.query.js +65 -21
  126. package/map/api/models/projects.model.mongodb.js +8 -0
  127. package/map/api/services/catalog/catalog.hooks.js +5 -3
  128. package/map/api/services/features/features.hooks.js +18 -6
  129. package/map/api/services/index.js +22 -6
  130. package/map/api/services/projects/projects.hooks.js +118 -0
  131. package/map/client/capture.js +16 -0
  132. package/map/client/cesium/utils/index.js +4 -0
  133. package/map/client/cesium/utils/utils.events.js +30 -0
  134. package/map/client/cesium/utils/utils.features.js +8 -0
  135. package/map/client/cesium/utils/utils.popup.js +17 -0
  136. package/map/client/cesium/utils/utils.style.js +137 -0
  137. package/map/client/components/KCapture.vue +50 -0
  138. package/map/client/components/KCaptureTextArea.vue +53 -0
  139. package/map/client/components/KCompass.vue +2 -2
  140. package/map/client/components/KFeaturesChart.vue +1 -1
  141. package/map/client/components/KFeaturesFilter.vue +2 -2
  142. package/map/client/components/KLayerStyleForm.vue +288 -454
  143. package/map/client/components/KLevelSlider.vue +1 -1
  144. package/map/client/components/KNorth.vue +31 -0
  145. package/map/client/components/KProjectMenu.vue +88 -0
  146. package/map/client/components/KTimezoneMap.vue +36 -24
  147. package/map/client/components/catalog/KAddLayer.vue +3 -4
  148. package/map/client/components/catalog/KConnectLayer.vue +20 -4
  149. package/map/client/components/catalog/KCreateLayer.vue +1 -2
  150. package/map/client/components/catalog/KCreateProject.vue +100 -0
  151. package/map/client/components/catalog/KCreateView.vue +25 -2
  152. package/map/client/components/catalog/KLayersPanel.vue +24 -27
  153. package/map/client/components/catalog/KLayersSelector.vue +1 -1
  154. package/map/client/components/catalog/KProjectEditor.vue +91 -0
  155. package/map/client/components/catalog/KProjectManager.vue +60 -0
  156. package/map/client/components/catalog/KProjectSelector.vue +38 -0
  157. package/map/client/components/catalog/KProjectsPanel.vue +153 -0
  158. package/map/client/components/catalog/KSelectLayers.vue +96 -0
  159. package/map/client/components/catalog/KSelectViews.vue +96 -0
  160. package/map/client/components/catalog/KViewsPanel.vue +66 -30
  161. package/map/client/components/form/KDirectionField.vue +24 -5
  162. package/map/client/components/form/KLayerCategoryField.vue +12 -2
  163. package/map/client/components/form/KLocationField.vue +20 -5
  164. package/map/client/components/form/KOwsLayerField.vue +12 -2
  165. package/map/client/components/form/KOwsServiceField.vue +12 -2
  166. package/map/client/components/form/KSelectLayersField.vue +159 -0
  167. package/map/client/components/form/KSelectViewsField.vue +121 -0
  168. package/map/client/components/form/KTimezoneField.vue +24 -17
  169. package/map/client/components/legend/KColorScaleLegend.vue +6 -2
  170. package/map/client/components/legend/KLayerLegend.vue +71 -0
  171. package/map/client/components/legend/KLegend.vue +54 -51
  172. package/map/client/components/legend/KLegendRenderer.vue +5 -3
  173. package/map/client/components/legend/KSymbolsLegend.vue +12 -10
  174. package/map/client/components/legend/KVariablesLegend.vue +78 -0
  175. package/map/client/components/location/KGeocodersFilter.vue +2 -4
  176. package/map/client/components/location/KLocationCardSection.vue +8 -4
  177. package/map/client/components/location/KLocationMap.vue +48 -17
  178. package/map/client/components/location/KLocationSearch.vue +13 -3
  179. package/map/client/components/tools/KSearchTool.vue +17 -12
  180. package/map/client/components/widget/KElevationProfile.vue +16 -19
  181. package/map/client/components/widget/KMapillaryViewer.vue +21 -22
  182. package/map/client/components/widget/KTimeSeries.vue +35 -29
  183. package/map/client/composables/activity.js +15 -2
  184. package/map/client/composables/catalog.js +81 -0
  185. package/map/client/composables/highlight.js +45 -30
  186. package/map/client/composables/index.js +2 -0
  187. package/map/client/composables/location.js +25 -18
  188. package/map/client/composables/probe.js +4 -1
  189. package/map/client/composables/project.js +122 -0
  190. package/map/client/composables/weather.js +3 -3
  191. package/map/client/geolocation.js +1 -1
  192. package/map/client/globe.js +2 -0
  193. package/map/client/i18n/map_en.json +127 -76
  194. package/map/client/i18n/map_fr.json +128 -72
  195. package/map/client/index.js +3 -0
  196. package/map/client/init.js +17 -0
  197. package/map/client/leaflet/GSMaPLayer.js +16 -17
  198. package/map/client/leaflet/ShapeMarker.js +51 -0
  199. package/map/client/leaflet/TiledFeatureLayer.js +39 -9
  200. package/map/client/leaflet/TiledMeshLayer.js +13 -15
  201. package/map/client/leaflet/TiledWindLayer.js +6 -10
  202. package/map/client/leaflet/utils/index.js +4 -0
  203. package/map/client/leaflet/utils/utils.events.js +41 -0
  204. package/map/client/leaflet/utils/utils.popup.js +21 -0
  205. package/map/client/leaflet/utils/utils.style.js +195 -0
  206. package/map/client/leaflet/utils/utils.tiles.js +87 -0
  207. package/map/client/map.js +2 -0
  208. package/map/client/mixins/globe/mixin.base-globe.js +39 -18
  209. package/map/client/mixins/globe/mixin.geojson-layers.js +139 -69
  210. package/map/client/mixins/globe/mixin.popup.js +2 -1
  211. package/map/client/mixins/globe/mixin.style.js +6 -4
  212. package/map/client/mixins/globe/mixin.tooltip.js +8 -3
  213. package/map/client/mixins/map/mixin.base-map.js +53 -28
  214. package/map/client/mixins/map/mixin.edit-layers.js +15 -15
  215. package/map/client/mixins/map/mixin.forecast-layers.js +3 -1
  216. package/map/client/mixins/map/mixin.geojson-layers.js +60 -20
  217. package/map/client/mixins/map/mixin.georaster-layers.js +4 -11
  218. package/map/client/mixins/map/mixin.heatmap-layers.js +1 -1
  219. package/map/client/mixins/map/mixin.popup.js +2 -1
  220. package/map/client/mixins/map/mixin.style.js +4 -67
  221. package/map/client/mixins/map/mixin.tiled-mesh-layers.js +2 -1
  222. package/map/client/mixins/map/mixin.tiled-wind-layers.js +4 -2
  223. package/map/client/mixins/map/mixin.tooltip.js +2 -1
  224. package/map/client/mixins/mixin.activity.js +71 -192
  225. package/map/client/mixins/mixin.catalog-panel.js +6 -6
  226. package/map/client/mixins/mixin.context.js +12 -9
  227. package/map/client/mixins/mixin.feature-service.js +29 -300
  228. package/map/client/mixins/mixin.weacast.js +11 -17
  229. package/map/client/pixi-utils.js +1 -1
  230. package/map/client/planets.js +66 -0
  231. package/map/client/utils/index.js +6 -0
  232. package/map/client/utils/utils.capture.js +176 -0
  233. package/map/client/utils/utils.catalog.js +166 -0
  234. package/map/client/utils/utils.features.js +364 -0
  235. package/map/client/utils/utils.js +0 -151
  236. package/map/client/utils/utils.layers.js +175 -0
  237. package/map/client/utils/utils.location.js +91 -23
  238. package/map/client/utils/utils.project.js +8 -0
  239. package/map/client/utils/utils.schema.js +0 -1
  240. package/map/client/utils/utils.style.js +309 -0
  241. package/map/client/utils.all.js +2 -2
  242. package/map/client/utils.globe.js +1 -1
  243. package/map/client/utils.map.js +1 -1
  244. package/map/common/permissions.js +2 -0
  245. package/map/common/schemas/capture.create.json +132 -0
  246. package/map/common/schemas/projects.create.json +52 -0
  247. package/map/common/schemas/projects.update.json +52 -0
  248. package/map/common/wms-utils.js +8 -3
  249. package/package.json +6 -5
  250. package/test/api/core/account.test.js +20 -0
  251. package/test/api/core/config/default.cjs +16 -3
  252. package/test/api/core/import-export.test.js +86 -0
  253. package/test/api/core/test-log-2024-01-04.log +14 -0
  254. package/test/api/map/catalog.test.js +164 -0
  255. package/test/api/map/index.test.js +25 -61
  256. package/test/api/map/test-log-2024-01-04.log +2 -0
  257. package/test/api/map/test-log-2024-01-11.log +1 -0
  258. package/test/api/map/test-log-2024-01-25.log +19 -0
  259. package/test/client/core/layout.js +24 -5
  260. package/test/client/core/utils.js +7 -0
  261. package/test/client/map/catalog.js +78 -1
  262. package/test/client/map/time.js +2 -1
  263. package/core/client/components/screen/KEndpointScreen.vue +0 -80
  264. package/core/client/mixins/mixin.account.js +0 -61
  265. package/extras/icons/kdk.png +0 -0
  266. package/map/api/services/geocoder/geocoder.service.js +0 -79
  267. package/map/client/cesium/utils.js +0 -133
  268. package/map/client/components/KCaptureToolbar.vue +0 -155
  269. package/map/client/components/KColorLegend.vue +0 -349
  270. package/map/client/components/KTimeline.vue +0 -293
  271. package/map/client/components/KUrlLegend.vue +0 -122
  272. package/map/client/leaflet/utils.js +0 -246
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="column no-wrap">
2
+ <div class="column no-wrap" v-if="zoom">
3
3
  <!-- Sublegends -->
4
4
  <template
5
5
  v-for="sublegend in sublegends"
@@ -14,15 +14,32 @@
14
14
  :default-opened="sublegend.opened || opened"
15
15
  dense
16
16
  >
17
+ <template v-slot:header>
18
+ <!-- Label -->
19
+ <q-item-section>
20
+ {{ $tie(sublegend.name) }}
21
+ </q-item-section>
22
+ <!-- Helper -->
23
+ <q-item-section v-if="sublegend.helper" side >
24
+ <KAction
25
+ :id="sublegend.name + '-helper'"
26
+ color="primary"
27
+ :propagate="false"
28
+ :icon="getHelperIcon(sublegend.helper)"
29
+ :tooltip="getHelperTooltip(sublegend.helper)"
30
+ :url="getHelperUrl(sublegend.helper)"
31
+ :dialog="getHelperDialog(sublegend.helper)"
32
+ />
33
+ </q-item-section>
34
+ </template>
17
35
  <!-- legend components by layers -->
18
36
  <template v-for="layer in layersBySublegend[sublegend.name]" :key="layer.name" class="column full-width">
19
- <div class="q-py-xs q-px-md">
20
- <component
21
- :is="layer.legend.renderer"
22
- :label="layer.legend.label"
23
- :content="filterContent(layer)"
24
- />
25
- </div>
37
+ <KLayerLegend
38
+ :layer ="layer"
39
+ :zoom="zoom"
40
+ :engine="engine"
41
+ :renderers="renderers"
42
+ />
26
43
  </template>
27
44
  </q-expansion-item>
28
45
  </template>
@@ -34,15 +51,12 @@ import _ from 'lodash'
34
51
  import logger from 'loglevel'
35
52
  import sift from 'sift'
36
53
  import { ref, computed, watch } from 'vue'
37
- import { i18n, api, utils as coreUtils } from '../../../../core/client'
38
- import { useCurrentActivity } from '../../composables'
54
+ import { i18n, Store } from '../../../../core/client'
55
+ import { useCurrentActivity, useCatalog } from '../../composables'
56
+ import KLayerLegend from './KLayerLegend.vue'
39
57
 
40
58
  // Props
41
59
  const props = defineProps({
42
- contextId: {
43
- type: String,
44
- default: undefined
45
- },
46
60
  headerClass: {
47
61
  type: String,
48
62
  default: 'bg-grey-3 text-weight-regular'
@@ -65,12 +79,18 @@ const props = defineProps({
65
79
  return {
66
80
  image: 'legend/KImageLegend',
67
81
  'color-scale': 'legend/KColorScaleLegend',
68
- symbols: 'legend/KSymbolsLegend'
82
+ symbols: 'legend/KSymbolsLegend',
83
+ variables: 'legend/KVariablesLegend'
69
84
  }
70
85
  }
71
86
  }
72
87
  })
73
88
 
89
+ // Use global catalog
90
+ const { getSublegends } = useCatalog()
91
+ // Use local catalog if any
92
+ const { getSublegends: getContextSublegends } = useCatalog({ context: Store.get('context') })
93
+
74
94
  // Data
75
95
  const { CurrentActivity } = useCurrentActivity({ selection: false, probe: false })
76
96
  const sublegends = ref([])
@@ -95,23 +115,15 @@ const layersBySublegend = computed(() => {
95
115
 
96
116
  // Functions
97
117
  function onShowLayer (layer, engine) {
98
- const legend = layer.legend
99
- if (!legend) return
100
- if (!legend.content) {
101
- logger.warn(`[KDK] Legend for ${layer.name} has no content`)
102
- return
103
- }
118
+ const layerLegend = layer.legend
119
+ // Check whether the layer has a legend
120
+ if (!layerLegend) return
121
+ // Check wehther the legend is already registered for that layer
104
122
  if (_.find(layers.value, { name: layer.name })) {
105
123
  logger.warn(`[KDK] Legend for ${layer.name} already resgistered`)
106
124
  return
107
125
  }
108
126
  logger.debug(`[KDK] Register '${layer.name}' legend`)
109
- const renderer = props.renderers[legend.type]
110
- if (!renderer) {
111
- logger.warn(`[KDK] Cannot find any renderer for the layer's legend of type of ${legend.type}`)
112
- return
113
- }
114
- legend.renderer = coreUtils.loadComponent(renderer)
115
127
  layers.value.push(layer)
116
128
  }
117
129
  function onHideLayer (layer) {
@@ -122,36 +134,27 @@ function onHideLayer (layer) {
122
134
  function onZoomChanged () {
123
135
  zoom.value = CurrentActivity.value.getCenter().zoomLevel
124
136
  }
125
- function filterContent (layer) {
126
- const content = layer.legend.content
127
- if (!zoom.value) return content
128
- let result
129
- if (Array.isArray(content)) {
130
- _.forEach(content, item => {
131
- const minZoom = _.get(layer, `${engine.value}.minZoom`, _.get(item, 'minZoom', 0))
132
- const maxZoom = _.get(layer, `${engine.value}.maxZoom`, _.get(item, 'maxZoom', 99))
133
- if (zoom.value >= minZoom && zoom.value <= maxZoom) {
134
- result = item
135
- return false
136
- }
137
- })
138
- } else {
139
- const minZoom = _.get(layer, `${engine.value}.minZoom`, _.get(content, 'minZoom', 0))
140
- const maxZoom = _.get(layer, `${engine.value}.maxZoom`, _.get(content, 'maxZoom', 99))
141
- if (zoom.value >= minZoom && zoom.value <= maxZoom) {
142
- result = content
143
- }
144
- }
145
- return result
137
+ function getHelperIcon (helper) {
138
+ return _.get(helper, 'icon', undefined)
139
+ }
140
+ function getHelperTooltip (helper) {
141
+ return _.get(helper, 'tooltip', '')
142
+ }
143
+ function getHelperUrl (helper) {
144
+ return _.get(helper, 'url', null)
145
+ }
146
+ function getHelperDialog (helper) {
147
+ return _.get(helper, 'dialog', null)
146
148
  }
147
149
 
148
150
  // Watch
149
151
  watch([() => props.sublegends, () => props.sublegendsFromCatalog], async () => {
150
152
  // Retrieve the legends from catalog if required
151
153
  if (props.sublegendsFromCatalog) {
152
- const catalogService = api.getService('catalog', props.contextOrId)
153
- const response = await catalogService.find({ query: { type: 'Sublegend' } })
154
- sublegends.value = response.data
154
+ sublegends.value = await getSublegends()
155
+ if (Store.get('context')) {
156
+ sublegends.value = sublegends.value.concat(await getContextSublegends())
157
+ }
155
158
  } else {
156
159
  sublegends.value = []
157
160
  }
@@ -1,11 +1,13 @@
1
1
  <template>
2
2
  <div class="column full-width q-gutter-xs">
3
- <div v-if="label" class="text-weight-light">
3
+ <div v-if="label" class="text-weight-medium">
4
4
  {{ $tie(label) }}
5
5
  </div>
6
- <slot>
6
+ <div class="q-pr-sm">
7
+ <slot>
7
8
  <!-- to be overloaded -->
8
- </slot>
9
+ </slot>
10
+ </div>
9
11
  </div>
10
12
  </template>
11
13
 
@@ -17,20 +17,22 @@
17
17
  >
18
18
  <q-item dense>
19
19
  <q-item-section avatar v-if="element.component">
20
- <component
21
- :is="element.component"
22
- v-bind="element.props"
23
- :key="element.label"
24
- />
20
+ <div class="row justify-center">
21
+ <component
22
+ :is="element.component"
23
+ v-bind="element.props"
24
+ :key="element.label"
25
+ />
26
+ </div>
25
27
  </q-item-section>
26
28
  <q-item-section>
27
- <q-item-label>
29
+ <q-item-label class="text-caption">
28
30
  {{ $tie(element.label )}}
29
31
  </q-item-label>
30
32
  </q-item-section>
31
33
  </q-item>
32
34
  </template>
33
- <q-separator v-if="index < sections.length - 1" />
35
+ <q-separator v-if="index < sections.length - 1" style="margin: 8px;" />
34
36
  </q-list>
35
37
  </template>
36
38
  </div>
@@ -44,7 +46,7 @@ import { computed } from 'vue'
44
46
  import { loadComponent } from '../../../../core/client/utils'
45
47
  import KLegendRenderer from './KLegendRenderer.vue'
46
48
 
47
- // props
49
+ // Props
48
50
  const props = defineProps({
49
51
  label: {
50
52
  type: String,
@@ -56,9 +58,9 @@ const props = defineProps({
56
58
  }
57
59
  })
58
60
 
59
- // computed
61
+ // Computed
60
62
  const sections = computed(() => {
61
- return _.difference(_.keys(props.content), ['minZoom', 'maxZoom'])
63
+ return _.difference(_.keys(props.content))
62
64
  })
63
65
 
64
66
  // function
@@ -0,0 +1,78 @@
1
+ <template>
2
+ <KLegendRenderer
3
+ v-if="content"
4
+ :label="label"
5
+ >
6
+ <!-- content -->
7
+ <template v-for="variable in variables" :key="variable.name">
8
+ <!-- caption -->
9
+ <span class="text-caption">{{ variable.label }}</span>
10
+ <!-- colorscale -->
11
+ <KColorScale
12
+ v-bind="variable.colorScale"
13
+ style="height: 46px;"
14
+ />
15
+ </template>
16
+ </KLegendRenderer>
17
+ </template>
18
+
19
+ <script setup>
20
+ import _ from 'lodash'
21
+ import logger from 'loglevel'
22
+ import { computed } from 'vue'
23
+ import { i18n } from '../../../../core/client'
24
+ import { Units } from '../../../../core/client/units'
25
+ import { KColorScale } from '../../../../core/client/components'
26
+ import KLegendRenderer from './KLegendRenderer.vue'
27
+
28
+ // Props
29
+ const props = defineProps({
30
+ layer: {
31
+ type: Object,
32
+ required: true
33
+ },
34
+ label: {
35
+ type: String,
36
+ default: undefined
37
+ },
38
+ content: {
39
+ type: String,
40
+ default: '.'
41
+ }
42
+ })
43
+
44
+ // Computed
45
+ const variables = computed(() => {
46
+ const regexp = new RegExp(props.content)
47
+ return _.filter(props.layer.variables, variable => {
48
+ if (regexp.test(variable)) {
49
+ if (variable.chromajs) return true
50
+ logger.warn(`[KDK] variable '${variable.name}' must have a 'chromajs' property`)
51
+ }
52
+ return false
53
+ })
54
+ .map(variable => {
55
+ // Pick useful properties
56
+ let { name, label, chromajs, unit } = _.pick(variable, ['name', 'label', 'chromajs', 'unit'])
57
+ // Avoid mutating layer data
58
+ const colorScale = _.cloneDeep(chromajs)
59
+ label = `${i18n.tie(label)} (${Units.getTargetUnitSymbol(unit)})`
60
+ // Rename required properties for backward compatibility
61
+ if (colorScale.scale) {
62
+ colorScale.colors = colorScale.scale
63
+ delete colorScale.scale
64
+ }
65
+ // Convert to target unit
66
+ if (colorScale.domain) {
67
+ colorScale.domain = colorScale.domain.map(value => Units.convert(value, unit))
68
+ }
69
+ if (colorScale.classes) {
70
+ colorScale.classes = colorScale.classes.map(value => Units.convert(value, unit))
71
+ }
72
+ return {
73
+ name, label, colorScale
74
+ }
75
+ })
76
+ })
77
+
78
+ </script>
@@ -4,13 +4,13 @@
4
4
  v-model="selectedGeocoders"
5
5
  :options="availableGeocoders"
6
6
  type="toggle"
7
+ size="xs"
7
8
  />
8
9
  </template>
9
10
 
10
11
  <script setup>
11
12
  import _ from 'lodash'
12
13
  import { computed } from 'vue'
13
- import { i18n } from '../../../../core.client'
14
14
 
15
15
  // Props
16
16
  const props = defineProps({
@@ -37,8 +37,6 @@ const selectedGeocoders = computed({
37
37
  }
38
38
  })
39
39
  const availableGeocoders = computed(() => {
40
- return _.map(props.geocoders, geocoder => {
41
- return Object.assign({}, geocoder, { label: i18n.tie(geocoder.label) })
42
- })
40
+ return _.sortBy(props.geocoders, ['label'])
43
41
  })
44
42
  </script>
@@ -32,10 +32,10 @@
32
32
  </template>
33
33
 
34
34
  <script setup>
35
- import { toRefs } from 'vue'
35
+ import { ref, watch } from 'vue'
36
36
  import KLocationMap from './KLocationMap.vue'
37
37
 
38
- // props
38
+ // Props
39
39
  const props = defineProps({
40
40
  location: {
41
41
  type: Object,
@@ -55,7 +55,11 @@ const props = defineProps({
55
55
  }
56
56
  })
57
57
 
58
- // data
59
- const { location: feature } = toRefs(props)
58
+ // Data
59
+ const feature = ref(null)
60
60
 
61
+ // Watch
62
+ watch(() => props.location, (value) => {
63
+ feature.value = value
64
+ }, { immediate: true })
61
65
  </script>
@@ -20,15 +20,19 @@
20
20
 
21
21
  <script>
22
22
  import _ from 'lodash'
23
+ import logger from 'loglevel'
23
24
  import L from 'leaflet'
24
25
  import config from 'config'
25
26
  import centroid from '@turf/centroid'
26
27
  import { KPanel } from '../../../../core/client/components'
28
+ import { api } from '../../../../core/client/api.js'
27
29
  import * as mapMixins from '../../mixins/map'
28
- import { Geolocation } from '../../geolocation'
30
+ import { Geolocation } from '../../geolocation.js'
31
+ import { useCatalog, useCurrentActivity } from '../../composables'
29
32
  import {
30
- setEngineJwt, coordinatesToGeoJSON, formatUserCoordinates,
31
- bindLeafletEvents, unbindLeafletEvents, createLeafletMarkerFromStyle, convertToLeafletFromSimpleStyleSpec
33
+ coordinatesToGeoJSON, formatUserCoordinates,
34
+ bindLeafletEvents, unbindLeafletEvents, getFeatureStyleType,
35
+ getDefaultPointStyle, getDefaultLineStyle, getDefaultPolygonStyle, createMarkerFromPointStyle
32
36
  } from '../../utils.map.js'
33
37
 
34
38
  export default {
@@ -169,20 +173,34 @@ export default {
169
173
  }
170
174
  // create a new layer
171
175
  const type = _.get(this.location, 'geometry.type')
172
- // style is expressed as simple style spec in config
173
- const pointStyle = convertToLeafletFromSimpleStyleSpec(this.engineOptions.pointStyle)
174
- const featureStyle = convertToLeafletFromSimpleStyleSpec(this.engineOptions.featureStyle)
175
176
  if (type === 'Point') {
176
177
  const coordinates = _.get(this.location, 'geometry.coordinates')
177
- this.locationLayer = createLeafletMarkerFromStyle([coordinates[1], coordinates[0]],
178
- Object.assign({ draggable: this.draggable, pmIgnore: true }, pointStyle))
178
+ const style = _.get(this.engineOptions, 'style.location.point')
179
+ this.locationLayer = createMarkerFromPointStyle([coordinates[1], coordinates[0]],
180
+ Object.assign({ draggable: this.draggable, pmIgnore: true }, style))
179
181
  if (this.draggable) this.locationLayer.on('dragend', this.onLocationDragged)
180
182
  } else {
181
183
  this.locationLayer = L.geoJson(this.location, {
182
- pointToLayer: (feature, latlng) => createLeafletMarkerFromStyle(latlng, pointStyle),
183
- style: (feature) => featureStyle
184
+ style: (feature) => {
185
+ const styleType = getFeatureStyleType(feature)
186
+ if (!styleType) {
187
+ logger.warn(`[KDK] cannot get a style type from the feature of geometry type ${feature.geometry.type}`)
188
+ return
189
+ }
190
+ if (styleType === 'line') return getDefaultLineStyle(feature, null, this.engineOptions, 'style.location.line')
191
+ return getDefaultPolygonStyle(feature, null, this.engineOptions, 'style.location.polygon')
192
+ },
193
+ pointToLayer: (feature, latlng) => {
194
+ const style = getDefaultPointStyle(feature, null, this.engineOptions, 'style.location.point')
195
+ if (!style) {
196
+ logger.warn('[KDK] cannot generate point style from a feature')
197
+ return
198
+ }
199
+ return createMarkerFromPointStyle(latlng, style)
200
+ }
184
201
  })
185
202
  }
203
+ // }
186
204
  this.locationLayer.addTo(this.map)
187
205
  // wait for the next tick to recenter the view
188
206
  this.$nextTick(() => this.recenter())
@@ -232,14 +250,10 @@ export default {
232
250
  this.map.pm.setGlobalOptions({ layerGroup: null })
233
251
  },
234
252
  async refreshBaseLayer () {
235
- const catalogService = this.$api.getService('catalog', '')
253
+ const layers = await this.getLayers()
236
254
  // Get first visible base layer
237
- const response = await catalogService.find({ query: { type: 'BaseLayer', 'leaflet.isVisible': true } })
238
- if (response.data.length > 0) {
239
- const baseLayer = response.data[0]
240
- // Do we need to inject a token ?
241
- await setEngineJwt([baseLayer])
242
- this.addLayer(baseLayer)
255
+ if (layers.length > 0) {
256
+ this.addLayer(layers[0])
243
257
  }
244
258
  },
245
259
  mapRefCreated (container) {
@@ -261,6 +275,23 @@ export default {
261
275
  },
262
276
  beforeUnmount () {
263
277
  this.$engineEvents.off('pm:create', this.stopDraw)
278
+ },
279
+ async setup () {
280
+ // Get current project for activity if any
281
+ const { getActivityProject } = useCurrentActivity({ selection: false, probe: false })
282
+ const project = getActivityProject()
283
+ // We expect the project object to expose the underlying API
284
+ const planetApi = project && typeof project.getPlanetApi === 'function' ? project.getPlanetApi() : api
285
+ // Use target catalog according to project and filtering options to get base layer
286
+ const { getLayers } = useCatalog({
287
+ project,
288
+ layers: { type: 'BaseLayer', 'leaflet.isVisible': true },
289
+ planetApi
290
+ })
291
+ // expose
292
+ return {
293
+ getLayers
294
+ }
264
295
  }
265
296
  }
266
297
  </script>
@@ -49,14 +49,22 @@
49
49
  <q-item-section>
50
50
  <q-item-label>{{ scope.opt.properties ? scope.opt.properties.name : scope.opt.name }}</q-item-label>
51
51
  </q-item-section>
52
+ <q-item-section avatar v-if="scope.opt.properties.source">
53
+ <q-chip dense size="0.7rem" color="primary" text-color="white">
54
+ {{ $tie(`Geocoders.${scope.opt.properties.source}`) }}
55
+ </q-chip>
56
+ </q-item-section>
52
57
  <KLocationTip :location="scope.opt" />
53
58
  </q-item>
54
59
  </template>
55
60
  <!-- No options -->
56
61
  <template v-slot:no-option>
57
62
  <q-item>
63
+ <q-item-section avatar>
64
+ <q-icon name="las la-frown" color="grey" />
65
+ </q-item-section>
58
66
  <q-item-section class="text-grey">
59
- {{ $t('KLocationSearch.NO_RESULTS') }}
67
+ {{ $t('KLocationSearch.NO_RESULT') }}
60
68
  </q-item-section>
61
69
  </q-item>
62
70
  </template>
@@ -126,7 +134,7 @@ const hasGeocoders = computed(() => {
126
134
 
127
135
  // Functions
128
136
  async function onSearch (pattern, update, abort) {
129
- if (pattern.length < 4) {
137
+ if (pattern.length < 3) {
130
138
  abort()
131
139
  return
132
140
  }
@@ -140,5 +148,7 @@ function onLocationChanged () {
140
148
  }
141
149
 
142
150
  // Hooks
143
- watch(() => props.geocoders, async (geocoders) => setGeocoders(geocoders), { immediate: true })
151
+ watch(() => props.geocoders, (geocoders) => {
152
+ setGeocoders(geocoders)
153
+ }, { immediate: true })
144
154
  </script>
@@ -9,6 +9,7 @@
9
9
  <script setup>
10
10
  import { ref, computed, watch, onBeforeUnmount } from 'vue'
11
11
  import { uid, getCssVar, useQuasar } from 'quasar'
12
+ import bbox from '@turf/bbox'
12
13
  import KLocationSearch from '../location/KLocationSearch.vue'
13
14
  import { useCurrentActivity } from '../../composables'
14
15
 
@@ -36,6 +37,7 @@ const computedStyle = computed(() => {
36
37
  // Functions
37
38
  async function createLocationLayer () {
38
39
  // create the layer
40
+ const style = CurrentActivity.value.activityOptions.engine.style.location
39
41
  await CurrentActivity.value.addLayer({
40
42
  name: LocationLayerName,
41
43
  type: 'OverlayLayer',
@@ -46,20 +48,18 @@ async function createLocationLayer () {
46
48
  isVisible: true,
47
49
  realtime: true,
48
50
  interactive: false,
49
- popup: { template: '<%= properties.name %>' },
50
- 'icon-classes': 'fas fa-circle',
51
- 'marker-color': getCssVar('primary'),
52
- 'icon-color': '#FFFFFF',
53
- 'icon-x-offset': -2,
54
- 'icon-y-offset': 0
51
+ style,
52
+ popup: { template: '<%= properties.name %>' }
55
53
  },
56
54
  cesium: {
57
55
  type: 'geoJson',
58
56
  isVisible: true,
59
57
  realtime: true,
60
- popup: { template: '<%= properties.name %>' },
58
+ // FIXME: should use the style
59
+ // style,
61
60
  'marker-symbol': 'marker',
62
- 'marker-color': getCssVar('primary')
61
+ 'marker-color': getCssVar('primary'),
62
+ popup: { template: '<%= properties.name %>' }
63
63
  }
64
64
  })
65
65
  // updated the layer with the location
@@ -70,10 +70,15 @@ async function createLocationLayer () {
70
70
  // show the layer
71
71
  if (!CurrentActivity.value.isLayerVisible(LocationLayerName)) await CurrentActivity.value.showLayer(LocationLayerName)
72
72
  // zoom to the location
73
- const zoomOrDist = CurrentActivity.value.is2D() ? 18 : 75
74
- const lng = location.value.geometry.coordinates[0]
75
- const lat = location.value.geometry.coordinates[1]
76
- CurrentActivity.value.center(lng, lat, zoomOrDist)
73
+ const geometry = location.value.geometry
74
+ if (geometry.type === 'Point') {
75
+ const zoomOrDist = CurrentActivity.value.is2D() ? 18 : 75
76
+ const lng = location.value.geometry.coordinates[0]
77
+ const lat = location.value.geometry.coordinates[1]
78
+ CurrentActivity.value.center(lng, lat, zoomOrDist)
79
+ } else {
80
+ CurrentActivity.value.zoomToBBox(bbox(location.value))
81
+ }
77
82
  }
78
83
 
79
84
  async function removeLocationLayer () {