qwc2 2025.11.15 → 2025.11.19

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 (42) hide show
  1. package/actions/windows.js +3 -1
  2. package/components/AttributeTableWidget.js +12 -6
  3. package/components/ResizeableWindow.js +3 -1
  4. package/components/ThemeLayersListWindow.js +14 -4
  5. package/components/WindowManager.js +14 -1
  6. package/components/map3d/Map3D.js +35 -34
  7. package/components/map3d/layers/GeoTIFFLayer3D.js +2 -1
  8. package/components/map3d/layers/VectorLayer3D.js +10 -0
  9. package/components/map3d/layers/WFSLayer3D.js +17 -1
  10. package/components/style/WindowManager.css +6 -0
  11. package/package.json +2 -2
  12. package/plugins/API.js +1 -0
  13. package/plugins/Editing.js +1 -1
  14. package/plugins/map/RedliningSupport.js +2 -2
  15. package/reducers/windows.js +2 -1
  16. package/static/translations/bg-BG.json +1 -0
  17. package/static/translations/ca-ES.json +1 -0
  18. package/static/translations/cs-CZ.json +1 -0
  19. package/static/translations/de-CH.json +1 -0
  20. package/static/translations/de-DE.json +1 -0
  21. package/static/translations/en-US.json +1 -0
  22. package/static/translations/es-ES.json +1 -0
  23. package/static/translations/fi-FI.json +1 -0
  24. package/static/translations/fr-FR.json +2 -1
  25. package/static/translations/hu-HU.json +1 -0
  26. package/static/translations/it-IT.json +1 -0
  27. package/static/translations/ja-JP.json +1 -0
  28. package/static/translations/nl-NL.json +1 -0
  29. package/static/translations/no-NO.json +1 -0
  30. package/static/translations/pl-PL.json +1 -0
  31. package/static/translations/pt-BR.json +1 -0
  32. package/static/translations/pt-PT.json +1 -0
  33. package/static/translations/ro-RO.json +1 -0
  34. package/static/translations/ru-RU.json +1 -0
  35. package/static/translations/sv-SE.json +1 -0
  36. package/static/translations/tr-TR.json +1 -0
  37. package/static/translations/tsconfig.json +1 -0
  38. package/static/translations/uk-UA.json +1 -0
  39. package/utils/EditingUtils.js +0 -1
  40. package/utils/LayerUtils.js +1 -1
  41. package/utils/ServiceLayerUtils.js +1 -1
  42. package/utils/ThemeUtils.js +2 -1
@@ -52,12 +52,14 @@ export function showIframeDialog(name, url, options) {
52
52
  export function showNotification(name, text) {
53
53
  var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : NotificationType.INFO;
54
54
  var sticky = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
55
+ var actions = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : [];
55
56
  return {
56
57
  type: SHOW_NOTIFICATION,
57
58
  name: name,
58
59
  text: text,
59
60
  notificationType: type,
60
- sticky: sticky
61
+ sticky: sticky,
62
+ actions: actions
61
63
  };
62
64
  }
63
65
  export function closeWindow(name) {
@@ -119,7 +119,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
119
119
  filteredSortedFeatures: _this.filteredSortedFeatures(features, state2),
120
120
  loadedLayer: selectedLayer,
121
121
  curEditConfig: editConfig,
122
- curFieldTranslations: fieldTranslations
122
+ fieldTranslations: fieldTranslations
123
123
  };
124
124
  });
