@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,293 +0,0 @@
1
- <template>
2
- <div id="timeline" class="q-pa-xs column k-timeline">
3
- <!--
4
- Time controls
5
- -->
6
- <div class="full-width row justify-center items-center k-timeline-control">
7
- <q-btn id="timeline-backward" v-if="$q.screen.gt.xs" dense flat round icon='las la-step-backward' size="md" color="primary" @click="onPreviousStepClicked">
8
- <q-tooltip>{{$t('KTimeline.PREVIOUS_STEP')}}</q-tooltip>
9
- </q-btn>
10
- <q-btn id="timeline-date" dense flat round icon='las la-calendar' size="md" color="primary">
11
- <q-tooltip>{{$t('KTimeline.SET_DATE')}}</q-tooltip>
12
- <q-popup-proxy transition-show="scale" transition-hide="scale">
13
- <q-date v-model="date" :mask="calendarDateMask" today-btn minimal />
14
- </q-popup-proxy>
15
- </q-btn>
16
- <q-chip :label="formatTime(time, 'date.long') + ' ' + formatTime(time, 'time.long')" color="primary" text-color="white" :dense="$q.screen.lt.sm" />
17
- <q-btn id="timeline-now" dense flat round icon="las la-clock" size="md" color="primary" @click="onNowClicked">
18
- <q-tooltip>{{$t('KTimeline.SET_NOW')}}</q-tooltip>
19
- <q-badge v-if="Time.realtime" floating transparent color="green">
20
- <q-icon name="las la-play" size="10px" color="white'" />
21
- </q-badge>
22
- </q-btn>
23
- <q-btn v-if="$q.screen.gt.xs" id="timeline-forward" dense flat round icon='las la-step-forward' size="md" color="primary" @click="onNextStepClicked">
24
- <q-tooltip>{{$t('KTimeline.NEXT_STEP')}}</q-tooltip>
25
- </q-btn>
26
- </div>
27
- <div v-if="!$q.screen.gt.xs" class="full-width row justify-around q-pt-xs">
28
- <k-panel id="timeline-actions" :content="actions" mode="mobile" color="primary" />
29
- </div>
30
- <!--
31
- Time bars
32
- -->
33
- <div v-if="$q.screen.gt.xs" class="q-pt-sm column">
34
- <div v-if="minutes.length > 0" class="row justify-center items-center">
35
- <template v-for="(minute, index) in minutes" :key="index">
36
- <q-chip
37
- :id="'timeline-minutes-' + index"
38
- dense flat outline :size="$q.screen.gt.sm ? '12px' : '10px'"
39
- :color="minute.color"
40
- :text-color="minute.textColor"
41
- :label="minute.label"
42
- clickable @click="onMinutesClicked(index)" />
43
- </template>
44
- </div>
45
- <div v-if="hours.length > 0" class="full-width row justify-center items-center">
46
- <q-btn id="timeline-previous-hour" dense flat round icon='las la-angle-left' color="primary" @click="onPreviousHourClicked">
47
- <q-tooltip>{{$t('KTimeline.PREVIOUS_HOUR')}}</q-tooltip>
48
- </q-btn>
49
- <template v-for="(hour, index) in hours" :key="index">
50
- <div :id="'timeline-hours-' + index" :class="hour.class"
51
- style="height: 25px" @click="onHourClicked(index, hours.length)">
52
- {{hour.label}}
53
- </div>
54
- </template>
55
- <q-btn id="timeline-next-hour" flat round icon='las la-angle-right' color="primary" @click="onNextHourClicked">
56
- <q-tooltip>{{$t('KTimeline.NEXT_HOUR')}}</q-tooltip>
57
- </q-btn>
58
- </div>
59
- <div class="row justify-center items-center">
60
- <q-btn id="timeline-previous-day" dense flat round icon='las la-calendar-minus' color="primary" @click="onPreviousDayClicked">
61
- <q-tooltip>{{$t('KTimeline.PREVIOUS_DAY')}}</q-tooltip>
62
- </q-btn>
63
- <template v-for="(day, index) in days" :key="index">
64
- <q-chip
65
- :id="'timeline-days-' + index"
66
- dense flat square outline size="md"
67
- :color="day.color"
68
- :text-color="day.textColor"
69
- :label="day.label"
70
- clickable @click="onDayClicked(index, days.length)" />
71
- </template>
72
- <q-btn id="timeline-next-day" dense flat round icon='las la-calendar-plus' color="primary" @click="onNextDayClicked">
73
- <q-tooltip>{{$t('KTimeline.NEXT_DAY')}}</q-tooltip>
74
- </q-btn>
75
- </div>
76
- </div>
77
- </div>
78
- </template>
79
-
80
- <script>
81
- import logger from 'loglevel'
82
- import moment from 'moment'
83
- import { Time } from '../../../core/client/time'
84
- import { KPanel } from '../../../core/client/components'
85
-
86
- export default {
87
- name: 'k-timeline',
88
- inject: ['kActivity'],
89
- components: {
90
- KPanel
91
- },
92
- data () {
93
- return {
94
- time: moment.utc(),
95
- calendarDateMask: 'YYYY-MM-DD',
96
- Time: Time.get()
97
- }
98
- },
99
- computed: {
100
- minutes () {
101
- const minutes = []
102
- if (this.Time.step < 60) {
103
- const start = moment.utc(this.time).minute(0)
104
- const end = moment.utc(this.time).minute(59)
105
- for (let m = moment.utc(start); m.isBefore(end); m.add(this.Time.step, 'm')) {
106
- minutes.push({
107
- label: m.minute().toString().padStart(2, 0),
108
- color: m.isSame(this.time, 'minute') ? 'primary' : 'grey-7',
109
- textColor: m.isSame(this.time, 'minute') ? 'white' : 'black'
110
- })
111
- }
112
- }
113
- return minutes
114
- },
115
- hours () {
116
- const hours = []
117
- let size = 0
118
- if (this.$q.screen.gt.xs) size = 2
119
- if (this.$q.screen.gt.sm) size = 5
120
- if (this.$q.screen.gt.md) size = 8
121
- if (this.$q.screen.gt.lg) size = 10
122
- const start = moment.utc(this.time).subtract(size, 'hour')
123
- const end = moment.utc(this.time).add((size + 1), 'hour')
124
- for (let h = moment.utc(start); h.isBefore(end); h.add(1, 'h')) {
125
- hours.push({
126
- label: Time.format(h, 'time.short'),
127
- class: 'col k-timeline-hour-frame text-caption ' + (h.isSame(this.time, 'hour') ? 'k-timeline-hour-selected' : '')
128
- })
129
- }
130
- return hours
131
- },
132
- days () {
133
- const days = []
134
- let size = 0
135
- if (this.$q.screen.gt.xs) size = 1
136
- if (this.$q.screen.gt.sm) size = 3
137
- if (this.$q.screen.gt.md) size = 5
138
- if (this.$q.screen.gt.lg) size = 7
139
- const start = moment.utc(this.time).subtract(size, 'day')
140
- const end = moment.utc(this.time).add(size + 1, 'day')
141
- for (let d = moment.utc(start); d.isBefore(end); d.add(1, 'd')) {
142
- days.push({
143
- label: Time.format(d, 'date.short'),
144
- color: d.isSame(this.time, 'date') ? 'primary' : this.monthColors[d.month()],
145
- textColor: d.isSame(this.time, 'date') ? 'white' : 'black'
146
- })
147
- }
148
- return days
149
- },
150
- date: {
151
- get: function () {
152
- // Assume locale if timezone not provided
153
- return Time.getFormatTimezone()
154
- ? moment(this.time).tz(Time.getFormatTimezone()).format(this.calendarDateMask)
155
- : moment(this.time).local().format(this.calendarDateMask)
156
- },
157
- set: function (value) {
158
- let time
159
- // Assume locale if timezone not provided
160
- if (Time.getFormatTimezone()) {
161
- time = moment.tz(value, this.calendarDateMask, Time.getFormatTimezone())
162
- } else {
163
- time = moment(value, this.calendarDateMask)
164
- }
165
- time.hour(this.time.hour())
166
- time.minute(this.time.minute())
167
- this.setTime(moment.utc(time))
168
- }
169
- }
170
- },
171
- methods: {
172
- formatTime (time, format) {
173
- return Time.format(time, format)
174
- },
175
- setTime (time, propagate = true) {
176
- if (!time.isValid()) {
177
- logger.error('the provided time is invalid')
178
- return
179
- }
180
- if (time.utcOffset() > 0) {
181
- logger.error('the provided time should be in UTC')
182
- return
183
- }
184
- this.time = time.clone()
185
- this.$events.off('time-current-time-changed', this.onTimeChanged)
186
- if (propagate) Time.setCurrentTime(moment.utc(time))
187
- this.$events.on('time-current-time-changed', this.onTimeChanged)
188
- },
189
- onPreviousStepClicked () {
190
- let minutesToSubtract = this.Time.step
191
- const remainder = (this.time.minute() + this.time.hour() * 60) % this.Time.step
192
- if (remainder > 0) {
193
- minutesToSubtract = remainder
194
- }
195
- this.setTime(this.time.subtract(minutesToSubtract, 'minute'))
196
- },
197
- onNextStepClicked () {
198
- let minutesToAdd = this.Time.step
199
- const remainder = (this.time.minute() + this.time.hour() * 60) % this.Time.step
200
- if (remainder > 0) {
201
- minutesToAdd = this.Time.step - remainder
202
- }
203
- this.setTime(this.time.add(minutesToAdd, 'minute'))
204
- },
205
- onMinutesClicked (index) {
206
- this.setTime(this.time.minute(index * this.Time.step))
207
- },
208
- onHourClicked (index, length) {
209
- this.setTime(this.time.add((index - Math.trunc(length / 2)), 'hour'))
210
- },
211
- onPreviousHourClicked () {
212
- this.setTime(this.time.subtract(1, 'hour'))
213
- },
214
- onNextHourClicked () {
215
- this.setTime(this.time.add(1, 'hour'))
216
- },
217
- onDayClicked (index, length) {
218
- this.setTime(this.time.add((index - Math.trunc(length / 2)), 'day'))
219
- },
220
- onPreviousDayClicked () {
221
- this.setTime(this.time.subtract(1, 'day'))
222
- },
223
- onNextDayClicked () {
224
- this.setTime(this.time.add(1, 'day'))
225
- },
226
- onNowClicked () {
227
- Time.startRealtime()
228
- },
229
- onTimeChanged (time) {
230
- // When updating settings the root time object is sent instead of just the current time
231
- this.setTime(time.currentTime || time, false)
232
- }
233
- },
234
- created () {
235
- // Define the colors assgigned to the months
236
- this.monthColors = ['red', 'purple', 'indigo', 'green', 'orange', 'green', 'pink', 'deep-purple', 'lime', 'teal', 'light-blue', 'amber']
237
- // Define the actions
238
- this.actions = {
239
- mobile: [
240
- { id: 'previous-day', icon: 'las la-calendar-minus', tooltip: this.$t('KTimeline.PREVIOUS_DAY'), handler: this.onPreviousDayClicked },
241
- { id: 'previous-hour', icon: 'las la-angle-left', tooltip: this.$t('KTimeline.PREVIOUS_HOUR'), handler: this.onPreviousHourClicked },
242
- { id: 'previous-step', icon: 'las la-step-backward', tooltip: this.$t('KTimeline.PREVIOUS_STEP'), handler: this.onPreviousStepClicked },
243
- { id: 'next-step', icon: 'las la-step-forward', tooltip: this.$t('KTimeline.NEXT_STEP'), handler: this.onNextStepClicked },
244
- { id: 'next-hour', icon: 'las la-angle-right', tooltip: this.$t('KTimeline.NEXT_HOUR'), handler: this.onNextHourClicked },
245
- { id: 'next-day', icon: 'las la-calendar-plus', tooltip: this.$t('KTimeline.NEXT_DAY'), handler: this.onNextDayClicked }
246
- ]
247
- }
248
- },
249
- mounted () {
250
- this.$events.on('time-current-time-changed', this.onTimeChanged)
251
- // Set the time
252
- this.setTime(Time.getCurrentTime(), false)
253
- },
254
- beforeUnmount () {
255
- this.$events.off('time-current-time-changed', this.onTimeChanged)
256
- }
257
- }
258
- </script>
259
-
260
- <style lang="scss">
261
- .k-timeline {
262
- background: #ffffff;
263
- border: solid 1px lightgrey;
264
- border-radius: 5px;
265
- width: 60vw;
266
- }
267
- .k-timeline:hover {
268
- border: solid 1px $primary;
269
- cursor: mouse;
270
- }
271
- .k-timeline-control {
272
- padding: 5px;
273
- border-bottom: solid 1px lightgrey;
274
- }
275
- .k-timeline-hour-frame {
276
- border-bottom: solid 5px $grey-5;
277
- border-left: solid 1px white;
278
- border-right: solid 1px white;
279
- text-align: center;
280
- vertical-align: middle;
281
- user-select: none; /* supported by Chrome and Opera */
282
- -webkit-user-select: none; /* Safari */
283
- -khtml-user-select: none; /* Konqueror HTML */
284
- -moz-user-select: none; /* Firefox */
285
- -ms-user-select: none; /* Internet Explorer/Edge */
286
- }
287
- .k-timeline-hour-selected {
288
- border-bottom: solid 5px $primary;
289
- }
290
- .k-timeline-hour-frame:hover {
291
- border-bottom: solid 5px $primary;
292
- }
293
- </style>
@@ -1,122 +0,0 @@
1
- <template>
2
- <div v-if="legends.length > 0" class="k-url-legend-container">
3
- <div v-for="legend, index in legends" @click="onLegendClick(index)" class="k-url-legend-item text-primary text-caption q-pa-xs q-ma-xs shadow-2">
4
- <div v-if="legend.visible">&blacktriangledown; {{legend.layer}}</div>
5
- <img v-if="legend.visible" :src="legend.src"/>
6
- <div v-if="!legend.visible">&blacktriangleright; {{legend.layer}}</div>
7
- </div>
8
- </div>
9
- </template>
10
-
11
- <script>
12
- import _ from 'lodash'
13
- import fetch from 'node-fetch'
14
- import * as wms from '../../common/wms-utils'
15
-
16
- export default {
17
- name: 'k-url-legend',
18
- inject: ['kActivity'],
19
- data () {
20
- return {
21
- legends: []
22
- }
23
- },
24
- methods: {
25
- onLegendClick (index) {
26
- this.legends[index].visible = !this.legends[index].visible
27
- },
28
- async getLegend (layer) {
29
- let legendUrl = _.get(layer, 'legendUrl')
30
- if (!legendUrl) {
31
- // no legend on layer, try to fetch legend in case of WMS layer
32
- if (_.get(layer, 'leaflet.type') === 'tileLayer.wms') {
33
- // leaflet wms layer uses every other options as request extra parameters
34
- const leafletOptions = [
35
- 'type', 'source', 'isVisible', // these are kdk specific
36
- 'layers', 'styles', 'format', 'transparent', 'version', 'crs', 'uppercase' // these are leaflet specific
37
- ]
38
- const searchParams = _.omit(layer.leaflet, leafletOptions)
39
- // lookup wms parameters on the leaflet layer parameters
40
- legendUrl = wms.makeGetLegendGraphic(
41
- layer.leaflet.source,
42
- _.get(layer.leaflet, 'version', '1.0.0'),
43
- layer.leaflet.layers,
44
- _.get(layer.leaflet, 'styles'),
45
- searchParams)
46
- }
47
- // TODO: might try in case of WMTS layer too
48
- }
49
-
50
- // make sure server answers the request before using it
51
- if (legendUrl) {
52
- try {
53
- const response = await fetch(legendUrl)
54
- // additional check for funny servers answering with empty body ...
55
- if (response.ok) {
56
- const asBlob = await response.blob()
57
- if (asBlob.size === 0) legendUrl = null
58
- }
59
- } catch (error) {
60
- legendUrl = null
61
- }
62
- }
63
-
64
- return legendUrl
65
- },
66
- async tryAddLegend (layer) {
67
- const legendUrl = await this.getLegend(layer)
68
- if (legendUrl) {
69
- // make sure layer is still visible since it may have been hidden in the meantime ...
70
- if (this.kActivity.isLayerVisible(layer.name)) {
71
- this.legends.push({
72
- src: legendUrl,
73
- layer: layer.label || layer.name,
74
- visible: true
75
- })
76
- }
77
- }
78
- },
79
- async tryRemoveLegend (layer) {
80
- const legendUrl = await this.getLegend(layer)
81
- if (legendUrl) {
82
- const index = this.legends.findIndex((legend) => legend.src === legendUrl)
83
- this.legends.splice(index, 1)
84
- }
85
- },
86
- onShowLayer (layer, engineLayer) {
87
- this.tryAddLegend(layer)
88
- },
89
- onHideLayer (layer) {
90
- this.tryRemoveLegend(layer)
91
- }
92
- },
93
- mounted () {
94
- this.kActivity.$engineEvents.on('layer-shown', this.onShowLayer)
95
- this.kActivity.$engineEvents.on('layer-hidden', this.onHideLayer)
96
-
97
- // initial scan of already added layers
98
- this.kActivity.getLayers().forEach((layer) => {
99
- if (this.kActivity.isLayerVisible(layer.name)) {
100
- this.tryAddLegend(layer)
101
- }
102
- })
103
- },
104
- beforeUnmount () {
105
- this.kActivity.$engineEvents.off('layer-shown', this.onShowLayer)
106
- this.kActivity.$engineEvents.off('layer-hidden', this.onHideLayer)
107
- }
108
- }
109
- </script>
110
-
111
- <style lang="scss">
112
- .k-url-legend-container {
113
- display: flex;
114
- flex-direction: column;
115
- align-items: flex-start;
116
- }
117
- .k-url-legend-item {
118
- text-overflow: ellipsis;
119
- cursor: pointer;
120
- background-color: rgba(255, 255, 255, 0.5);
121
- }
122
- </style>
@@ -1,246 +0,0 @@
1
- import _ from 'lodash'
2
- import L from 'leaflet'
3
- import { utils as kdkCoreUtils } from '../../../core/client/index.js'
4
-
5
- export const LeafletStyleMappings = {
6
- 'z-index': 'pane',
7
- pane: 'pane',
8
- stroke: 'color',
9
- 'stroke-color': 'color',
10
- 'stroke-opacity': 'opacity',
11
- 'stroke-width': 'weight',
12
- fill: 'fillColor',
13
- 'fill-opacity': 'fillOpacity',
14
- 'fill-color': 'fillColor',
15
- weight: 'weight',
16
- radius: 'radius',
17
- 'line-cap': 'lineCap',
18
- 'line-join': 'lineJoin',
19
- 'dash-array': 'dashArray',
20
- 'dash-offset': 'dashOffset',
21
- 'marker-size': 'icon.options.iconSize',
22
- 'marker-symbol': 'icon.options.iconUrl',
23
- 'marker-color': 'icon.options.markerColor',
24
- 'marker-type': 'type',
25
- 'icon-color': 'icon.options.iconColor',
26
- 'icon-size': 'icon.options.iconSize',
27
- 'icon-anchor': 'icon.options.iconAnchor',
28
- 'icon-classes': 'icon.options.iconClasses',
29
- 'icon-html': 'icon.options.html',
30
- 'icon-class': 'icon.options.className',
31
- 'icon-x-offset': 'icon.options.iconXOffset',
32
- 'icon-y-offset': 'icon.options.iconYOffset'
33
- }
34
- export const LeafletStyleOptions = _.values(LeafletStyleMappings)
35
-
36
- // Get the unique global symbol to store event listeners on a leaflet object
37
- const LISTENERS_KEY = Symbol.for('leaflet-event-listeners')
38
- // Bind a set of events on given Leaflet object to a vue component
39
- export function bindLeafletEvents (object, events, component, options) {
40
- object[LISTENERS_KEY] = []
41
- events.forEach(eventName => {
42
- const listener = (...args) => {
43
- if (options) component.$engineEvents.emit(eventName, options, ...args)
44
- else component.$engineEvents.emit(eventName, ...args)
45
- }
46
- object[LISTENERS_KEY].push(listener)
47
- object.on(eventName, listener)
48
- })
49
- }
50
-
51
- export function unbindLeafletEvents (object, events) {
52
- const listeners = object[LISTENERS_KEY]
53
- if (listeners) {
54
- events.forEach((eventName, index) => {
55
- object.off(eventName, object[LISTENERS_KEY][index])
56
- })
57
- delete object[LISTENERS_KEY]
58
- }
59
- }
60
-
61
- export const LeafletEvents = {
62
- Map: ['baselayerchange', 'overlayadd', 'overlayremove', 'layeradd', 'layerremove', 'zoomlevelschange',
63
- 'resize', 'unload', 'viewreset', 'load',
64
- 'zoomstart', 'boxzoomstart', 'boxselectionstart', 'movestart',
65
- 'zoom', 'move',
66
- 'zoomend', 'boxzoomend', 'boxselectionend', 'moveend',
67
- 'click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout', 'mousemove', 'contextmenu',
68
- 'keypress', 'preclick', 'moveend', 'zoomanim', 'fullscreenchange'],
69
- Popup: ['add', 'remove'],
70
- Tooltip: ['add', 'remove'],
71
- Layer: ['add', 'remove', 'popupopen', 'popupclose', 'tooltipopen', 'tooltipclose'],
72
- Feature: ['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout', 'contextmenu',
73
- 'dragstart', 'dragend', 'drag', 'movestart', 'moveend', 'move'],
74
- Cluster: ['spiderfied', 'unspiderfied']
75
- }
76
-
77
- export function createLeafletMarkerFromStyle (latlng, markerStyle, feature) {
78
- if (markerStyle) {
79
- let icon = markerStyle.icon
80
- // Parse icon options to get icon object if any
81
- if (icon) {
82
- const iconOptions = icon.options || icon
83
- const options = markerStyle.options || markerStyle
84
- icon = _.get(L, icon.type)(iconOptions)
85
- return _.get(L, markerStyle.type || 'marker')(latlng, Object.assign(_.omit(options, ['icon']), { icon }))
86
- } else {
87
- const options = markerStyle.options || markerStyle
88
- return _.get(L, markerStyle.type || 'marker')(latlng, options)
89
- }
90
- } else {
91
- return L.marker(latlng)
92
- }
93
- }
94
-
95
- export function convertToLeafletFromSimpleStyleSpec (style, inPlace) {
96
- if (!style) return {}
97
- const convertedStyle = (inPlace ? style : {})
98
- // Compute flags first because if updating in place options in style spec will be replaced
99
- const isHtml = _.has(style, 'icon-html')
100
- const hasClass = _.has(style, 'icon-class')
101
- const isFontAwesome = _.has(style, 'icon-classes')
102
- let isIconSpec = _.has(style, 'icon')
103
- // First copy any icon spec as not supported by simple style spec
104
- if (isIconSpec) _.set(convertedStyle, 'icon', _.get(style, 'icon'))
105
- _.forOwn(style, (value, key) => {
106
- if (_.has(LeafletStyleMappings, key)) {
107
- const mapping = _.get(LeafletStyleMappings, key)
108
- // Specific options
109
- switch (key) {
110
- case 'icon-size':
111
- case 'icon-anchor':
112
- case 'marker-size':
113
- if (!Array.isArray(value)) value = [value, value]
114
- _.set(convertedStyle, mapping, value)
115
- break
116
- default:
117
- _.set(convertedStyle, mapping, value)
118
- }
119
- if (inPlace) _.unset(style, key)
120
- // In this case we have a marker with icon spec
121
- if (mapping.startsWith('icon')) isIconSpec = true
122
- }
123
- })
124
- if (isIconSpec) {
125
- // Select the right icon type based on options if not already set
126
- if (!_.has(style, 'icon.type')) _.set(convertedStyle, 'icon.type', (isFontAwesome ? 'icon.fontAwesome' : isHtml ? 'divIcon' : 'icon'))
127
- // Leaflet adds a default background style but we prefer to remove it
128
- if (isHtml && !hasClass) _.set(convertedStyle, 'icon.options.className', '')
129
- _.set(convertedStyle, 'type', 'marker')
130
- }
131
- // Manage panes to make z-index work for all types of layers,
132
- // pane name can actually be a z-index value
133
- if (_.has(convertedStyle, 'pane')) _.set(convertedStyle, 'pane', _.get(convertedStyle, 'pane').toString())
134
- if (_.has(convertedStyle, 'shadowPane')) _.set(convertedStyle, 'shadowPane', _.get(convertedStyle, 'shadowPane').toString())
135
- return convertedStyle
136
- }
137
-
138
- export function getHtmlTable (properties) {
139
- properties = kdkCoreUtils.dotify(properties)
140
- properties = _.pickBy(properties, value => !_.isNil(value))
141
- const keys = _.keys(properties)
142
- let html
143
- if (keys.length === 0) return null
144
- else if (keys.length === 1) html = _.get(properties, keys[0])
145
- else {
146
- const borderStyle = ' style="border: 1px solid black; border-collapse: collapse;"'
147
- html = '<table' + borderStyle + '>'
148
- html += keys
149
- .map(key => '<tr' + borderStyle + '><th' +
150
- borderStyle + '>' + key + '</th><th>' + _.get(properties, key) + '</th></tr>')
151
- .join('')
152
- html += '</table>'
153
- }
154
- return html
155
- }
156
-
157
- export function tile2key (coords) {
158
- // JS Number.MAX_SAFE_INTEGER = 2^53 - 1, so 53 bits available
159
- // put z value on 5 bits (0 - 32)
160
- // put y value on 24 bits (0 - 16777216)
161
- // put x value on 24 bits (0 - 16777216)
162
- // shift y by 5 bits (* 32)
163
- // shift x by 5+24 bits (* 536870912)
164
- return (coords.x * 536870912) + (coords.y * 32) + coords.z
165
- }
166
-
167
- export function key2tile (key) {
168
- // JS Number.MAX_SAFE_INTEGER = 2^53 - 1, so 53 bits available
169
- // put z value on 5 bits (0 - 32)
170
- // put y value on 24 bits (0 - 16777216)
171
- // put x value on 24 bits (0 - 16777216)
172
- // shift y by 5 bits (* 32)
173
- // shift x by 5+24 bits (* 536870912)
174
- const x = Math.floor(key / 536870912)
175
- const y = Math.floor((key - (x * 536870912)) / 32)
176
- const p = L.point(x, y)
177
- p.z = key - ((x * 536870912) + (y * 32))
178
- return p
179
- }
180
-
181
- export function tileSetContainsParent (tileset, coords) {
182
- const triplet = {
183
- x: coords.x,
184
- y: coords.y,
185
- z: coords.z
186
- }
187
-
188
- while (triplet.z > 1) {
189
- const tilekey = tile2key(triplet)
190
- if (tileset.has(tilekey)) return true
191
-
192
- triplet.x = Math.floor(triplet.x / 2)
193
- triplet.y = Math.floor(triplet.y / 2)
194
- triplet.z -= 1
195
- }
196
-
197
- return false
198
- }
199
-
200
- export function getParentTileInTileSet (tileset, coords) {
201
- const triplet = {
202
- x: coords.x,
203
- y: coords.y,
204
- z: coords.z
205
- }
206
-
207
- triplet.x = Math.floor(triplet.x / 2)
208
- triplet.y = Math.floor(triplet.y / 2)
209
- triplet.z -= 1
210
-
211
- while (triplet.z > 1) {
212
- const tilekey = tile2key(triplet)
213
- if (tileset.has(tilekey)) return triplet
214
-
215
- triplet.x = Math.floor(triplet.x / 2)
216
- triplet.y = Math.floor(triplet.y / 2)
217
- triplet.z -= 1
218
- }
219
-
220
- return undefined
221
- }
222
-
223
- export function computeIdealMaxNativeZoom (gridLayer, dataSetBounds, dataSetTileSize) {
224
- // compute optimal maxNativeZoom value to ensure
225
- // the smallest leaflet tile will approximately match a dataset tile
226
-
227
- // compute tile size farthest from equator
228
- const nw = dataSetBounds.getNorthWest()
229
- let z = 1
230
- while (true) {
231
- const nwPoint = gridLayer._map.project(nw, z)
232
- const coords = nwPoint.unscaleBy(gridLayer.getTileSize())
233
- coords.x = Math.floor(coords.x)
234
- coords.y = Math.floor(coords.y)
235
- coords.z = z
236
-
237
- const tileBounds = gridLayer._tileCoordsToBounds(coords)
238
- const tileWidth = tileBounds.getEast() - tileBounds.getWest()
239
- const tileHeight = tileBounds.getNorth() - tileBounds.getSouth()
240
- if (tileWidth < dataSetTileSize.lng || tileHeight < dataSetTileSize.lat) break
241
-
242
- z += 1
243
- }
244
-
245
- return Math.max(1, z - 1)
246
- }