qwc2
Version:
QGIS Web Client
1,164 lines (1,161 loc) • 54.1 kB
JavaScript
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); }
function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); }
function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); }
function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
/**
* Copyright 2024 Sourcepole AG
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
import React from 'react';
import { connect } from 'react-redux';
import Sortable from 'react-sortablejs';
import FileSaver from 'file-saver';
import PropTypes from 'prop-types';
import { createSelector } from 'reselect';
import { v4 as uuidv4 } from 'uuid';
import { LayerRole, addLayerFeatures, removeLayer } from '../actions/layers';
import { zoomToExtent } from '../actions/map';
import { setCurrentTask } from '../actions/task';
import Icon from '../components/Icon';
import ResizeableWindow from '../components/ResizeableWindow';
import ButtonBar from '../components/widgets/ButtonBar';
import DateTimeInput from '../components/widgets/DateTimeInput';
import NumberInput from '../components/widgets/NumberInput';
import SearchWidget from '../components/widgets/SearchWidget';
import Spinner from '../components/widgets/Spinner';
import ToggleSwitch from '../components/widgets/ToggleSwitch';
import VectorLayerPicker from '../components/widgets/VectorLayerPicker';
import searchProvidersSelector from '../selectors/searchproviders';
import ConfigUtils from '../utils/ConfigUtils';
import CoordinatesUtils from '../utils/CoordinatesUtils';
import LocaleUtils from '../utils/LocaleUtils';
import MeasureUtils from '../utils/MeasureUtils';
import RoutingInterface from '../utils/RoutingInterface';
import VectorLayerUtils from '../utils/VectorLayerUtils';
import './style/Routing.css';
/**
* Compute routes and isochrones.
*
* Requires `routingServiceUrl` in `config.json` pointing to a Valhalla routing service.
*/
var Routing = /*#__PURE__*/function (_React$Component) {
function Routing(props) {
var _this;
_classCallCheck(this, Routing);
_this = _callSuper(this, Routing, [props]);
_defineProperty(_this, "state", {
visible: false,
currentTab: 'Route',
mode: 'auto',
settings: {
auto: {
method: 'fastest',
maxSpeed: 130,
useFerries: true,
useHighways: true,
useTollways: true
},
heavyvehicle: {
method: 'fastest',
maxSpeed: 100,
useFerries: true,
useHighways: true,
useTollways: true
},
transit: {
timepoint: 'now',
time: ''
},
bicycle: {
method: 'fastest',
maxSpeed: 25,
useFerries: true
},
pedestrian: {
method: 'fastest',
maxSpeed: 4,
useFerries: true
}
},
settingsPopup: false,
routeConfig: {
points: [{
text: '',
pos: null,
crs: null
}, {
text: '',
pos: null,
crs: null
}],
result: null,
roundtrip: false,
optimized_route: false,
excludeLayer: null
},
isoConfig: {
points: [{
text: '',
pos: null,
crs: null
}],
mode: 'time',
units: {
time: 'min',
distance: 'km'
},
intervals: '5, 10',
result: null
},
searchProviders: [],
searchParams: {},
highlightId: null
});
_defineProperty(_this, "renderSettings", function () {
var settings = _this.state.settings[_this.state.mode];
return /*#__PURE__*/React.createElement("div", {
className: "routing-settings-menu"
}, /*#__PURE__*/React.createElement("table", {
className: "routing-settings-menu-entries"
}, /*#__PURE__*/React.createElement("tbody", null, settings.method !== undefined ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("routing.method"), ":"), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
onChange: function onChange(ev) {
return _this.updateSetting(_this.state.mode, {
method: ev.target.value
});
},
value: settings.method
}, /*#__PURE__*/React.createElement("option", {
value: "fastest"
}, LocaleUtils.tr("routing.fastest")), /*#__PURE__*/React.createElement("option", {
value: "shortest"
}, LocaleUtils.tr("routing.shortest"))))) : null, settings.maxSpeed !== undefined ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("routing.maxspeed"), ":"), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(NumberInput, {
max: 350,
min: 1,
mobile: true,
onChange: function onChange(value) {
return _this.updateSetting(_this.state.mode, {
maxSpeed: value
});
},
suffix: " km/h",
value: settings.maxSpeed
}))) : null, settings.useFerries !== undefined ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("routing.useferries"), ":"), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(ToggleSwitch, {
active: settings.useFerries,
onChange: function onChange(value) {
return _this.updateSetting(_this.state.mode, {
useFerries: value
});
}
}))) : null, settings.useHighways !== undefined ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("routing.usehighways"), ":"), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(ToggleSwitch, {
active: settings.useHighways,
onChange: function onChange(value) {
return _this.updateSetting(_this.state.mode, {
useHighways: value
});
}
}))) : null, settings.useTollways !== undefined ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("routing.usetollways"), ":"), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(ToggleSwitch, {
active: settings.useTollways,
onChange: function onChange(value) {
return _this.updateSetting(_this.state.mode, {
useTollways: value
});
}
}))) : null)));
});
_defineProperty(_this, "renderRouteWidget", function () {
var routeConfig = _this.state.routeConfig;
var vectorLayers = _this.props.layers.filter(function (layer) {
return layer.type === "vector" && layer.role === LayerRole.USERLAYER && !layer.readonly;
});
var numpoints = routeConfig.points.length;
return /*#__PURE__*/React.createElement("div", {
className: "routing-tab-widget"
}, /*#__PURE__*/React.createElement("div", {
className: "routing-input"
}, /*#__PURE__*/React.createElement("div", {
className: "routing-points"
}, /*#__PURE__*/React.createElement(Sortable, {
onChange: _this.onSortChange,
options: {
ghostClass: 'drop-ghost',
delay: 200
}
}, routeConfig.points.map(function (entry, idx) {
var placeholder = LocaleUtils.tr("routing.addviapoint");
if (idx === 0) {
placeholder = LocaleUtils.tr("routing.fromhere");
} else if (idx === routeConfig.points.length - 1) {
placeholder = LocaleUtils.tr("routing.tohere");
}
return _this.renderSearchField(entry, idx, 'routeConfig', idx > 0 && idx < numpoints - 1, placeholder);
})), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Icon, {
icon: "up-down-arrow",
onClick: _this.reverseRoutePts
}))), /*#__PURE__*/React.createElement("div", {
className: "routing-points-commands"
}, /*#__PURE__*/React.createElement("a", {
href: "#",
onClick: function onClick() {
return _this.addPoint('routeConfig', -1);
}
}, /*#__PURE__*/React.createElement(Icon, {
icon: "plus"
}), " ", LocaleUtils.tr("routing.add")), /*#__PURE__*/React.createElement("span", {
className: "routing-points-commands-spacer"
}), _this.renderImportButton('routeConfig'), /*#__PURE__*/React.createElement("span", {
className: "routing-points-commands-spacer"
}), /*#__PURE__*/React.createElement("a", {
href: "#",
onClick: function onClick() {
return _this.clearConfig('routeConfig');
}
}, /*#__PURE__*/React.createElement(Icon, {
icon: "clear"
}), " ", LocaleUtils.tr("common.clear"))), _this.state.mode === 'transit' ? /*#__PURE__*/React.createElement("div", {
className: "routing-time-settings"
}, /*#__PURE__*/React.createElement("select", {
onChange: _this.updateTransitTimepoint,
value: _this.state.settings.transit.timepoint
}, /*#__PURE__*/React.createElement("option", {
value: "now"
}, LocaleUtils.tr("routing.leavenow")), /*#__PURE__*/React.createElement("option", {
value: "leaveat"
}, LocaleUtils.tr("routing.leaveat")), /*#__PURE__*/React.createElement("option", {
value: "arriveat"
}, LocaleUtils.tr("routing.arriveat"))), _this.state.settings.transit.timepoint !== 'now' ? /*#__PURE__*/React.createElement(DateTimeInput, {
onChange: function onChange(value) {
return _this.updateSetting('transit', {
time: value
});
},
value: _this.state.settings.transit.time
}) : null) : null, /*#__PURE__*/React.createElement("div", {
className: "routing-points-commands"
}, /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("input", {
onChange: function onChange(ev) {
return _this.updateRouteConfig({
roundtrip: ev.target.checked
});
},
type: "checkbox",
value: routeConfig.roundtrip
}), " ", LocaleUtils.tr("routing.roundtrip"))), _this.state.mode !== 'transit' ? /*#__PURE__*/React.createElement("div", {
className: "routing-points-commands"
}, /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("input", {
onChange: function onChange(ev) {
return _this.updateRouteConfig({
optimized_route: ev.target.checked
});
},
type: "checkbox",
value: routeConfig.optimized_route
}), " ", LocaleUtils.tr("routing.optimized_route"))) : null, ConfigUtils.havePlugin("Redlining") ? /*#__PURE__*/React.createElement("div", {
className: "routing-points-commands controlgroup"
}, /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("routing.excludepolygons"), ":\xA0"), /*#__PURE__*/React.createElement(VectorLayerPicker, {
layers: vectorLayers,
onChange: function onChange(layer) {
return _this.updateRouteConfig({
excludeLayer: (layer || {}).id
});
},
showNone: true,
value: routeConfig.excludeLayer || ""
}), /*#__PURE__*/React.createElement("button", {
className: "button",
onClick: _this.setRedliningTool
}, /*#__PURE__*/React.createElement(Icon, {
icon: "draw"
}))) : null), routeConfig.busy ? /*#__PURE__*/React.createElement("div", {
className: "routing-busy"
}, /*#__PURE__*/React.createElement(Spinner, null), " ", LocaleUtils.tr("routing.computing")) : null, routeConfig.result ? _this.renderRouteResult(routeConfig) : null);
});
_defineProperty(_this, "updateTransitTimepoint", function (ev) {
var diff = {
timepoint: ev.target.value
};
if (ev.target.value !== 'now' && _this.state.settings.transit.timepoint === 'now') {
var tzoffset = new Date().getTimezoneOffset() * 60000;
diff.time = new Date(Date.now() - tzoffset).toISOString().slice(0, -1);
}
_this.updateSetting('transit', diff);
});
_defineProperty(_this, "setRedliningTool", function () {
_this.props.setCurrentTask("Redlining", null, null, {
layerId: _this.state.routeConfig.excludeLayer
});
});
_defineProperty(_this, "renderRouteResult", function (routeConfig) {
if (routeConfig.result.success === false) {
return /*#__PURE__*/React.createElement("div", {
className: "routing-status-failure"
}, routeConfig.result.data.errorMsgId ? LocaleUtils.tr(routeConfig.result.data.errorMsgId) : routeConfig.result.data.error);
} else {
return /*#__PURE__*/React.createElement("div", {
className: "routing-result"
}, /*#__PURE__*/React.createElement("div", {
className: "routing-result-summary"
}, /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(Icon, {
icon: "clock"
}), " ", MeasureUtils.formatDuration(routeConfig.result.data.summary.time)), /*#__PURE__*/React.createElement("span", {
className: "routing-result-spacer"
}), /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(Icon, {
icon: "measure"
}), " ", MeasureUtils.formatMeasurement(routeConfig.result.data.summary.length, false)), /*#__PURE__*/React.createElement("span", {
className: "routing-result-spacer"
}), /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(Icon, {
icon: "export"
}), " ", /*#__PURE__*/React.createElement("a", {
href: "#",
onClick: _this.exportRoute
}, LocaleUtils.tr("common.export"))), /*#__PURE__*/React.createElement("span", {
className: "routing-result-spacer"
}), /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(Icon, {
icon: "layers"
}), " ", /*#__PURE__*/React.createElement("a", {
href: "#",
onClick: _this.addRouteLayer
}, LocaleUtils.tr("routing.addlayer")))), /*#__PURE__*/React.createElement("div", {
className: "routing-result-instructions"
}, routeConfig.result.data.legs.map(function (leg, lidx) {
return leg.maneuvers.map(function (entry, eidx) {
return /*#__PURE__*/React.createElement("div", {
className: "routing-result-instruction",
key: "instr" + lidx + ":" + eidx,
onMouseEnter: function onMouseEnter() {
return _this.highlightRouteSection(lidx + ":" + eidx, entry, leg);
},
onMouseLeave: function onMouseLeave() {
return _this.clearRouteSectionHighlight(lidx + ":" + eidx);
}
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Icon, {
icon: entry.icon
}), /*#__PURE__*/React.createElement("b", null, entry.instruction)), /*#__PURE__*/React.createElement("div", {
className: "routing-result-instruction-summary"
}, /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(Icon, {
icon: "clock"
}), " ", MeasureUtils.formatDuration(entry.time)), /*#__PURE__*/React.createElement("span", {
className: "routing-result-spacer"
}), /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(Icon, {
icon: "measure"
}), " ", MeasureUtils.formatMeasurement(entry.length, false))));
});
})));
}
});
_defineProperty(_this, "highlightRouteSection", function (id, entry, leg) {
_this.setState({
highlightId: id
});
var feature = {
type: "Feature",
crs: "EPSG:4326",
geometry: {
type: "LineString",
coordinates: leg.coordinates.slice(entry.geom_indices[0], entry.geom_indices[1] + 1)
}
};
var sellayer = {
id: "routingselection",
role: LayerRole.SELECTION,
styleOptions: {
strokeWidth: 3,
strokeColor: [255, 255, 0, 1],
strokeDash: []
}
};
_this.props.addLayerFeatures(sellayer, [feature], true);
});
_defineProperty(_this, "clearRouteSectionHighlight", function (id) {
if (_this.state.highlightId === id) {
_this.setState({
highlightId: null
});
_this.props.removeLayer("routingselection");
}
});
_defineProperty(_this, "renderIsochroneWidget", function () {
var isoConfig = _this.state.isoConfig;
var intervalValid = !!isoConfig.intervals.match(/^\d+(,\s*\d+)*$/);
return /*#__PURE__*/React.createElement("div", {
className: "routing-tab-widget"
}, /*#__PURE__*/React.createElement("div", {
className: "routing-input"
}, /*#__PURE__*/React.createElement("div", null, isoConfig.points.map(function (entry, idx) {
return _this.renderSearchField(entry, idx, 'isoConfig', idx > 0);
})), /*#__PURE__*/React.createElement("table", {
className: "routing-iso-settings"
}, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("routing.iso_mode"), ": "), /*#__PURE__*/React.createElement("td", {
colSpan: "2"
}, /*#__PURE__*/React.createElement("select", {
onChange: function onChange(ev) {
return _this.updateIsoConfig({
mode: ev.target.value
});
},
value: isoConfig.mode
}, /*#__PURE__*/React.createElement("option", {
value: "time"
}, LocaleUtils.tr("routing.iso_mode_time")), /*#__PURE__*/React.createElement("option", {
value: "distance"
}, LocaleUtils.tr("routing.iso_mode_distance"))))), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("routing.iso_intervals"), ": "), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("input", {
className: isoConfig.intervals && !intervalValid ? "routing-input-invalid" : "",
onChange: function onChange(ev) {
return _this.updateIsoConfig({
intervals: ev.target.value
});
},
placeholder: "5, 10, 15",
type: "text",
value: isoConfig.intervals
})), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
onChange: function onChange(ev) {
_this.setState(function (state) {
return {
isoConfig: _objectSpread(_objectSpread({}, state.isoConfig), {}, {
units: _objectSpread(_objectSpread({}, state.isoConfig.units), {}, _defineProperty({}, state.isoConfig.mode, ev.target.value))
})
};
});
_this.recomputeIfNeeded();
},
value: isoConfig.units[isoConfig.mode]
}, Object.keys(_this.props.units[isoConfig.mode]).map(function (unit) {
return /*#__PURE__*/React.createElement("option", {
key: unit,
value: unit
}, unit);
})))))), /*#__PURE__*/React.createElement("div", {
className: "routing-points-commands"
}, /*#__PURE__*/React.createElement("a", {
href: "#",
onClick: function onClick() {
return _this.addPoint('isoConfig', isoConfig.points.length);
}
}, /*#__PURE__*/React.createElement(Icon, {
icon: "plus"
}), " ", LocaleUtils.tr("routing.add")), /*#__PURE__*/React.createElement("span", {
className: "routing-points-commands-spacer"
}), _this.renderImportButton('isoConfig'), /*#__PURE__*/React.createElement("span", {
className: "routing-points-commands-spacer"
}), /*#__PURE__*/React.createElement("a", {
href: "#",
onClick: function onClick() {
return _this.clearConfig('isoConfig');
}
}, /*#__PURE__*/React.createElement(Icon, {
icon: "clear"
}), " ", LocaleUtils.tr("common.clear")))), isoConfig.busy ? /*#__PURE__*/React.createElement("div", {
className: "routing-busy"
}, /*#__PURE__*/React.createElement(Spinner, null), " ", LocaleUtils.tr("routing.computing")) : null, isoConfig.result ? _this.renderIsochroneResult(isoConfig) : null);
});
_defineProperty(_this, "renderIsochroneResult", function (isoConfig) {
if (isoConfig.result.success === false) {
return /*#__PURE__*/React.createElement("div", {
className: "routing-status-failure"
}, isoConfig.result.data.errorMsgId ? LocaleUtils.tr(isoConfig.result.data.errorMsgId) : isoConfig.result.data.error);
} else {
return /*#__PURE__*/React.createElement("div", {
className: "routing-result"
}, /*#__PURE__*/React.createElement("div", {
className: "routing-result-summary"
}, /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(Icon, {
icon: "export"
}), " ", /*#__PURE__*/React.createElement("a", {
href: "#",
onClick: _this.exportIsochrone
}, LocaleUtils.tr("common.export"))), /*#__PURE__*/React.createElement("span", {
className: "routing-result-spacer"
}), /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(Icon, {
icon: "layers"
}), " ", /*#__PURE__*/React.createElement("a", {
href: "#",
onClick: _this.addIsochroneLayer
}, LocaleUtils.tr("routing.addlayer")))));
}
});
_defineProperty(_this, "renderSearchField", function (entry, idx, config, removeable) {
var placeholder = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
return /*#__PURE__*/React.createElement("div", {
className: "routing-search-field controlgroup",
key: "field" + idx
}, /*#__PURE__*/React.createElement(SearchWidget, {
placeholder: placeholder,
resultSelected: function resultSelected(result) {
return _this.searchResultSelected(config, idx, result);
},
role: "input",
searchParams: _this.state.searchParams,
searchProviders: _this.state.searchProviders,
value: entry.text
}), idx === 0 ? /*#__PURE__*/React.createElement("button", {
className: "button",
disabled: !_this.props.locatePos,
onClick: function onClick() {
return _this.updatePoint(config, 0, _this.locatePos());
},
role: "suffix"
}, /*#__PURE__*/React.createElement(Icon, {
icon: "screenshot"
})) : null, removeable ? /*#__PURE__*/React.createElement("button", {
className: "button",
onClick: function onClick() {
return _this.removePoint(config, idx);
},
role: "suffix"
}, /*#__PURE__*/React.createElement(Icon, {
icon: "remove"
})) : null);
});
_defineProperty(_this, "renderImportButton", function (config) {
return /*#__PURE__*/React.createElement("label", {
className: "routing-import-button",
title: LocaleUtils.tr("routing.importhint")
}, /*#__PURE__*/React.createElement(Icon, {
icon: "import"
}), " ", LocaleUtils.tr("routing.importpoints"), /*#__PURE__*/React.createElement("input", {
onChange: function onChange(ev) {
return _this.importPoints(ev, config);
},
type: "file"
}));
});
_defineProperty(_this, "locatePos", function () {
return {
pos: _toConsumableArray(_this.props.locatePos),
text: _this.props.locatePos.map(function (x) {
return x.toFixed(4);
}).join(", "),
crs: 'EPSG:4326'
};
});
_defineProperty(_this, "updateSetting", function (mode, diff) {
_this.setState(function (state) {
return {
settings: _objectSpread(_objectSpread({}, state.settings), {}, _defineProperty({}, mode, _objectSpread(_objectSpread({}, state.settings[mode]), diff)))
};
});
_this.recomputeIfNeeded();
});
_defineProperty(_this, "addPoint", function (config) {
var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : -1;
var entry = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
text: '',
pos: null
};
_this.setState(function (state) {
return _defineProperty({}, config, _objectSpread(_objectSpread({}, state[config]), {}, {
points: [].concat(_toConsumableArray(state[config].points.slice(0, index)), [entry], _toConsumableArray(state[config].points.slice(index)))
}));
});
if (entry.pos) {
_this.recomputeIfNeeded();
}
});
_defineProperty(_this, "updatePoint", function (config, idx, diff) {
_this.setState(function (state) {
return _defineProperty({}, config, _objectSpread(_objectSpread({}, state[config]), {}, {
points: [].concat(_toConsumableArray(state[config].points.slice(0, idx)), [_objectSpread(_objectSpread({}, state[config].points[idx]), diff)], _toConsumableArray(state[config].points.slice(idx + 1)))
}));
});
_this.recomputeIfNeeded();
});
_defineProperty(_this, "importPoints", function (ev, config) {
var reader = new FileReader();
reader.onload = function (loadev) {
try {
var obj = JSON.parse(loadev.target.result);
var crs = "EPSG:4326";
if (obj.crs && obj.crs.properties) {
crs = CoordinatesUtils.fromOgcUrnCrs(obj.crs.properties.name);
}
var prec = CoordinatesUtils.getPrecision(crs);
_this.setState(function (state) {
return _defineProperty({}, config, _objectSpread(_objectSpread({}, state[config]), {}, {
points: obj.features.map(function (feature) {
var coordinates = feature.geometry.coordinates;
return {
text: coordinates.map(function (x) {
return x.toFixed(prec);
}).join(", ") + " (" + crs + ")",
pos: coordinates,
crs: crs
};
})
}));
});
_this.recomputeIfNeeded();
} catch (e) {
// eslint-disable-next-line
alert(LocaleUtils.tr("routing.importerror"));
}
};
reader.readAsText(ev.target.files[0]);
});
_defineProperty(_this, "removePoint", function (config, idx) {
_this.setState(function (state) {
return _defineProperty({}, config, _objectSpread(_objectSpread({}, state[config]), {}, {
points: [].concat(_toConsumableArray(state[config].points.slice(0, idx)), _toConsumableArray(state[config].points.slice(idx + 1)))
}));
});
_this.recomputeIfNeeded();
});
_defineProperty(_this, "clearConfig", function (config) {
var newPoints = config === 'routeConfig' ? [{
text: '',
pos: null,
crs: null
}, {
text: '',
pos: null,
crs: null
}] : [{
text: '',
pos: null,
crs: null
}];
_this.setState(function (state) {
return _defineProperty({}, config, _objectSpread(_objectSpread({}, state[config]), {}, {
points: newPoints,
result: null
}));
});
_this.props.removeLayer("routinggeometries");
_this.props.removeLayer("routingmarkers");
_this.recomputeIfNeeded();
});
_defineProperty(_this, "reverseRoutePts", function () {
_this.setState(function (state) {
return {
routeConfig: _objectSpread(_objectSpread({}, state.routeConfig), {}, {
points: state.routeConfig.points.reverse()
})
};
});
_this.recomputeIfNeeded();
});
_defineProperty(_this, "updateRouteConfig", function (diff) {
var recompute = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
_this.setState(function (state) {
return {
routeConfig: _objectSpread(_objectSpread({}, state.routeConfig), diff)
};
});
if (recompute) {
_this.recomputeIfNeeded();
}
});
_defineProperty(_this, "updateIsoConfig", function (diff) {
var recompute = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
_this.setState(function (state) {
return {
isoConfig: _objectSpread(_objectSpread({}, state.isoConfig), diff)
};
});
if (recompute) {
_this.recomputeIfNeeded();
}
});
_defineProperty(_this, "searchResultSelected", function (config, idx, result) {
if (result) {
_this.updatePoint(config, idx, {
text: result.text,
pos: [result.x, result.y],
crs: result.crs
});
} else {
_this.updatePoint(config, idx, {
text: "",
pos: null,
crs: null
});
}
});
_defineProperty(_this, "updateRoutingMarkers", function () {
var points = [];
if (_this.state.currentTab === "Route") {
points = _this.state.routeConfig.points;
} else {
points = _this.state.isoConfig.points;
}
var layer = {
id: "routingmarkers",
role: LayerRole.MARKER,
styleName: 'marker'
};
var features = points.filter(function (point) {
return point.pos;
}).map(function (point, idx) {
return {
type: "Feature",
crs: point.crs,
geometry: {
type: "Point",
coordinates: point.pos
},
properties: {
label: _this.props.showPinLabels && _this.state.routeConfig.result ? String(idx + 1) : null
}
};
});
_this.props.addLayerFeatures(layer, features, true);
});
_defineProperty(_this, "computeRoute", function () {
var locations = _this.state.routeConfig.points.filter(function (entry) {
return entry.pos;
}).map(function (entry) {
return CoordinatesUtils.reproject(entry.pos, entry.crs, "EPSG:4326");
});
_this.props.removeLayer("routinggeometries");
_this.updateRouteConfig({
busy: locations.length >= 2,
result: null
}, false);
if (locations.length < 2) {
return;
}
if (_this.state.routeConfig.roundtrip) {
locations.push(locations[0]);
}
var settings = _objectSpread({}, _this.state.settings[_this.state.mode]);
if (_this.state.routeConfig.excludeLayer) {
var layer = _this.props.layers.find(function (l) {
return l.id === _this.state.routeConfig.excludeLayer;
});
if (layer) {
settings.exclude_polygons = layer.features.filter(function (feature) {
return feature.geometry.type === "Polygon";
}).map(function (feature) {
return VectorLayerUtils.reprojectGeometry(feature.geometry, _this.props.mapCrs, "EPSG:4326").coordinates[0];
});
}
}
settings.optimized_route = _this.state.routeConfig.optimized_route;
RoutingInterface.computeRoute(_this.state.mode, locations, settings, function (success, result) {
if (success) {
// Add routing leg geometries
var _layer = {
id: "routinggeometries",
role: LayerRole.SELECTION,
styleName: "default",
styleOptions: {
strokeColor: [10, 10, 255, 1],
strokeWidth: 4,
strokeDash: []
}
};
var features = [];
result.legs.forEach(function (leg) {
leg.maneuvers.forEach(function (man) {
features.push({
type: "Feature",
crs: "EPSG:4326",
styleOptions: {
strokeColor: man.color
},
geometry: {
type: "LineString",
coordinates: leg.coordinates.slice(man.geom_indices[0], man.geom_indices[1] + 1)
}
});
});
});
_this.props.addLayerFeatures(_layer, features, true);
// Reorder locations based on routing result, keeping null entries
var _this$state$routeConf = _this.state.routeConfig.points.reduce(function (res, point, idx) {
return point.pos ? _objectSpread(_objectSpread({}, res), {}, {
points: [].concat(_toConsumableArray(res.points), [point])
}) : _objectSpread(_objectSpread({}, res), {}, {
nullPoints: [].concat(_toConsumableArray(res.nullPoints), [{
point: point,
idx: idx
}])
});
}, {
points: [],
nullPoints: []
}),
points = _this$state$routeConf.points,
nullPoints = _this$state$routeConf.nullPoints;
var reorderedPoints = result.locations.map(function (location) {
return points[location.orig_idx];
}).filter(Boolean);
nullPoints.forEach(function (entry) {
reorderedPoints.splice(entry.idx, 0, entry.point);
});
_this.updateRouteConfig({
points: reorderedPoints,
result: {
success: success,
data: result
},
busy: false
}, false);
if (_this.props.zoomAuto) {
_this.props.zoomToExtent(result.summary.bounds, "EPSG:4326", -1);
}
} else {
_this.updateRouteConfig({
result: {
success: success,
data: result
},
busy: false
}, false);
}
});
});
_defineProperty(_this, "computeIsochrone", function () {
var intervalValid = !!_this.state.isoConfig.intervals.match(/^\d+(,\s*\d+)*$/);
if (!intervalValid) {
return;
}
var locations = _this.state.isoConfig.points.filter(function (entry) {
return entry.pos;
}).map(function (entry) {
return CoordinatesUtils.reproject(entry.pos, entry.crs, "EPSG:4326");
});
_this.props.removeLayer("routinggeometries");
_this.updateIsoConfig({
busy: true,
result: null
}, false);
var unitsFactor = _this.props.units[_this.state.isoConfig.mode][_this.state.isoConfig.units[_this.state.isoConfig.mode]];
var contourOptions = {
mode: _this.state.isoConfig.mode,
intervals: _this.state.isoConfig.intervals.split(",").map(function (entry) {
return parseInt(entry.trim(), 10) / unitsFactor;
}).sort()
};
RoutingInterface.computeIsochrone(_this.state.mode, locations, contourOptions, _this.state.settings[_this.state.mode], function (success, result) {
if (success) {
var layer = {
id: "routinggeometries",
role: LayerRole.SELECTION,
styleOptions: {
strokeColor: [10, 10, 255, 1],
fillColor: [10, 10, 255, 0.5],
strokeWidth: 4,
strokeDash: []
}
};
var features = result.areas.map(function (area) {
return {
type: "Feature",
crs: "EPSG:4326",
geometry: {
type: "Polygon",
coordinates: [area]
}
};
});
_this.props.addLayerFeatures(layer, features, true);
if (_this.props.zoomAuto) {
_this.props.zoomToExtent(result.bounds, "EPSG:4326", -0.5);
}
}
_this.updateIsoConfig({
result: {
success: success,
data: result
},
busy: false
}, false);
});
});
_defineProperty(_this, "recomputeIfNeeded", function () {
clearTimeout(_this.recomputeTimeout);
_this.recomputeTimeout = setTimeout(function () {
if (_this.state.currentTab === "Route" && _this.state.routeConfig.points.filter(function (entry) {
return entry.pos;
}).length >= 2) {
_this.computeRoute();
} else if (_this.state.currentTab === "Reachability" && _this.state.isoConfig.points.filter(function (entry) {
return entry.pos;
}).length > 0) {
_this.computeIsochrone();
}
_this.recomputeTimeout = null;
}, 750);
});
_defineProperty(_this, "collectRoutingFeatures", function () {
return _this.state.routeConfig.result.data.legs.map(function (leg) {
return {
type: "Feature",
properties: {
time: leg.time,
length: leg.length
},
geometry: {
type: "LineString",
coordinates: leg.coordinates
},
styleName: "default",
styleOptions: {
strokeColor: [10, 10, 255, 1],
strokeWidth: 4,
strokeDash: []
}
};
});
});
_defineProperty(_this, "exportRoute", function () {
var data = JSON.stringify({
type: "FeatureCollection",
features: _this.collectRoutingFeatures()
});
FileSaver.saveAs(new Blob([data], {
type: "text/plain;charset=utf-8"
}), "route.json");
});
_defineProperty(_this, "addRouteLayer", function () {
var layer = {
id: uuidv4(),
crs: "EPSG:4326",
title: LocaleUtils.tr("routing.route"),
type: 'vector'
};
_this.props.addLayerFeatures(layer, _this.collectRoutingFeatures());
_this.props.setCurrentTask("LayerTree");
});
_defineProperty(_this, "collectIsochroneFeatures", function () {
return _this.state.isoConfig.result.data.areas.map(function (area) {
return {
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [area]
},
styleName: "default",
styleOptions: {
strokeColor: [10, 10, 255, 1],
fillColor: [10, 10, 255, 0.5],
strokeWidth: 4,
strokeDash: []
}
};
});
});
_defineProperty(_this, "exportIsochrone", function () {
var data = JSON.stringify({
type: "FeatureCollection",
features: _this.collectIsochroneFeatures()
});
FileSaver.saveAs(new Blob([data], {
type: "text/plain;charset=utf-8"
}), "isochrone.json");
});
_defineProperty(_this, "addIsochroneLayer", function () {
var layer = {
id: uuidv4(),
crs: "EPSG:4326",
title: LocaleUtils.tr("routing.reachability"),
type: 'vector'
};
_this.props.addLayerFeatures(layer, [_this.collectIsochroneFeatures()]);
_this.props.setCurrentTask("LayerTree");
});
_defineProperty(_this, "onSortChange", function (order, sortable, ev) {
var newpoints = _this.state.routeConfig.points.slice(0);
var moved = newpoints.splice(ev.oldIndex, 1)[0];
newpoints.splice(ev.newIndex, 0, moved);
_this.updateRouteConfig({
points: newpoints
});
});
_this.recomputeTimeout = null;
_this.state.mode = _this.props.enabledModes[0];
return _this;
}
_inherits(Routing, _React$Component);
return _createClass(Routing, [{
key: "componentDidUpdate",
value: function componentDidUpdate(prevProps, prevState) {
var _this2 = this;
// Recollect search providers
if (this.props.searchProviders !== prevProps.searchProviders) {
this.setState({
searchProviders: this.props.enabledProviders.map(function (key) {
return _this2.props.searchProviders[key];
}).filter(Boolean),
searchParams: {
mapcrs: this.props.mapCrs,
displaycrs: this.props.displayCrs
}
});
}
// Activated / message
if (this.props.task.id === "Routing") {
this.props.setCurrentTask(null);
if (!this.state.visible) {
this.setState({
visible: true
});
}
var taskData = this.props.task.data || {};
if (taskData.from) {
this.setState({
currentTab: 'Route'
});
this.updatePoint('routeConfig', 0, taskData.from);
}
if (taskData.to) {
this.setState({
currentTab: 'Route'
});
this.updatePoint('routeConfig', this.state.routeConfig.points.length - 1, taskData.to);
}
if (taskData.via) {
this.setState({
currentTab: 'Route'
});
this.addPoint('routeConfig', -1, taskData.via);
}
if (taskData.isocenter) {
this.setState({
currentTab: 'Reachability'
});
this.updateIsoConfig({
points: [taskData.isocenter]
});
}
if (taskData.isoextracenter) {
this.setState({
currentTab: 'Reachability'
});
this.updateIsoConfig({
points: [].concat(_toConsumableArray(this.state.isoConfig.points), [taskData.isoextracenter])
});
}
}
// Window closed
if (!this.state.visible && prevState.visible) {
this.props.removeLayer("routinggeometries");
this.props.removeLayer("routingmarkers");
this.updateRouteConfig({
points: [{
text: '',
pos: null,
crs: null
}, {
text: '',
pos: null,
crs: null
}],
result: null
}, false);
this.updateIsoConfig({
point: {
text: '',
pos: null,
crs: null
},
result: null
}, false);
}
// No further processing beyond here if not visible
if (!this.state.visible) {
return;
}
// Tab changed
if (this.state.currentTab !== prevState.currentTab) {
this.props.removeLayer("routinggeometries");
this.props.removeLayer("routingmarkers");
this.recomputeIfNeeded();
}
// Mode changed
if (this.state.mode !== prevState.mode) {
this.recomputeIfNeeded();
}
// Routing markers
if (this.state.currentTab !== prevState.currentTab || this.state.routeConfig.points !== prevState.routeConfig.points || this.state.isoConfig.points !== prevState.isoConfig.points) {
this.updateRoutingMarkers();
}
// Theme changed
if (this.props.theme !== prevProps.theme) {
this.setState({
visible: false
});
}
// Recompute when exclude layer changes
if (this.state.currentTab === 'Route' && this.state.routeConfig.excludeLayer && this.props.layers !== prevProps.layers) {
var newlayer = this.props.layers.find(function (layer) {
return layer.id === _this2.state.routeConfig.excludeLayer;
});
var prevLayer = prevProps.layers.find(function (layer) {
return layer.id === _this2.state.routeConfig.excludeLayer;
});
if (newlayer !== prevLayer) {
this.recomputeIfNeeded();
}
}
}
}, {
key: "render",
value: function render() {
var _this3 = this;
if (!this.state.visible) {
return null;
}
var tabButtons = [{
key: "Route",
label: LocaleUtils.tr("routing.route")
}, {
key: "Reachability",
label: LocaleUtils.tr("routing.reachability")
}];
var tabRenderers = {
Route: this.renderRouteWidget,
Reachability: this.renderIsochroneWidget
};
var buttons = [{
key: "auto",
icon: "routing-car",
tooltip: LocaleUtils.tr("routing.mode_auto")
}, {
key: "heavyvehicle",
icon: "routing-truck",
tooltip: LocaleUtils.tr("routing.mode_heavyvehicle")
}, {
key: "transit",
icon: "routing-train",
tooltip: LocaleUtils.tr("routing.mode_transit")
}, {
key: "bicycle",
icon: "routing-bicycle",
tooltip: LocaleUtils.tr("routing.mode_bicycle")
}, {
key: "pedestrian",
icon: "routing-walking",
tooltip: LocaleUtils.tr("routing.mode_walking")
}];
var enabledButtons = this.props.enabledModes.map(function (entry) {
return buttons.find(function (button) {
return button.key === entry;
});
});
return /*#__PURE__*/React.createElement(ResizeableWindow, {
dockable: this.props.geometry.side,
icon: "routing",
initialHeight: this.props.geometry.initialHeight,
initialW