UNPKG

qwc2

Version:
1,164 lines (1,161 loc) 54.1 kB
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