125
125
  } else {
@@ -942,15 +942,22 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
942
942
  wmsName = _ref5[0],
943
943
  serviceConfigs = _ref5[1];
944
944
  return Object.entries(serviceConfigs).map(function (_ref6) {
945
- var _ref8, _ref9, _match$layer$translat, _match$layer$translat2, _match$sublayer;
946
945
  var _ref7 = _slicedToArray(_ref6, 2),
947
946
  layerName = _ref7[0],
948
947
  editConfig = _ref7[1];
949
948
  var match = LayerUtils.searchLayer(_this2.props.layers, 'wms_name', wmsName, 'name', layerName);
950
- if (!match) {
951
- return null;
949
+ var layerTitle = layerName;
950
+ if (match) {
951
+ var _ref8, _ref9, _match$layer$translat, _match$layer$translat2, _match$sublayer;
952
+ layerTitle = (_ref8 = (_ref9 = (_match$layer$translat = (_match$layer$translat2 = match.layer.translations) === null || _match$layer$translat2 === void 0 || (_match$layer$translat2 = _match$layer$translat2.layertree) === null || _match$layer$translat2 === void 0 ? void 0 : _match$layer$translat2[layerName]) !== null && _match$layer$translat !== void 0 ? _match$layer$translat : editConfig.layerTitle) !== null && _ref9 !== void 0 ? _ref9 : match === null || match === void 0 || (_match$sublayer = match.sublayer) === null || _match$sublayer === void 0 ? void 0 : _match$sublayer.title) !== null && _ref8 !== void 0 ? _ref8 : layerName;
953
+ } else {
954
+ var _this2$props$layers$f, _ref10, _translations$layertr, _translations$layertr2;
955
+ // Note: geometry-less tables are filtered from the theme sublayers
956
+ var translations = (_this2$props$layers$f = _this2.props.layers.find(function (layer) {
957
+ return layer.wms_name === wmsName;
958
+ })) === null || _this2$props$layers$f === void 0 ? void 0 : _this2$props$layers$f.translations;
959
+ layerTitle = (_ref10 = (_translations$layertr = translations === null || translations === void 0 || (_translations$layertr2 = translations.layertree) === null || _translations$layertr2 === void 0 ? void 0 : _translations$layertr2[layerName]) !== null && _translations$layertr !== void 0 ? _translations$layertr : editConfig.layerTitle) !== null && _ref10 !== void 0 ? _ref10 : layerName;
952
960
  }
953
- var layerTitle = (_ref8 = (_ref9 = (_match$layer$translat = (_match$layer$translat2 = match.layer.translations) === null || _match$layer$translat2 === void 0 || (_match$layer$translat2 = _match$layer$translat2.layertree) === null || _match$layer$translat2 === void 0 ? void 0 : _match$layer$translat2[layerName]) !== null && _match$layer$translat !== void 0 ? _match$layer$translat : editConfig.layerTitle) !== null && _ref9 !== void 0 ? _ref9 : match === null || match === void 0 || (_match$sublayer = match.sublayer) === null || _match$sublayer === void 0 ? void 0 : _match$sublayer.title) !== null && _ref8 !== void 0 ? _ref8 : layerName;
954
961
  var value = wmsName + "#" + layerName;
955
962
  return /*#__PURE__*/React.createElement("option", {
956
963
  key: value,
@@ -1081,7 +1088,6 @@ _defineProperty(AttributeTableWidget, "defaultState", {
1081
1088
  selectedLayer: "",
1082
1089
  loadedLayer: "",
1083
1090
  curEditConfig: null,
1084
- curTranslations: null,
1085
1091
  fieldTranslations: null,
1086
1092
  features: [],
1087
1093
  filteredSortedFeatures: [],
@@ -274,7 +274,8 @@ var ResizeableWindow = /*#__PURE__*/function (_React$Component) {
274
274
  width: width,
275
275
  height: height,
276
276
  docked: _this.props.initiallyDocked,
277
- detached: false
277
+ detached: false,
278
+ minimized: _this.props.initiallyMinimized || false
278
279
  };
279
280
  }
280
281
  if (_this.props.splitScreenWhenDocked && geometry.docked) {
@@ -537,6 +538,7 @@ _defineProperty(ResizeableWindow, "propTypes", {
537
538
  initialX: PropTypes.number,
538
539
  initialY: PropTypes.number,
539
540
  initiallyDocked: PropTypes.bool,
541
+ initiallyMinimized: PropTypes.bool,
540
542
  mapMargins: PropTypes.object,
541
543
  maxHeight: PropTypes.number,
542
544
  maxWidth: PropTypes.number,
@@ -35,7 +35,7 @@ import PropTypes from 'prop-types';
35
35
  import { LayerRole, addLayer } from '../actions/layers';
36
36
  import { setCurrentTask } from '../actions/task';
37
37
  import { setThemeLayersList } from '../actions/theme';
38
- import { showNotification, closeWindow } from '../actions/windows';
38
+ import { showNotification, closeWindow, NotificationType } from '../actions/windows';
39
39
  import LayerUtils from '../utils/LayerUtils';
40
40
  import LocaleUtils from '../utils/LocaleUtils';
41
41
  import ThemeUtils from '../utils/ThemeUtils';
@@ -70,14 +70,23 @@ var ThemeLayersListWindow = /*#__PURE__*/function (_React$Component) {
70
70
  var filteredSublayers = [];
71
71
  sublayers = sublayers.filter(function (sublayer) {
72
72
  if (existingSublayers.includes(sublayer.name)) {
73
- filteredSublayers.push(sublayer.title);
73
+ filteredSublayers.push(sublayer);
74
74
  return false;
75
75
  }
76
76
  return true;
77
77
  });
78
78
  if (!isEmpty(filteredSublayers)) {
79
- var text = LocaleUtils.tr("themelayerslist.existinglayers") + ": " + filteredSublayers.join(",");
80
- _this.props.showNotification("existinglayers", text);
79
+ var text = LocaleUtils.tr("themelayerslist.existinglayers") + ": " + filteredSublayers.map(function (l) {
80
+ return l.title;
81
+ }).join(", ");
82
+ var actions = [{
83
+ name: LocaleUtils.tr("themelayerslist.addanyway"),
84
+ onClick: function onClick() {
85
+ _this.props.addLayer(ThemeUtils.createThemeLayer(_this.props.theme, _this.props.themes, LayerRole.USERLAYER, filteredSublayers));
86
+ return true;
87
+ }
88
+ }];
89
+ _this.props.showNotification("existinglayers", text, NotificationType.INFO, false, actions);
81
90
  }
82
91
  }
83
92
  if (!isEmpty(sublayers)) {
@@ -108,6 +117,7 @@ var ThemeLayersListWindow = /*#__PURE__*/function (_React$Component) {
108
117
  }
109
118
  });
110
119
  _defineProperty(_this, "onClose", function () {
120
+ _this.props.closeWindow("existinglayers");
111
121
  _this.props.setThemeLayersList(null);
112
122
  });
113
123
  return _this;
@@ -32,6 +32,7 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
32
32
 
33
33
  import React from 'react';
34
34
  import { connect } from 'react-redux';
35
+ import isEmpty from 'lodash.isempty';
35
36
  import PropTypes from 'prop-types';
36
37
  import { closeWindow, closeAllWindows, NotificationType } from '../actions/windows';
37
38
  import LocaleUtils from '../utils/LocaleUtils';
@@ -92,7 +93,19 @@ var WindowManager = /*#__PURE__*/function (_React$Component) {
92
93
  return /*#__PURE__*/React.createElement("div", {
93
94
  className: className,
94
95
  key: key
95
- }, /*#__PURE__*/React.createElement("div", null, data.text), /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(Icon, {
96
+ }, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", null, data.text), !isEmpty(data.actions) ? /*#__PURE__*/React.createElement("div", {
97
+ className: "windows-notification-actions"
98
+ }, data.actions.map(function (action, idx) {
99
+ return /*#__PURE__*/React.createElement("button", {
100
+ className: "button",
101
+ key: "action" + idx,
102
+ onClick: function onClick() {
103
+ var res = action.onClick();
104
+ if (res) _this.closeWindow(key);
105
+ },
106
+ type: "button"
107
+ }, action.name);
108
+ })) : null), /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(Icon, {
96
109
  icon: "remove",
97
110
  onClick: function onClick() {
98
111
  return _this.closeWindow(key);
@@ -37,10 +37,12 @@ import React, { Suspense } from 'react';
37
37
  import ReactDOM from 'react-dom';
38
38
  import { connect } from 'react-redux';
39
39
  import Instance from '@giro3d/giro3d/core/Instance.js';
40
- import Coordinates from '@giro3d/giro3d/core/geographic/Coordinates';
40
+ import Coordinates, { crsIsGeographic } from '@giro3d/giro3d/core/geographic/Coordinates';
41
+ import Ellipsoid from '@giro3d/giro3d/core/geographic/Ellipsoid';
41
42
  import Extent from '@giro3d/giro3d/core/geographic/Extent.js';
43
+ import CoordinateSystem from '@giro3d/giro3d/core/geographic/coordinate-system/CoordinateSystem';
42
44
  import ElevationLayer from '@giro3d/giro3d/core/layer/ElevationLayer.js';
43
- import FeatureCollection from "@giro3d/giro3d/entities/FeatureCollection.js";
45
+ import DrapedFeatureCollection from '@giro3d/giro3d/entities/DrapedFeatureCollection';
44
46
  import Map from '@giro3d/giro3d/entities/Map.js';
45
47
  import Tiles3D from "@giro3d/giro3d/entities/Tiles3D.js";
46
48
  import Inspector from "@giro3d/giro3d/gui/Inspector.js";
@@ -212,7 +214,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
212
214
  colorLayers[layer.id] = _objectSpread(_objectSpread({}, layer), {}, {
213
215
  visibility: (_prevOptions$visibili = prevOptions === null || prevOptions === void 0 ? void 0 : prevOptions.visibility) !== null && _prevOptions$visibili !== void 0 ? _prevOptions$visibili : false,
214
216
  opacity: (_prevOptions$opacity = prevOptions === null || prevOptions === void 0 ? void 0 : prevOptions.opacity) !== null && _prevOptions$opacity !== void 0 ? _prevOptions$opacity : 255,
215
- extrusionHeight: (_prevOptions$extrusio = prevOptions === null || prevOptions === void 0 ? void 0 : prevOptions.extrusionHeight) !== null && _prevOptions$extrusio !== void 0 ? _prevOptions$extrusio : ['vector', 'wfs'].includes(layer.type) ? 0 : undefined,
217
+ extrusionHeight: (_prevOptions$extrusio = prevOptions === null || prevOptions === void 0 ? void 0 : prevOptions.extrusionHeight) !== null && _prevOptions$extrusio !== void 0 ? _prevOptions$extrusio : layerCreator.createFeatureSource ? 0 : undefined,
216
218
  fields: (_prevOptions$fields = prevOptions === null || prevOptions === void 0 ? void 0 : prevOptions.fields) !== null && _prevOptions$fields !== void 0 ? _prevOptions$fields : undefined,
217
219
  sublayers: _preserveSublayerOptions(layer, prevOptions)
218
220
  });
@@ -250,9 +252,9 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
250
252
  mapLayer.visible = options.visibility;
251
253
  mapLayer.opacity = options.opacity / 255;
252
254
  layerBelow = mapLayer;
253
- if (options.extrusionHeight !== 0) {
254
- _this2.createUpdateExtrudedLayer(mapLayer, options, options.features !== (prevOptions === null || prevOptions === void 0 ? void 0 : prevOptions.features));
255
- } else if ((prevOptions === null || prevOptions === void 0 ? void 0 : prevOptions.extrusionHeight) !== 0) {
255
+ if (options.extrusionHeight !== undefined && options.extrusionHeight !== 0) {
256
+ _this2.createUpdateExtrudedLayer(layerCreator, mapLayer, options, options.features !== (prevOptions === null || prevOptions === void 0 ? void 0 : prevOptions.features));
257
+ } else if ((prevOptions === null || prevOptions === void 0 ? void 0 : prevOptions.extrusionHeight) !== undefined && (prevOptions === null || prevOptions === void 0 ? void 0 : prevOptions.extrusionHeight) !== 0) {
256
258
  _this2.removeExtrudedLayer(options.id);
257
259
  }
258
260
  });
@@ -262,7 +264,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
262
264
  layerId = _ref4[0],
263
265
  options = _ref4[1];
264
266
  if (!(layerId in colorLayers)) {
265
- if (options.extrusionHeight !== 0) {
267
+ if (options.extrusionHeight !== undefined && options.extrusionHeight !== 0) {
266
268
  _this2.removeExtrudedLayer(options.id);
267
269
  }
268
270
  _this2.removeLayer(layerId);
@@ -270,11 +272,9 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
270
272
  });
271
273
  _this2.instance.notifyChange(_this2.map);
272
274
  });
273
- _defineProperty(_this2, "createUpdateExtrudedLayer", function (mapLayer, options) {
275
+ _defineProperty(_this2, "createUpdateExtrudedLayer", function (layerCreator, mapLayer, options) {
274
276
  var _options$features, _options$features$red;
275
- var forceCreate = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
276
- var bounds = options.bbox.bounds;
277
- var extent = new Extent(options.bbox.crs, bounds[0], bounds[2], bounds[1], bounds[3]);
277
+ var forceCreate = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
278
278
  var objId = options.id + ":extruded";
279
279
  var makeColor = function makeColor(c) {
280
280
  if (Array.isArray(c)) {
@@ -292,20 +292,9 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
292
292
  _this2.instance.remove(obj);
293
293
  }
294
294
  var layercolor = makeColor((_options$color = options.color) !== null && _options$color !== void 0 ? _options$color : "#FF0000");
295
- obj = new FeatureCollection({
296
- source: mapLayer.source.source,
297
- extent: extent,
298
- minLevel: 1,
299
- maxLevel: 1,
300
- ignoreZ: true,
301
- elevation: function elevation(feature) {
302
- var _this2$getTerrainHeig;
303
- var coordinates = feature.getGeometry().getCoordinates();
304
- while (Array.isArray(coordinates[0])) {
305
- coordinates = coordinates[0];
306
- }
307
- return (_this2$getTerrainHeig = _this2.getTerrainHeightFromMap(coordinates)) !== null && _this2$getTerrainHeig !== void 0 ? _this2$getTerrainHeig : 0;
308
- },
295
+ obj = new DrapedFeatureCollection({
296
+ source: layerCreator.createFeatureSource(mapLayer, options, _this2.state.sceneContext.mapCrs),
297
+ drapingMode: 'per-feature',
309
298
  extrusionOffset: function extrusionOffset(feature) {
310
299
  if (typeof obj.userData.extrusionHeight === "string") {
311
300
  return parseFloat(feature.getProperties()[obj.userData.extrusionHeight]) || 0;
@@ -325,7 +314,9 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
325
314
  });
326
315
  obj.castShadow = true;
327
316
  obj.receiveShadow = true;
328
- _this2.instance.add(obj);
317
+ _this2.instance.add(obj).then(function () {
318
+ obj.attach(_this2.map);
319
+ });
329
320
  _this2.objectMap[objId] = obj;
330
321
  }
331
322
  obj.userData.extrusionHeight = options.extrusionHeight;
@@ -339,7 +330,9 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
339
330
  }, {});
340
331
  obj.opacity = mapLayer.opacity;
341
332
  obj.visible = mapLayer.visible;
342
- obj.updateStyles();
333
+ if (obj.visible) {
334
+ obj.updateStyles();
335
+ }
343
336
  });
344
337
  _defineProperty(_this2, "removeExtrudedLayer", function (layerId) {
345
338
  var objId = layerId + ":extruded";
@@ -602,23 +595,25 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
602
595
  return;
603
596
  }
604
597
  var projection = _this2.props.theme.mapCrs;
598
+ var crs = CoordinateSystem.fromSrid(projection);
605
599
 
606
600
  // Setup instance
607
601
  _this2.instance = new Instance({
608
602
  target: _this2.container,
609
- crs: projection,
603
+ crs: crs,
610
604
  renderer: {
611
605
  clearColor: 0x000000,
612
606
  preserveDrawingBuffer: true
613
607
  }
614
608
  });
615
609
  _this2.sceneObjectGroup = new Group();
610
+ _this2.sceneObjectGroup.name = "sceneObjects";
616
611
  _this2.instance.add(_this2.sceneObjectGroup);
617
612
 
618
613
  // Setup map
619
614
  var initialBbox = (_this2$props$theme$ma = (_this2$props$theme$ma2 = _this2.props.theme.map3d) === null || _this2$props$theme$ma2 === void 0 ? void 0 : _this2$props$theme$ma2.extent) !== null && _this2$props$theme$ma !== void 0 ? _this2$props$theme$ma : _this2.props.theme.initialBbox;
620
615
  var bounds = CoordinatesUtils.reprojectBbox(initialBbox.bounds, initialBbox.crs, projection);
621
- var extent = new Extent(projection, bounds[0], bounds[2], bounds[1], bounds[3]);
616
+ var extent = new Extent(crs, bounds[0], bounds[2], bounds[1], bounds[3]);
622
617
  _this2.map = new Map({
623
618
  extent: extent,
624
619
  backgroundColor: "white"
@@ -627,7 +622,12 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
627
622
 
628
623
  // Setup camera
629
624
  var center = extent.center();
630
- _this2.instance.view.camera.position.set(center.x, center.y, 0.5 * (extent.east - extent.west));
625
+ if (crsIsGeographic(center.crs)) {
626
+ var position = Ellipsoid.WGS84.toCartesian(center.latitude, center.longitude, center.altitude);
627
+ _this2.instance.view.camera.position.set(position.x, position.y, 0.5 * (extent.east - extent.west));
628
+ } else {
629
+ _this2.instance.view.camera.position.set(center.x, center.y, 0.5 * (extent.east - extent.west));
630
+ }
631
631
 
632
632
  // Skybox
633
633
  var cubeTextureLoader = new CubeTextureLoader();
@@ -637,7 +637,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
637
637
 
638
638
  // Setup elevation
639
639
  var demUrl = MiscUtils.resolveAssetsPath((_this2$props$theme$ma3 = (_this2$props$theme$ma4 = _this2.props.theme.map3d) === null || _this2$props$theme$ma4 === void 0 || (_this2$props$theme$ma4 = _this2$props$theme$ma4.dtm) === null || _this2$props$theme$ma4 === void 0 ? void 0 : _this2$props$theme$ma4.url) !== null && _this2$props$theme$ma3 !== void 0 ? _this2$props$theme$ma3 : "");
640
- var demCrs = ((_this2$props$theme$ma5 = _this2.props.theme.map3d) === null || _this2$props$theme$ma5 === void 0 || (_this2$props$theme$ma5 = _this2$props$theme$ma5.dtm) === null || _this2$props$theme$ma5 === void 0 ? void 0 : _this2$props$theme$ma5.crs) || "EPSG:3857";
640
+ var demCrs = CoordinateSystem.fromSrid(((_this2$props$theme$ma5 = _this2.props.theme.map3d) === null || _this2$props$theme$ma5 === void 0 || (_this2$props$theme$ma5 = _this2$props$theme$ma5.dtm) === null || _this2$props$theme$ma5 === void 0 ? void 0 : _this2$props$theme$ma5.crs) || "EPSG:3857");
641
641
  if (demUrl) {
642
642
  var _this2$props$theme$ma6, _this2$props$theme$ma7;
643
643
  var demSource = new GeoTIFFSource({
@@ -740,8 +740,8 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
740
740
 
741
741
  // Add other objects
742
742
  (((_this2$props$theme$ma10 = _this2.props.theme.map3d) === null || _this2$props$theme$ma10 === void 0 ? void 0 : _this2$props$theme$ma10.objects3d) || []).forEach(function (entry) {
743
- var _entry$visibility2;
744
- importGltf(MiscUtils.resolveAssetsPath(entry.url), entry.name, _this2.state.sceneContext, {
743
+ var _entry$title2, _entry$visibility2;
744
+ importGltf(MiscUtils.resolveAssetsPath(entry.url), (_entry$title2 = entry.title) !== null && _entry$title2 !== void 0 ? _entry$title2 : entry.name, _this2.state.sceneContext, {
745
745
  visibility: (_entry$visibility2 = entry.visibility) !== null && _entry$visibility2 !== void 0 ? _entry$visibility2 : true
746
746
  });
747
747
  });
@@ -968,7 +968,8 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
968
968
  });
969
969
  _defineProperty(_this2, "getTerrainHeightFromMap", function (scenePos) {
970
970
  var _elevationResult$samp;
971
- var coordinates = new Coordinates(_this2.state.sceneContext.mapCrs, scenePos[0], scenePos[1], 0);
971
+ var crs = CoordinateSystem.fromSrid(_this2.state.sceneContext.mapCrs);
972
+ var coordinates = new Coordinates(crs, scenePos[0], scenePos[1], 0);
972
973
  var elevationResult = _this2.state.sceneContext.map.getElevation({
973
974
  coordinates: coordinates
974
975
  });
@@ -6,6 +6,7 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
 
9
+ import CoordinateSystem from '@giro3d/giro3d/core/geographic/coordinate-system/CoordinateSystem';
9
10
  import ColorLayer from '@giro3d/giro3d/core/layer/ColorLayer';
10
11
  import GeoTIFFSource from "@giro3d/giro3d/sources/GeoTIFFSource.js";
11
12
  export default {
@@ -14,7 +15,7 @@ export default {
14
15
  name: options.name,
15
16
  source: new GeoTIFFSource({
16
17
  url: options.url,
17
- crs: projection
18
+ crs: CoordinateSystem.fromSrid(projection)
18
19
  })
19
20
  });
20
21
  }
@@ -12,7 +12,9 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
12
12
  * LICENSE file in the root directory of this source tree.
13
13
  */
14
14
 
15
+ import CoordinateSystem from '@giro3d/giro3d/core/geographic/coordinate-system/CoordinateSystem';
15
16
  import ColorLayer from '@giro3d/giro3d/core/layer/ColorLayer';
17
+ import StaticFeatureSource from '@giro3d/giro3d/sources/StaticFeatureSource';
16
18
  import VectorSource from "@giro3d/giro3d/sources/VectorSource.js";
17
19
  import ol from 'openlayers';
18
20
  import FeatureStyles from '../../../utils/FeatureStyles';
@@ -22,6 +24,7 @@ export default {
22
24
  return new ColorLayer({
23
25
  name: options.name,
24
26
  source: new VectorSource({
27
+ dataProjection: CoordinateSystem.fromSrid(projection),
25
28
  data: createFeatures(options, projection),
26
29
  format: new ol.format.GeoJSON(),
27
30
  style: options.styleFunction || function (feature) {
@@ -54,5 +57,12 @@ export default {
54
57
  });
55
58
  resolve(_toConsumableArray(fields.values()));
56
59
  });
60
+ },
61
+ createFeatureSource: function createFeatureSource(layer, options, projection) {
62
+ var crs = CoordinateSystem.fromSrid(projection);
63
+ return new StaticFeatureSource({
64
+ coordinateSystem: crs,
65
+ features: layer.source.source.getFeatures()
66
+ });
57
67
  }
58
68
  };
@@ -22,7 +22,10 @@ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
22
22
  * LICENSE file in the root directory of this source tree.
23
23
  */
24
24
 
25
+ import Extent from '@giro3d/giro3d/core/geographic/Extent';
26
+ import CoordinateSystem from '@giro3d/giro3d/core/geographic/coordinate-system/CoordinateSystem';
25
27
  import ColorLayer from '@giro3d/giro3d/core/layer/ColorLayer';
28
+ import StreamableFeatureSource, { wfsBuilder, tiledLoadingStrategy } from '@giro3d/giro3d/sources/StreamableFeatureSource';
26
29
  import VectorSource from "@giro3d/giro3d/sources/VectorSource.js";
27
30
  import axios from 'axios';
28
31
  import { tile } from "ol/loadingstrategy.js";
@@ -55,7 +58,7 @@ export default {
55
58
  return new ColorLayer({
56
59
  name: options.name,
57
60
  source: new VectorSource({
58
- dataProjection: options.projection,
61
+ dataProjection: CoordinateSystem.fromSrid(projection),
59
62
  data: {
60
63
  url: url.format(urlParts),
61
64
  format: olOpts.format
@@ -110,5 +113,18 @@ export default {
110
113
  reject([]);
111
114
  });
112
115
  });
116
+ },
117
+ createFeatureSource: function createFeatureSource(layer, options, projection) {
118
+ var bounds = CoordinatesUtils.reprojectBbox(options.bbox.bounds, options.bbox.crs, projection);
119
+ var crs = CoordinateSystem.fromSrid(projection);
120
+ var maxextent = new Extent(crs, bounds[0], bounds[2], bounds[1], bounds[3]);
121
+ return new StreamableFeatureSource({
122
+ queryBuilder: wfsBuilder(options.url, options.name),
123
+ sourceCoordinateSystem: crs,
124
+ extent: maxextent,
125
+ loadingStrategy: tiledLoadingStrategy({
126
+ tileSize: 5000
127
+ })
128
+ });
113
129
  }
114
130
  };
@@ -43,3 +43,9 @@ div.windows-notification-warn {
43
43
  div.windows-notification-error {
44
44
  background-color: red;
45
45
  }
46
+
47
+ div.windows-notification-actions {
48
+ display: flex;
49
+ flex-wrap: wrap;
50
+ justify-content: center;
51
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwc2",
3
- "version": "2025.11.15",
3
+ "version": "2025.11.19",
4
4
  "description": "QGIS Web Client",
5
5
  "author": "Sourcepole AG",
6
6
  "license": "BSD-2-Clause",
@@ -17,7 +17,7 @@
17
17
  ],
18
18
  "dependencies": {
19
19
  "@furkot/webfonts-generator": "^2.0.2",
20
- "@giro3d/giro3d": "^0.43.4",
20
+ "@sourcepole/qwc-giro3d": "^0.44.0-dev",
21
21
  "@kayahr/text-encoding": "^2.0.0",
22
22
  "@loaders.gl/core": "^4.3.3",
23
23
  "@loaders.gl/shapefile": "^4.3.3",
package/plugins/API.js CHANGED
@@ -386,6 +386,7 @@ var API = /*#__PURE__*/function (_React$Component) {
386
386
  window.qwc2.CoordinatesUtils = CoordinatesUtils;
387
387
  window.qwc2.EditingInterface = EditingInterface;
388
388
  window.qwc2.EditingUtils = EditingUtils;
389
+ window.qwc2.LayerUtils = LayerUtils;
389
390
  window.qwc2.LocaleUtils = LocaleUtils;
390
391
  window.qwc2.MapUtils = MapUtils;
391
392
  window.qwc2.PermaLinkUtils = PermaLinkUtils;
@@ -348,7 +348,7 @@ var Editing = /*#__PURE__*/function (_React$Component) {
348
348
  // Get source layer's field configuration and build name-to-id mapping
349
349
  var sourceFields = (_this$props$editConfi = _this.props.editConfigs[mapName]) === null || _this$props$editConfi === void 0 || (_this$props$editConfi = _this$props$editConfi[layer]) === null || _this$props$editConfi === void 0 ? void 0 : _this$props$editConfi.fields;
350
350
  var sourceNameToIdMap = (sourceFields || []).reduce(function (res, field) {
351
- return _objectSpread(_objectSpread({}, res), {}, _defineProperty(_defineProperty({}, sourceFields.name, sourceFields.id), sourceFields.id, sourceFields.id));
351
+ return _objectSpread(_objectSpread({}, res), {}, _defineProperty(_defineProperty({}, field.name, field.id), field.id, field.id));
352
352
  }, {});
353
353
  var sourcePropertiesById = Object.entries(sourceProperties).reduce(function (res, _ref7) {
354
354
  var _ref8 = _slicedToArray(_ref7, 2),
@@ -427,12 +427,12 @@ var RedliningSupport = /*#__PURE__*/function (_React$Component) {
427
427
  evt.feature.setId(uuidv4());
428
428
  evt.feature.set('shape', _this.props.redlining.geomType);
429
429
  _this.updateFeatureStyle(evt.feature);
430
- _this.toggleFeatureMeasurements(ev.feature);
430
+ _this.toggleFeatureMeasurements(evt.feature);
431
431
  _this.selectFeatures([evt.feature]);
432
432
  }, _this);
433
433
  drawInteraction.on('drawend', function () {
434
434
  // Draw end
435
- _this.commitFeatures(_this.selectFeatures, _this.props.redlining, true);
435
+ _this.commitFeatures(_this.selectedFeatures, _this.props.redlining, true);
436
436
  _this.reset(_this.props.redlining);
437
437
  // Ughh... Apparently we need to wait 250ms for the 'singleclick' event processing to finish to avoid pick interactions picking up the current event
438
438
  setTimeout(function () {
@@ -108,7 +108,8 @@ export default function windows() {
108
108
  type: 'notification',
109
109
  text: action.text,
110
110
  notificationType: action.notificationType,
111
- sticky: action.sticky
111
+ sticky: action.sticky,
112
+ actions: action.actions
112
113
  }))
113
114
  });
114
115
  }
@@ -650,6 +650,7 @@
650
650
  "vertex": "Прилепване към върховете"
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "Добавяне на слой",
654
655
  "addlayerstotheme": "Добавяне на слоеве към текущата карта",
655
656
  "addselectedlayers": "Добавяне на избран(и) слой(и)",
@@ -650,6 +650,7 @@
650
650
  "vertex": "Ajustar als vèrtexs"
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "Afegir capa",
654
655
  "addlayerstotheme": "Afegir capa al mapa actual",
655
656
  "addselectedlayers": "Afegir capa(s) seleccionada(s)",
@@ -650,6 +650,7 @@
650
650
  "vertex": ""
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "Přidat vrstvu",
654
655
  "addlayerstotheme": "Přidat vrstvy do aktuálního tématu",
655
656
  "addselectedlayers": "Přidat vybrané vrstvy",
@@ -650,6 +650,7 @@
650
650
  "vertex": "An Ecken einrasten"
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "Trotzdem hinzufügen",
653
654
  "addlayer": "Layer hinzufügen",
654
655
  "addlayerstotheme": "Ebenen der Karte hinzufügen",
655
656
  "addselectedlayers": "Selektierte Ebenen hinzufügen",
@@ -650,6 +650,7 @@
650
650
  "vertex": "An Ecken einrasten"
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "Trotzdem hinzufügen",
653
654
  "addlayer": "Layer hinzufügen",
654
655
  "addlayerstotheme": "Ebenen der Karte hinzufügen",
655
656
  "addselectedlayers": "Selektierte Ebenen hinzufügen",
@@ -650,6 +650,7 @@
650
650
  "vertex": "Snap to vertices"
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "Add anyway",
653
654
  "addlayer": "Add layer",
654
655
  "addlayerstotheme": "Add layers to current map",
655
656
  "addselectedlayers": "Add selected layer(s)",
@@ -650,6 +650,7 @@
650
650
  "vertex": "Ajustar a los vértices"
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "Agregar capa",
654
655
  "addlayerstotheme": "Agregar capas al mapa actual",
655
656
  "addselectedlayers": "Agregar capa(s) seleccionada(s)",
@@ -650,6 +650,7 @@
650
650
  "vertex": ""
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "Lisää taso",
654
655
  "addlayerstotheme": "Lisää tasoja nykyiseen karttaan",
655
656
  "addselectedlayers": "Lisää valitut tasot",
@@ -456,7 +456,7 @@
456
456
  "angle": "Angle",
457
457
  "featureunsupported": "Entrée numérique non disponible pour cette géométrie",
458
458
  "height": "Hauteur",
459
- "nofeatureormultiple": "",
459
+ "nofeatureormultiple": "Aucun ou plusieurs objets actifs",
460
460
  "side": "Côté",
461
461
  "width": "Largeur",
462
462
  "windowtitle": "Entrée numérique"
@@ -650,6 +650,7 @@
650
650
  "vertex": "Snapping aux sommets"
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "Ajouter quand même",
653
654
  "addlayer": "Ajouter la couche",
654
655
  "addlayerstotheme": "Ajouter des couches à la carte",
655
656
  "addselectedlayers": "Ajouter les couches sélectionnées",
@@ -650,6 +650,7 @@
650
650
  "vertex": ""
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "",
654
655
  "addlayerstotheme": "",
655
656
  "addselectedlayers": "",
@@ -650,6 +650,7 @@
650
650
  "vertex": "Snap ai vertici"
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "Aggiungi comunque",
653
654
  "addlayer": "Aggiungi layer",
654
655
  "addlayerstotheme": "Aggiungi layer alla mappa corrente",
655
656
  "addselectedlayers": "Aggiungi i layer selezionati",
@@ -650,6 +650,7 @@
650
650
  "vertex": "頂点にスナップ"
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "レイヤを追加",
654
655
  "addlayerstotheme": "現在の地図にレイヤを追加",
655
656
  "addselectedlayers": "選択されたレイヤを追加",
@@ -650,6 +650,7 @@
650
650
  "vertex": "Naar hoekpunten snappen"
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "Laag toevoegen",
654
655
  "addlayerstotheme": "Lagen toevoegen aan huidige kaart",
655
656
  "addselectedlayers": "Geselecteerde la(a)g(en) toevoegen",
@@ -650,6 +650,7 @@
650
650
  "vertex": ""
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "",
654
655
  "addlayerstotheme": "",
655
656
  "addselectedlayers": "",
@@ -650,6 +650,7 @@
650
650
  "vertex": ""
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "",
654
655
  "addlayerstotheme": "",
655
656
  "addselectedlayers": "",
@@ -650,6 +650,7 @@
650
650
  "vertex": ""
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "Adicionar camada",
654
655
  "addlayerstotheme": "Adicionar camadas ao mapa atual",
655
656
  "addselectedlayers": "Adicionar camadas selecionadas",
@@ -650,6 +650,7 @@
650
650
  "vertex": "Vértice"
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "Adicionar Camada",
654
655
  "addlayerstotheme": "Adicionar Camadas ao Mapa Atual",
655
656
  "addselectedlayers": "Adicionar Camadas Selecionadas",
@@ -650,6 +650,7 @@
650
650
  "vertex": ""
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "Adaugă strat",
654
655
  "addlayerstotheme": "Adaugă strat la hartă",
655
656
  "addselectedlayers": "Adaugă straturile selectate",
@@ -650,6 +650,7 @@
650
650
  "vertex": ""
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "",
654
655
  "addlayerstotheme": "",
655
656
  "addselectedlayers": "",
@@ -650,6 +650,7 @@
650
650
  "vertex": ""
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "",
654
655
  "addlayerstotheme": "",
655
656
  "addselectedlayers": "",
@@ -650,6 +650,7 @@
650
650
  "vertex": "Kırık noktalarını yakala"
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "Katman ekle",
654
655
  "addlayerstotheme": "Geçerli haritaya katman ekle",
655
656
  "addselectedlayers": "Seçili katmanları ekle",
@@ -559,6 +559,7 @@
559
559
  "snapping.loading",
560
560
  "snapping.snappingenabled",
561
561
  "snapping.vertex",
562
+ "themelayerslist.addanyway",
562
563
  "themelayerslist.addlayer",
563
564
  "themelayerslist.addlayerstotheme",
564
565
  "themelayerslist.addselectedlayers",
@@ -650,6 +650,7 @@
650
650
  "vertex": ""
651
651
  },
652
652
  "themelayerslist": {
653
+ "addanyway": "",
653
654
  "addlayer": "",
654
655
  "addlayerstotheme": "",
655
656
  "addselectedlayers": "",
@@ -346,7 +346,6 @@ export function computeExpressionFields(editConfig, feature, editIface, mapCrs,
346
346
  }, {});
347
347
  }
348
348
  // Evaluate expressions
349
- FeatureCache.clear();
350
349
  var mapPrefix = editConfig.editDataset.split(".")[0];
351
350
  parseExpressionsAsync(fieldExpressions, feature, editConfig, editIface, mapPrefix, mapCrs).then(function (result) {
352
351
  // Adjust values based on field type
@@ -1506,7 +1506,7 @@ var LayerUtils = {
1506
1506
  var newLayer = _objectSpread({}, layer);
1507
1507
  var itempath = [].concat(_toConsumableArray(path.slice(1)), [newLayer.name]).join("/");
1508
1508
  if (newLayer.sublayers) {
1509
- newLayer.visibility = itempath in preset;
1509
+ newLayer.visibility = itempath in preset || path.length === 0;
1510
1510
  newLayer.sublayers = newLayer.sublayers.map(function (sublayer) {
1511
1511
  return LayerUtils.applyVisibilityPreset(sublayer, preset, [].concat(_toConsumableArray(path), [layer.name]));
1512
1512
  });
@@ -31,12 +31,12 @@ import ol from 'openlayers';
31
31
  import randomColor from 'randomcolor';
32
32
  import url from 'url';
33
33
  import { LayerRole } from '../actions/layers';
34
+ import StandardApp from '../components/StandardApp';
34
35
  import ConfigUtils from './ConfigUtils';
35
36
  import CoordinatesUtils from './CoordinatesUtils';
36
37
  import LayerUtils from './LayerUtils';
37
38
  import LocaleUtils from './LocaleUtils';
38
39
  import MiscUtils from './MiscUtils';
39
- import StandardApp from '../components/StandardApp';
40
40
  function strcmp(a, b) {
41
41
  var al = a.toLowerCase();
42
42
  var bl = b.toLowerCase();
@@ -137,6 +137,7 @@ var ThemeUtils = {
137
137
  var sublayerNames = LayerUtils.getSublayerNames({
138
138
  sublayers: subLayers !== null && subLayers !== void 0 ? subLayers : theme.sublayers
139
139
  });
140
+ var commonTranslations = StandardApp.store.getState().locale.messagesTree.maptranslations || {};
140
141
  var baseParams = urlParts.query;
141
142
  var layer = {
142
143
  type: "wms",
@@ -175,7 +176,7 @@ var ThemeUtils = {
175
176
  LayerUtils.completeExternalLayer(res[cur.internalLayer], LayerUtils.searchSubLayer(theme, 'name', cur.internalLayer));
176
177
  return res;
177
178
  }, {})),
178
- translations: theme.translations,
179
+ translations: deepmerge(commonTranslations, theme.translations),
179
180
  editConfig: theme.editConfig,
180
181
  wms_name: theme.wms_name
181
182
  };