qwc2 2026.3.18 → 2026.3.30
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.
- package/README.md +2 -23
- package/components/AppMenu.js +29 -30
- package/components/AttributeTableWidget.js +24 -4
- package/components/IdentifyViewer.js +9 -4
- package/components/SearchBox.js +2 -1
- package/components/map3d/Map3D.js +31 -2
- package/components/map3d/utils/MiscUtils3D.js +11 -11
- package/components/style/AppMenu.css +58 -27
- package/components/style/AttributeTableWidget.css +5 -5
- package/components/widgets/Input.js +2 -1
- package/components/widgets/style/ListInput.css +1 -0
- package/package.json +5 -2
- package/plugins/Bookmark.js +3 -2
- package/plugins/Editing.js +4 -0
- package/plugins/LayerTree.js +21 -1
- package/plugins/MapExport.js +4 -6
- package/plugins/Measure.js +4 -2
- package/plugins/Redlining.js +1 -1
- package/plugins/SensorThingsTool.js +3022 -0
- package/plugins/TopBar.js +15 -11
- package/plugins/View3D.js +8 -0
- package/plugins/map/MeasurementSupport.js +7 -4
- package/plugins/map3d/HideObjects3D.js +4 -2
- package/plugins/map3d/MeasureObjects3D.js +8 -6
- package/plugins/map3d/Settings3D.js +20 -2
- package/plugins/map3d/TopBar3D.js +11 -4
- package/plugins/style/Portal.css +0 -5
- package/plugins/style/SensorThingsTool.css +193 -0
- package/reducers/layers.js +17 -0
- package/static/translations/bg-BG.json +96 -0
- package/static/translations/ca-ES.json +96 -0
- package/static/translations/cs-CZ.json +96 -0
- package/static/translations/de-CH.json +96 -0
- package/static/translations/de-DE.json +96 -0
- package/static/translations/en-US.json +96 -0
- package/static/translations/es-ES.json +96 -0
- package/static/translations/fi-FI.json +96 -0
- package/static/translations/fr-FR.json +96 -0
- package/static/translations/hu-HU.json +96 -0
- package/static/translations/it-IT.json +96 -0
- package/static/translations/ja-JP.json +96 -0
- package/static/translations/nl-NL.json +96 -0
- package/static/translations/no-NO.json +96 -0
- package/static/translations/pl-PL.json +96 -0
- package/static/translations/pt-BR.json +96 -0
- package/static/translations/pt-PT.json +96 -0
- package/static/translations/ro-RO.json +96 -0
- package/static/translations/ru-RU.json +96 -0
- package/static/translations/sv-SE.json +96 -0
- package/static/translations/tr-TR.json +96 -0
- package/static/translations/tsconfig.json +78 -0
- package/static/translations/uk-UA.json +96 -0
- package/utils/LayerUtils.js +24 -11
- package/utils/QuickHull2D.js +135 -0
- package/utils/ServiceLayerUtils.js +4 -1
- package/utils/expr_grammar/grammar.js +15 -15
- package/utils/expr_grammar/grammar.ne +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
 QGIS Web Client
|
|
1
|
+
 QGIS Web Client · [qwc.app](https://qwc.app)
|
|
2
2
|
=================
|
|
3
3
|
|
|
4
4
|
## Introduction
|
|
@@ -10,28 +10,7 @@ The `qwc2` NPM package can be used as a dependency to build a custom QWC applica
|
|
|
10
10
|
|
|
11
11
|
### Main Features
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
- Responsive, separately configurable for desktop and mobile devices
|
|
15
|
-
- Theme switcher
|
|
16
|
-
- Search with configurable search providers
|
|
17
|
-
- Layer tree
|
|
18
|
-
* Toggle layers and groups
|
|
19
|
-
* Change layer order and opacity
|
|
20
|
-
* Import external WMS/WFS/WMTS/GeoJSON/KML layers
|
|
21
|
-
* Compare layers
|
|
22
|
-
- Feature info
|
|
23
|
-
- Printing using QGIS print layouts
|
|
24
|
-
- Share permalinks
|
|
25
|
-
- Bookmarks
|
|
26
|
-
- Measuring tools
|
|
27
|
-
- Height profile
|
|
28
|
-
- Redlining
|
|
29
|
-
- Editing and attribute table
|
|
30
|
-
- Attribute table
|
|
31
|
-
- Export map (raster images, DXF)
|
|
32
|
-
- Time manager for temporal layers
|
|
33
|
-
- Themeable with color schemes
|
|
34
|
-
- [Additional plugins!](https://qwc-services.github.io/master/references/qwc2_plugins/)
|
|
13
|
+
See [qwc.app/features](https://qwc.app/features).
|
|
35
14
|
|
|
36
15
|
## Quick start
|
|
37
16
|
|
package/components/AppMenu.js
CHANGED
|
@@ -72,8 +72,8 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
72
72
|
_this.props.setCurrentTask(null);
|
|
73
73
|
}
|
|
74
74
|
_this.props.onMenuToggled(!_this.state.menuVisible);
|
|
75
|
-
if (_this.props.
|
|
76
|
-
_this.props.setMenuMargin(!_this.state.menuVisible ? MiscUtils.convertEmToPx(3.
|
|
75
|
+
if (_this.props.menuDisplayMode !== "normal") {
|
|
76
|
+
_this.props.setMenuMargin(!_this.state.menuVisible ? MiscUtils.convertEmToPx(3.5) : 0, 0);
|
|
77
77
|
}
|
|
78
78
|
_this.setState(function (state) {
|
|
79
79
|
return {
|
|
@@ -84,7 +84,7 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
84
84
|
});
|
|
85
85
|
});
|
|
86
86
|
_defineProperty(_this, "checkCloseMenu", function (ev) {
|
|
87
|
-
if (_this.menuEl && !_this.menuEl.contains(ev.target) &&
|
|
87
|
+
if (_this.menuEl && !_this.menuEl.contains(ev.target) && _this.props.menuDisplayMode === "normal") {
|
|
88
88
|
_this.toggleMenu();
|
|
89
89
|
MiscUtils.killEvent(ev);
|
|
90
90
|
}
|
|
@@ -98,7 +98,7 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
98
98
|
});
|
|
99
99
|
});
|
|
100
100
|
_defineProperty(_this, "onMenuitemClicked", function (item) {
|
|
101
|
-
if (
|
|
101
|
+
if (_this.props.menuDisplayMode === "normal" && _this.state.menuVisible) {
|
|
102
102
|
_this.toggleMenu();
|
|
103
103
|
}
|
|
104
104
|
if (item.url) {
|
|
@@ -111,6 +111,10 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
111
111
|
_defineProperty(_this, "renderMenuItems", function (items, level, filter) {
|
|
112
112
|
var submenu = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
113
113
|
return (items || []).map(function (item) {
|
|
114
|
+
var trargs = item.trargs || [];
|
|
115
|
+
var label = item.title ? LocaleUtils.tr.apply(LocaleUtils, [item.title].concat(_toConsumableArray(trargs))) : LocaleUtils.tr.apply(LocaleUtils, ["appmenu.items." + item.key + (item.mode || "")].concat(_toConsumableArray(trargs)));
|
|
116
|
+
var comment = item.comment ? LocaleUtils.tr.apply(LocaleUtils, ["appmenu.items." + item.key + (item.mode || "") + "_comment"].concat(_toConsumableArray(trargs))) : "";
|
|
117
|
+
var labelclass = _this.props.menuDisplayMode === "icononly" ? "appmenu-menu-item-tooltip" : "appmenu-menu-item-label";
|
|
114
118
|
if (item.subitems) {
|
|
115
119
|
var _item$key;
|
|
116
120
|
var expanded = filter || _this.state.submenusVisible[level] === item.key;
|
|
@@ -123,7 +127,6 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
123
127
|
"appmenu-submenu": true,
|
|
124
128
|
"appmenu-submenu-expanded": expanded
|
|
125
129
|
});
|
|
126
|
-
var label = item.title ? LocaleUtils.tr(item.title) : LocaleUtils.tr("appmenu.items." + item.key);
|
|
127
130
|
return [/*#__PURE__*/React.createElement("div", {
|
|
128
131
|
className: className,
|
|
129
132
|
key: (_item$key = item.key) !== null && _item$key !== void 0 ? _item$key : item.title,
|
|
@@ -137,14 +140,12 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
137
140
|
tabIndex: 0
|
|
138
141
|
}, /*#__PURE__*/React.createElement(Icon, {
|
|
139
142
|
icon: item.icon,
|
|
140
|
-
size: "xlarge"
|
|
141
|
-
|
|
142
|
-
|
|
143
|
+
size: "xlarge"
|
|
144
|
+
}), /*#__PURE__*/React.createElement("span", {
|
|
145
|
+
className: labelclass
|
|
146
|
+
}, label)), subitems];
|
|
143
147
|
} else {
|
|
144
|
-
|
|
145
|
-
var _label = item.title ? LocaleUtils.tr.apply(LocaleUtils, [item.title].concat(_toConsumableArray(trargs))) : LocaleUtils.tr.apply(LocaleUtils, ["appmenu.items." + item.key + (item.mode || "")].concat(_toConsumableArray(trargs)));
|
|
146
|
-
var comment = item.comment ? LocaleUtils.tr.apply(LocaleUtils, ["appmenu.items." + item.key + (item.mode || "") + "_comment"].concat(_toConsumableArray(trargs))) : "";
|
|
147
|
-
if (!filter || removeDiacritics(_label.toLowerCase()).match(filter) || comment && removeDiacritics(comment.toLowerCase()).match(filter)) {
|
|
148
|
+
if (!filter || removeDiacritics(label.toLowerCase()).match(filter) || comment && removeDiacritics(comment.toLowerCase()).match(filter)) {
|
|
148
149
|
var _className = classnames({
|
|
149
150
|
"appmenu-menu-item": true,
|
|
150
151
|
"appmenu-menu-item-nested": submenu
|
|
@@ -162,13 +163,10 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
162
163
|
tabIndex: 0
|
|
163
164
|
}, /*#__PURE__*/React.createElement(Icon, {
|
|
164
165
|
icon: item.icon,
|
|
165
|
-
size: "xlarge"
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}, _label, comment ? /*#__PURE__*/React.createElement("div", {
|
|
170
|
-
className: "appmenu-menu-item-comment"
|
|
171
|
-
}, comment) : null) : null);
|
|
166
|
+
size: "xlarge"
|
|
167
|
+
}), /*#__PURE__*/React.createElement("span", {
|
|
168
|
+
className: labelclass
|
|
169
|
+
}, label));
|
|
172
170
|
}
|
|
173
171
|
return null;
|
|
174
172
|
}
|
|
@@ -215,7 +213,7 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
215
213
|
MiscUtils.killEvent(ev);
|
|
216
214
|
} else if (ev.key === 'Escape') {
|
|
217
215
|
var _this$menuBtn, _this$menuBtn$focus;
|
|
218
|
-
if (
|
|
216
|
+
if (_this.props.menuDisplayMode === "normal") {
|
|
219
217
|
_this.toggleMenu();
|
|
220
218
|
}
|
|
221
219
|
(_this$menuBtn = _this.menuBtn) === null || _this$menuBtn === void 0 || (_this$menuBtn$focus = _this$menuBtn.focus) === null || _this$menuBtn$focus === void 0 || _this$menuBtn$focus.call(_this$menuBtn);
|
|
@@ -237,7 +235,7 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
237
235
|
return _createClass(AppMenu, [{
|
|
238
236
|
key: "componentDidMount",
|
|
239
237
|
value: function componentDidMount() {
|
|
240
|
-
if (this.props.showOnStartup) {
|
|
238
|
+
if (this.props.showOnStartup || this.props.menuDisplayMode !== "normal") {
|
|
241
239
|
this.toggleMenu();
|
|
242
240
|
}
|
|
243
241
|
this.addKeyBindings(this.props.menuItems);
|
|
@@ -249,7 +247,7 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
249
247
|
key: "componentDidUpdate",
|
|
250
248
|
value: function componentDidUpdate(prevProps, prevState) {
|
|
251
249
|
var _this2 = this;
|
|
252
|
-
if (this.state.menuVisible && !prevState.menuVisible
|
|
250
|
+
if (this.state.menuVisible && !prevState.menuVisible) {
|
|
253
251
|
// Need to wait until slide in transition is over
|
|
254
252
|
setTimeout(function () {
|
|
255
253
|
var _this2$filterfield, _this2$filterfield$fo;
|
|
@@ -259,7 +257,7 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
259
257
|
setTimeout(function () {
|
|
260
258
|
return document.addEventListener('click', _this2.checkCloseMenu);
|
|
261
259
|
}, 0);
|
|
262
|
-
} else if (prevState.menuVisible && !this.state.menuVisible
|
|
260
|
+
} else if (prevState.menuVisible && !this.state.menuVisible) {
|
|
263
261
|
document.removeEventListener('click', this.checkCloseMenu);
|
|
264
262
|
}
|
|
265
263
|
}
|
|
@@ -281,13 +279,13 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
281
279
|
_this$props$buttonCon;
|
|
282
280
|
var isMobile = ConfigUtils.isMobile();
|
|
283
281
|
var visible = !this.props.currentTaskBlocked && this.state.menuVisible;
|
|
284
|
-
var showLabel =
|
|
282
|
+
var showLabel = this.props.menuDisplayMode === "normal" && !isMobile;
|
|
285
283
|
var className = classnames({
|
|
286
284
|
"AppMenu": true,
|
|
287
285
|
"appmenu-blocked": this.props.currentTaskBlocked,
|
|
288
286
|
"appmenu-visible": visible,
|
|
289
|
-
"appmenu-compact": this.props.
|
|
290
|
-
"appmenu-icononly": this.props.
|
|
287
|
+
"appmenu-compact": this.props.menuDisplayMode === "compact",
|
|
288
|
+
"appmenu-icononly": this.props.menuDisplayMode === "icononly",
|
|
291
289
|
"appmenu-nolabel": !showLabel
|
|
292
290
|
});
|
|
293
291
|
var filter = this.state.filter ? new RegExp(removeDiacritics(this.state.filter).replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&"), "i") : null;
|
|
@@ -313,6 +311,8 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
313
311
|
}))]), /*#__PURE__*/React.createElement("div", {
|
|
314
312
|
className: "appmenu-menu-container",
|
|
315
313
|
tabIndex: -1
|
|
314
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
315
|
+
className: "appmenu-menu-aligner"
|
|
316
316
|
}, /*#__PURE__*/React.createElement("div", {
|
|
317
317
|
className: "appmenu-menu",
|
|
318
318
|
inert: !visible,
|
|
@@ -321,7 +321,7 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
321
321
|
_this3.menuEl = el;
|
|
322
322
|
MiscUtils.setupKillTouchEvents(el);
|
|
323
323
|
}
|
|
324
|
-
}, this.props.showFilterField ? /*#__PURE__*/React.createElement("div", {
|
|
324
|
+
}, this.props.showFilterField && this.props.menuDisplayMode !== "icononly" ? /*#__PURE__*/React.createElement("div", {
|
|
325
325
|
className: "appmenu-menu-item appmenu-menu-item-filter",
|
|
326
326
|
onFocus: this.focusFilterField,
|
|
327
327
|
onKeyDown: this.keyNav,
|
|
@@ -352,7 +352,7 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
352
352
|
});
|
|
353
353
|
},
|
|
354
354
|
role: "suffix"
|
|
355
|
-
}))) : null, this.renderMenuItems(this.props.menuItems, 0, filter))));
|
|
355
|
+
}))) : null, this.renderMenuItems(this.props.menuItems, 0, filter)))));
|
|
356
356
|
}
|
|
357
357
|
}]);
|
|
358
358
|
}(React.Component);
|
|
@@ -362,8 +362,7 @@ _defineProperty(AppMenu, "propTypes", {
|
|
|
362
362
|
buttonContents: PropTypes.object,
|
|
363
363
|
buttonLabel: PropTypes.string,
|
|
364
364
|
currentTaskBlocked: PropTypes.bool,
|
|
365
|
-
|
|
366
|
-
menuCompact: PropTypes.bool,
|
|
365
|
+
menuDisplayMode: PropTypes.string,
|
|
367
366
|
menuIconOnly: PropTypes.bool,
|
|
368
367
|
menuItems: PropTypes.array,
|
|
369
368
|
onMenuToggled: PropTypes.func,
|
|
@@ -38,7 +38,7 @@ import { connect } from 'react-redux';
|
|
|
38
38
|
import FileSaver from 'file-saver';
|
|
39
39
|
import isEmpty from 'lodash.isempty';
|
|
40
40
|
import PropTypes from 'prop-types';
|
|
41
|
-
import { LayerRole, addLayerFeatures, removeLayer } from '../actions/layers';
|
|
41
|
+
import { LayerRole, addLayerFeatures, removeLayer, refreshLayer } from '../actions/layers';
|
|
42
42
|
import { zoomToExtent, zoomToPoint } from '../actions/map';
|
|
43
43
|
import { setCurrentTask, setCurrentTaskBlocked } from '../actions/task';
|
|
44
44
|
import EditComboField from '../components/EditComboField';
|
|
@@ -388,7 +388,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
|
|
|
388
388
|
};
|
|
389
389
|
newState[stateField] = val;
|
|
390
390
|
// Reset page if a reload is triggered (either filter changed with a set filter value, or filter value cleared)
|
|
391
|
-
if (newState.filterVal || _this.state.filterVal && !newState.filterVal) {
|
|
391
|
+
if (newState.filterField && (newState.filterVal || _this.state.filterVal && !newState.filterVal)) {
|
|
392
392
|
newState.currentPage = 0;
|
|
393
393
|
_this.reload(_this.state.selectedLayer, false, newState);
|
|
394
394
|
} else {
|
|
@@ -485,6 +485,10 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
|
|
|
485
485
|
return newState;
|
|
486
486
|
}, function () {
|
|
487
487
|
if (reload) {
|
|
488
|
+
var mapPrefix = _this.state.curEditConfig.editDataset.split(".")[0];
|
|
489
|
+
_this.props.refreshLayer(function (layer) {
|
|
490
|
+
return layer.wms_name === mapPrefix;
|
|
491
|
+
});
|
|
488
492
|
_this.reload(_this.state.loadedLayer, true);
|
|
489
493
|
}
|
|
490
494
|
});
|
|
@@ -566,6 +570,10 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
|
|
|
566
570
|
alert(result);
|
|
567
571
|
} else {
|
|
568
572
|
_this.changedFiles = {};
|
|
573
|
+
var mapPrefix = _this.state.curEditConfig.editDataset.split(".")[0];
|
|
574
|
+
_this.props.refreshLayer(function (layer) {
|
|
575
|
+
return layer.wms_name === mapPrefix;
|
|
576
|
+
});
|
|
569
577
|
_this.reload(_this.state.loadedLayer, true, {
|
|
570
578
|
changedFeatureIdx: null,
|
|
571
579
|
originalFeatureProps: null,
|
|
@@ -806,6 +814,13 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
|
|
|
806
814
|
if (this.state.highlightedFeature !== prevState.highlightedFeature || this.state.features !== prevState.features || this.state.selectedFeatures !== prevState.selectedFeatures) {
|
|
807
815
|
this.highlightFeatures();
|
|
808
816
|
}
|
|
817
|
+
if (this.state.loadedLayer !== prevState.loadedLayer && this.props.showDisplayFieldOnly) {
|
|
818
|
+
this.setState(function (state) {
|
|
819
|
+
return {
|
|
820
|
+
filterField: state.curEditConfig.displayField
|
|
821
|
+
};
|
|
822
|
+
});
|
|
823
|
+
}
|
|
809
824
|
}
|
|
810
825
|
}, {
|
|
811
826
|
key: "componentWillUnmount",
|
|
@@ -1029,7 +1044,10 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
|
|
|
1029
1044
|
return _this2.updateFilter("filterField", ev.target.value);
|
|
1030
1045
|
},
|
|
1031
1046
|
value: this.state.filterField
|
|
1032
|
-
},
|
|
1047
|
+
}, /*#__PURE__*/React.createElement("option", {
|
|
1048
|
+
disabled: true,
|
|
1049
|
+
value: ""
|
|
1050
|
+
}, LocaleUtils.tr("common.select")), showIdColumn ? /*#__PURE__*/React.createElement("option", {
|
|
1033
1051
|
value: "<id>"
|
|
1034
1052
|
}, this.translateFieldName(primaryKey)) : null, fields.map(function (field) {
|
|
1035
1053
|
return /*#__PURE__*/React.createElement("option", {
|
|
@@ -1239,6 +1257,7 @@ _defineProperty(AttributeTableWidget, "propTypes", {
|
|
|
1239
1257
|
mapCrs: PropTypes.string,
|
|
1240
1258
|
mapScales: PropTypes.array,
|
|
1241
1259
|
readOnly: PropTypes.bool,
|
|
1260
|
+
refreshLayer: PropTypes.func,
|
|
1242
1261
|
removeLayer: PropTypes.func,
|
|
1243
1262
|
setCurrentTask: PropTypes.func,
|
|
1244
1263
|
setCurrentTaskBlocked: PropTypes.func,
|
|
@@ -1279,7 +1298,7 @@ _defineProperty(AttributeTableWidget, "defaultState", {
|
|
|
1279
1298
|
originalFeatureProps: null,
|
|
1280
1299
|
pageSize: 50,
|
|
1281
1300
|
currentPage: 0,
|
|
1282
|
-
filterField: "
|
|
1301
|
+
filterField: "",
|
|
1283
1302
|
filterOp: "~",
|
|
1284
1303
|
filterVal: "",
|
|
1285
1304
|
sortField: null,
|
|
@@ -1302,6 +1321,7 @@ export default connect(function (state) {
|
|
|
1302
1321
|
};
|
|
1303
1322
|
}, {
|
|
1304
1323
|
addLayerFeatures: addLayerFeatures,
|
|
1324
|
+
refreshLayer: refreshLayer,
|
|
1305
1325
|
removeLayer: removeLayer,
|
|
1306
1326
|
setCurrentTask: setCurrentTask,
|
|
1307
1327
|
setCurrentTaskBlocked: setCurrentTaskBlocked,
|
|
@@ -620,9 +620,11 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
|
|
|
620
620
|
var inlineExtaAttribs = false;
|
|
621
621
|
var featureReports = _this.state.reports[layerid] || [];
|
|
622
622
|
if (feature.featurereport) {
|
|
623
|
+
var parts = feature.featurereport.split(".");
|
|
623
624
|
featureReports.push({
|
|
624
625
|
title: null,
|
|
625
|
-
template:
|
|
626
|
+
template: parts.shift(),
|
|
627
|
+
format: parts.join(".")
|
|
626
628
|
});
|
|
627
629
|
}
|
|
628
630
|
if (feature.type === "text") {
|
|
@@ -768,7 +770,7 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
|
|
|
768
770
|
}) : null, /*#__PURE__*/React.createElement("span", null, [_this.props.showLayerTitles ? feature.layertitle : "", feature.displayname].filter(Boolean).join(": ")), zoomToFeatureButton, /*#__PURE__*/React.createElement(Icon, {
|
|
769
771
|
icon: "info-sign",
|
|
770
772
|
onClick: function onClick() {
|
|
771
|
-
return _this.showLayerInfo(layerid);
|
|
773
|
+
return _this.showLayerInfo(layerid, feature.layerinfo);
|
|
772
774
|
}
|
|
773
775
|
}), /*#__PURE__*/React.createElement(Icon, {
|
|
774
776
|
icon: "trash",
|
|
@@ -1122,12 +1124,15 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
|
|
|
1122
1124
|
});
|
|
1123
1125
|
});
|
|
1124
1126
|
});
|
|
1125
|
-
_defineProperty(_this, "showLayerInfo", function (layer) {
|
|
1127
|
+
_defineProperty(_this, "showLayerInfo", function (layer, infolayer) {
|
|
1126
1128
|
var _layer$split = layer.split('#'),
|
|
1127
1129
|
_layer$split2 = _slicedToArray(_layer$split, 2),
|
|
1128
1130
|
layerUrl = _layer$split2[0],
|
|
1129
1131
|
layerName = _layer$split2[1];
|
|
1130
|
-
|
|
1132
|
+
if (!infolayer) {
|
|
1133
|
+
infolayer = layerName;
|
|
1134
|
+
}
|
|
1135
|
+
var match = LayerUtils.searchLayer(_this.props.layers, 'url', layerUrl, 'name', infolayer);
|
|
1131
1136
|
if (match) {
|
|
1132
1137
|
_this.props.setActiveLayerInfo(match.layer, match.sublayer);
|
|
1133
1138
|
}
|
package/components/SearchBox.js
CHANGED
|
@@ -1025,12 +1025,13 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
|
|
|
1025
1025
|
var text = LocaleUtils.tr("search.existinglayer") + ": " + existingLayerName;
|
|
1026
1026
|
_this.props.showNotification("existinglayer", text);
|
|
1027
1027
|
} else {
|
|
1028
|
+
var _existingLayer$role;
|
|
1028
1029
|
var existingLayer = _this.props.layers.find(function (l) {
|
|
1029
1030
|
return l.type === layer.type && l.url === layer.url;
|
|
1030
1031
|
});
|
|
1031
1032
|
_this.props.addLayer(_objectSpread(_objectSpread({}, layer), {}, {
|
|
1032
1033
|
srcid: existingLayer === null || existingLayer === void 0 ? void 0 : existingLayer.srcid,
|
|
1033
|
-
role: LayerRole.USERLAYER
|
|
1034
|
+
role: (_existingLayer$role = existingLayer === null || existingLayer === void 0 ? void 0 : existingLayer.role) !== null && _existingLayer$role !== void 0 ? _existingLayer$role : LayerRole.USERLAYER
|
|
1034
1035
|
}));
|
|
1035
1036
|
}
|
|
1036
1037
|
if (_this.props.searchOptions.zoomToLayers && layer.bbox) {
|
|
@@ -52,7 +52,7 @@ import { fromUrl } from "geotiff";
|
|
|
52
52
|
import isEmpty from 'lodash.isempty';
|
|
53
53
|
import PropTypes from 'prop-types';
|
|
54
54
|
import * as THREE from 'three';
|
|
55
|
-
import { Vector2, CubeTextureLoader, Group, Raycaster, Mesh, Box3, Vector3, Matrix4, EventDispatcher } from 'three';
|
|
55
|
+
import { Vector2, CubeTextureLoader, Group, Raycaster, Mesh, Box3, Vector3, Matrix4, EventDispatcher, Points } from 'three';
|
|
56
56
|
import { computeBoundsTree, disposeBoundsTree, computeBatchedBoundsTree, disposeBatchedBoundsTree, acceleratedRaycast } from 'three-mesh-bvh';
|
|
57
57
|
import { GLTFExporter } from 'three/addons/exporters/GLTFExporter.js';
|
|
58
58
|
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader';
|
|
@@ -147,6 +147,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
|
|
|
147
147
|
updateSceneObject: function updateSceneObject(objectId, options, flags) {},
|
|
148
148
|
zoomToObject: function zoomToObject(objectId) {},
|
|
149
149
|
objectIsVisible: function objectIsVisible(objectId) {},
|
|
150
|
+
objectContainsPoints: function objectContainsPoints(object) {},
|
|
150
151
|
getMap: function getMap() {},
|
|
151
152
|
computeBoundsTree: function computeBoundsTree(object) {},
|
|
152
153
|
setViewToExtent: function setViewToExtent(bounds, angle) {},
|
|
@@ -489,6 +490,9 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
|
|
|
489
490
|
scene.userData.tilesetName = objectId;
|
|
490
491
|
scene.userData.featureIdAttr = "id";
|
|
491
492
|
Tiles3DStyle.applyTileStyle(scene, tiles.userData, _this2.state.sceneContext);
|
|
493
|
+
if (_this2.objectContainsPoints(tiles)) {
|
|
494
|
+
tiles.pointSize = _this2.state.sceneContext.settings.pointSize;
|
|
495
|
+
}
|
|
492
496
|
_this2.computeBoundsTree(scene);
|
|
493
497
|
_this2.instance.notifyChange(tiles);
|
|
494
498
|
});
|
|
@@ -782,6 +786,17 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
|
|
|
782
786
|
}
|
|
783
787
|
return isVisible;
|
|
784
788
|
});
|
|
789
|
+
_defineProperty(_this2, "objectContainsPoints", function (object) {
|
|
790
|
+
var containsPoints = false;
|
|
791
|
+
if (object !== null && object !== void 0 && object.tiles) {
|
|
792
|
+
object.traverse(function (child) {
|
|
793
|
+
if (child instanceof Points) {
|
|
794
|
+
containsPoints = true;
|
|
795
|
+
}
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
return containsPoints;
|
|
799
|
+
});
|
|
785
800
|
_defineProperty(_this2, "getMap", function () {
|
|
786
801
|
return _this2.map;
|
|
787
802
|
});
|
|
@@ -999,7 +1014,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
|
|
|
999
1014
|
});
|
|
1000
1015
|
|
|
1001
1016
|
// Inspector
|
|
1002
|
-
if (["1", "true"].includes((UrlParams.getParam("inspector") || "").toLowerCase())) {
|
|
1017
|
+
if ((process.env.NODE_ENV !== "production" || _this2.props.forceAllowInspector) && ["1", "true"].includes((UrlParams.getParam("inspector") || "").toLowerCase())) {
|
|
1003
1018
|
var inspectorContainer = document.createElement("div");
|
|
1004
1019
|
inspectorContainer.className = 'map3d-inspector';
|
|
1005
1020
|
_this2.container.appendChild(inspectorContainer);
|
|
@@ -1368,6 +1383,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
|
|
|
1368
1383
|
_this2.state.sceneContext.updateSceneObject = _this2.updateSceneObject;
|
|
1369
1384
|
_this2.state.sceneContext.zoomToObject = _this2.zoomToObject;
|
|
1370
1385
|
_this2.state.sceneContext.objectIsVisible = _this2.objectIsVisible;
|
|
1386
|
+
_this2.state.sceneContext.objectContainsPoints = _this2.objectContainsPoints;
|
|
1371
1387
|
_this2.state.sceneContext.getMap = _this2.getMap;
|
|
1372
1388
|
_this2.state.computeBoundsTree = _this2.computeBoundsTree;
|
|
1373
1389
|
_this2.state.sceneContext.getTerrainHeightFromDTM = _this2.getTerrainHeightFromDTM;
|
|
@@ -1376,6 +1392,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
|
|
|
1376
1392
|
_this2.state.sceneContext.getSetting = _this2.getSetting;
|
|
1377
1393
|
_this2.state.sceneContext.setSetting = _this2.setSetting;
|
|
1378
1394
|
_this2.state.sceneContext.settings.fov = props.defaultFov;
|
|
1395
|
+
_this2.state.sceneContext.settings.pointSize = props.defaultPointSize;
|
|
1379
1396
|
_this2.state.sceneContext.settings.sceneQuality = props.defaultSceneQuality;
|
|
1380
1397
|
registerPermalinkDataStoreHook("map3d", _this2.store3dState);
|
|
1381
1398
|
return _this2;
|
|
@@ -1454,6 +1471,15 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
|
|
|
1454
1471
|
this.instance.view.camera.fov = this.state.sceneContext.settings.fov;
|
|
1455
1472
|
this.instance.notifyChange(this.instance.view.camera);
|
|
1456
1473
|
}
|
|
1474
|
+
if (this.state.sceneContext.settings.pointSize !== prevState.sceneContext.settings.pointSize) {
|
|
1475
|
+
Object.values(this.state.sceneContext.objectTree).map(function (entry) {
|
|
1476
|
+
var obj = _this3.state.sceneContext.getSceneObject(entry.objectId);
|
|
1477
|
+
if (_this3.objectContainsPoints(obj)) {
|
|
1478
|
+
obj.pointSize = _this3.state.sceneContext.settings.pointSize;
|
|
1479
|
+
_this3.instance.notifyChange(obj);
|
|
1480
|
+
}
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1457
1483
|
if (this.state.sceneContext.settings.sceneQuality !== prevState.sceneContext.settings.sceneQuality) {
|
|
1458
1484
|
var quality = Math.max(20, this.state.sceneContext.settings.sceneQuality);
|
|
1459
1485
|
this.map.segments = Math.pow(2, Math.floor(quality / 20));
|
|
@@ -1500,7 +1526,9 @@ _defineProperty(Map3D, "contextType", MapContainerPortalContext);
|
|
|
1500
1526
|
_defineProperty(Map3D, "propTypes", {
|
|
1501
1527
|
controlsPosition: PropTypes.string,
|
|
1502
1528
|
defaultFov: PropTypes.number,
|
|
1529
|
+
defaultPointSize: PropTypes.number,
|
|
1503
1530
|
defaultSceneQuality: PropTypes.number,
|
|
1531
|
+
forceAllowInspector: PropTypes.bool,
|
|
1504
1532
|
innerRef: PropTypes.func,
|
|
1505
1533
|
layers: PropTypes.array,
|
|
1506
1534
|
mouseButtons: PropTypes.object,
|
|
@@ -1534,6 +1562,7 @@ _defineProperty(Map3D, "defaultSceneState", {
|
|
|
1534
1562
|
snapObjects: [],
|
|
1535
1563
|
settings: {
|
|
1536
1564
|
fov: 30,
|
|
1565
|
+
pointSize: 0,
|
|
1537
1566
|
sceneQuality: 100
|
|
1538
1567
|
},
|
|
1539
1568
|
sceneId: null,
|
|
@@ -21,10 +21,10 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
|
|
|
21
21
|
* LICENSE file in the root directory of this source tree.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import convexHull from 'quick-hull-2d';
|
|
25
24
|
import { Box3, BufferGeometry, Matrix3, Matrix4, Mesh, Vector2, Vector3 } from 'three';
|
|
26
25
|
import { MeshLine, MeshLineMaterial } from 'three.meshline';
|
|
27
26
|
import { CSS2DObject } from "three/addons/renderers/CSS2DRenderer";
|
|
27
|
+
import convexHull from '../../../utils/QuickHull2D';
|
|
28
28
|
export function createLabelObject(text, pos, sceneContext, zoffset) {
|
|
29
29
|
var yoffset = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
|
|
30
30
|
var labelEl = document.createElement("span");
|
|
@@ -101,9 +101,10 @@ export function computeOBBXY(mesh) {
|
|
|
101
101
|
var zmin = Infinity;
|
|
102
102
|
var zmax = -Infinity;
|
|
103
103
|
for (var i = 0; i < n; i++) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
var p = new Vector3(pos.getX(i), pos.getY(i), pos.getZ(i)).applyMatrix4(mesh.matrixWorld);
|
|
105
|
+
pointsxy[i] = [p.x, p.y];
|
|
106
|
+
zmin = Math.min(zmin, p.z);
|
|
107
|
+
zmax = Math.max(zmax, p.z);
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
// Compute convex hull
|
|
@@ -125,9 +126,9 @@ export function computeOBBXY(mesh) {
|
|
|
125
126
|
var _vmin = Infinity;
|
|
126
127
|
var _vmax = -Infinity;
|
|
127
128
|
for (var j = 0; j < hull.length; j++) {
|
|
128
|
-
var
|
|
129
|
-
var pu =
|
|
130
|
-
var pv =
|
|
129
|
+
var _p = _construct(Vector2, _toConsumableArray(hull[j]));
|
|
130
|
+
var pu = _p.dot(_u);
|
|
131
|
+
var pv = _p.dot(_v);
|
|
131
132
|
if (pu < _umin) _umin = pu;
|
|
132
133
|
if (pu > _umax) _umax = pu;
|
|
133
134
|
if (pv < _vmin) _vmin = pv;
|
|
@@ -153,12 +154,11 @@ export function computeOBBXY(mesh) {
|
|
|
153
154
|
umax = _best.umax,
|
|
154
155
|
vmin = _best.vmin,
|
|
155
156
|
vmax = _best.vmax;
|
|
156
|
-
var center = new Vector3(u.x * (umin + umax) / 2 + v.x * (vmin + vmax) / 2, u.y * (umin + umax) / 2 + v.y * (vmin + vmax) / 2, (zmin + zmax) / 2)
|
|
157
|
-
var normalMatrix = new Matrix3().getNormalMatrix(mesh.matrixWorld);
|
|
157
|
+
var center = new Vector3(u.x * (umin + umax) / 2 + v.x * (vmin + vmax) / 2, u.y * (umin + umax) / 2 + v.y * (vmin + vmax) / 2, (zmin + zmax) / 2);
|
|
158
158
|
return {
|
|
159
159
|
center: center,
|
|
160
|
-
axes: [new Vector3(u.x, u.y, 0)
|
|
161
|
-
halfSizes: new Vector3((umax - umin) / 2
|
|
160
|
+
axes: [new Vector3(u.x, u.y, 0), new Vector3(v.x, v.y, 0), new Vector3(0, 0, 1)],
|
|
161
|
+
halfSizes: new Vector3((umax - umin) / 2, (vmax - vmin) / 2, (zmax - zmin) / 2)
|
|
162
162
|
};
|
|
163
163
|
}
|
|
164
164
|
export var TileMeshHelper = /*#__PURE__*/function () {
|
|
@@ -36,10 +36,16 @@ div.AppMenu.appmenu-visible .appmenu-label {
|
|
|
36
36
|
color: var(--app-submenu-text-color-hover);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
div.AppMenu .appmenu-icon {
|
|
40
|
+
width: 3.5em;
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
justify-content: center;
|
|
44
|
+
}
|
|
45
|
+
|
|
39
46
|
div.AppMenu .appmenu-icon > span.icon {
|
|
40
47
|
color: var(--app-menu-text-color);
|
|
41
48
|
padding: 0.25em;
|
|
42
|
-
margin: 0 1em;
|
|
43
49
|
border: 2px solid var(--app-menu-text-color);
|
|
44
50
|
transition: color 0.25s, border-color 0.25s, background-color 0.25s;
|
|
45
51
|
}
|
|
@@ -58,47 +64,52 @@ div.AppMenu div.appmenu-menu-container {
|
|
|
58
64
|
position: absolute;
|
|
59
65
|
top: 100%;
|
|
60
66
|
right: 0;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
67
|
+
width: 100%;
|
|
68
|
+
overflow-y: auto;
|
|
69
|
+
overflow-x: hidden;
|
|
70
|
+
height: calc(var(--plugins-container-height) - var(--topbar-height) - var(--bottombar-height));
|
|
71
|
+
pointer-events: none;
|
|
64
72
|
opacity: 0;
|
|
65
73
|
transform-origin: top;
|
|
66
74
|
transform: scaleY(0);
|
|
67
75
|
transition: transform 0.25s, opacity 0.25s;
|
|
68
|
-
overflow-y: auto;
|
|
69
|
-
max-height: calc(var(--plugins-container-height) - var(--topbar-height) - var(--bottombar-height));
|
|
70
|
-
border-radius: 0px 0px 0px var(--border-radius);
|
|
71
76
|
}
|
|
72
77
|
|
|
73
|
-
div.AppMenu.appmenu-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
height: calc(var(--plugins-container-height) - var(--topbar-height) - var(--bottombar-height));
|
|
77
|
-
transition: transform 0.25s, opacity 0.25s, right 0.5s;
|
|
78
|
-
background: var(--app-menu-bg-color);
|
|
79
|
-
box-shadow: 0px 0px 4px rgba(136, 136, 136, 0.5);
|
|
80
|
-
top: 3.5em;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
div.AppMenu.appmenu-icononly div.appmenu-menu-container {
|
|
84
|
-
right: 0;
|
|
85
|
-
width: auto;
|
|
78
|
+
div.AppMenu.appmenu-visible div.appmenu-menu-container {
|
|
79
|
+
transform: scaleY(1);
|
|
80
|
+
opacity: 1;
|
|
86
81
|
}
|
|
87
82
|
|
|
88
|
-
div.AppMenu
|
|
89
|
-
|
|
90
|
-
|
|
83
|
+
div.AppMenu div.appmenu-menu-aligner {
|
|
84
|
+
display: flex;
|
|
85
|
+
justify-content: end;
|
|
91
86
|
}
|
|
92
87
|
|
|
93
88
|
div.AppMenu div.appmenu-menu {
|
|
89
|
+
position: relative;
|
|
90
|
+
pointer-events: initial;
|
|
91
|
+
text-align: left;
|
|
94
92
|
background-color: var(--app-menu-bg-color);
|
|
93
|
+
box-shadow: 0px 2px 4px rgba(136, 136, 136, 0.5);
|
|
95
94
|
text-align: left;
|
|
96
|
-
|
|
95
|
+
width: 22.22em;
|
|
96
|
+
font-size: 90%;
|
|
97
|
+
border-radius: 0px 0px 0px var(--border-radius);
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
div.AppMenu.appmenu-
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
div.AppMenu.appmenu-compact div.appmenu-menu {
|
|
101
|
+
right: -18.33em;
|
|
102
|
+
transition: right 0.5s;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
div.AppMenu.appmenu-compact div.appmenu-menu:hover,
|
|
106
|
+
div.AppMenu.appmenu-compact div.appmenu-menu:focus-within {
|
|
107
|
+
right: 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
div.AppMenu.appmenu-icononly div.appmenu-menu {
|
|
111
|
+
width: 3.89em;
|
|
112
|
+
right: 0;
|
|
102
113
|
}
|
|
103
114
|
|
|
104
115
|
div.appmenu-menu-item {
|
|
@@ -106,6 +117,7 @@ div.appmenu-menu-item {
|
|
|
106
117
|
align-items: center;
|
|
107
118
|
color: var(--app-menu-text-color);
|
|
108
119
|
font-weight: bold;
|
|
120
|
+
position: relative;
|
|
109
121
|
}
|
|
110
122
|
|
|
111
123
|
div.appmenu-menu-item:not(:last-child) {
|
|
@@ -126,6 +138,25 @@ div.appmenu-menu-item-comment {
|
|
|
126
138
|
font-size: 90%;
|
|
127
139
|
}
|
|
128
140
|
|
|
141
|
+
span.appmenu-menu-item-tooltip {
|
|
142
|
+
position: absolute;
|
|
143
|
+
display: none;
|
|
144
|
+
background-color: var(--tooltip-bg-color);
|
|
145
|
+
border: 1px solid var(--tooltip-border-color);
|
|
146
|
+
color: var(--tooltip-text-color);
|
|
147
|
+
font-size: 75%;
|
|
148
|
+
font-weight: normal;
|
|
149
|
+
padding: 0.5em;
|
|
150
|
+
border-radius: 0.5em;
|
|
151
|
+
white-space: nowrap;
|
|
152
|
+
right: calc(100% + 0.25em);
|
|
153
|
+
z-index: 2;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
div.appmenu-menu-item:hover span.appmenu-menu-item-tooltip {
|
|
157
|
+
display: inline;
|
|
158
|
+
}
|
|
159
|
+
|
|
129
160
|
div.appmenu-submenu-active,
|
|
130
161
|
div.appmenu-submenu-expanded {
|
|
131
162
|
background-color: var(--app-menu-bg-color-hover);
|