@opentripplanner/vehicle-rental-overlay 1.4.4 → 2.0.0-alpha.2

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.
@@ -0,0 +1,99 @@
1
+ import { Styled as BaseMapStyled } from "@opentripplanner/base-map";
2
+ import coreUtils from "@opentripplanner/core-utils";
3
+ import FromToLocationPicker from "@opentripplanner/from-to-location-picker";
4
+ import flatten from "flat";
5
+ import { FormattedMessage, useIntl } from "react-intl";
6
+ import React from "react"; // Load the default messages.
7
+ // @ts-expect-error why is this failing?
8
+
9
+ import defaultEnglishMessages from "../i18n/en-US.yml"; // HACK: We should flatten the messages loaded above because
10
+ // the YAML loaders behave differently between webpack and our version of jest:
11
+ // - the yaml loader for webpack returns a nested object,
12
+ // - the yaml loader for jest returns messages with flattened ids.
13
+
14
+ var defaultMessages = flatten(defaultEnglishMessages);
15
+
16
+ function makeDefaultGetStationName(intl) {
17
+ return function defaultGetStationName(configCompanies, station) {
18
+ var stationNetworks = coreUtils.itinerary.getCompaniesLabelFromNetworks((station === null || station === void 0 ? void 0 : station.networks) || [], configCompanies);
19
+ var stationName = station.name || station.id; // If the station name or id is a giant UUID (with more than 3 "-" characters)
20
+ // best not to show that at all and instead use the network name.
21
+
22
+ if ((stationName.match(/-/g) || []).length > 3) {
23
+ stationName = stationNetworks;
24
+ }
25
+
26
+ if (station.isFloatingBike) {
27
+ stationName = intl.formatMessage({
28
+ defaultMessage: defaultEnglishMessages["otpUi.VehicleRentalOverlay.floatingBike"],
29
+ description: "Popup title for a free-floating bike",
30
+ id: "otpUi.VehicleRentalOverlay.floatingBike"
31
+ }, {
32
+ name: stationName
33
+ });
34
+ } else if (station.isFloatingCar) {
35
+ stationName = intl.formatMessage({
36
+ defaultMessage: defaultEnglishMessages["otpUi.VehicleRentalOverlay.floatingCar"],
37
+ description: "Popup title for a free-floating car",
38
+ id: "otpUi.VehicleRentalOverlay.floatingCar"
39
+ }, {
40
+ company: stationNetworks,
41
+ name: stationName
42
+ });
43
+ } else if (station.isFloatingVehicle) {
44
+ // assumes that all floating vehicles are E-scooters
45
+ stationName = intl.formatMessage({
46
+ defaultMessage: defaultEnglishMessages["otpUi.VehicleRentalOverlay.floatingEScooter"],
47
+ description: "Popup title for a free-floating e-scooter",
48
+ id: "otpUi.VehicleRentalOverlay.floatingEScooter"
49
+ }, {
50
+ company: stationNetworks
51
+ });
52
+ }
53
+
54
+ return stationName;
55
+ };
56
+ }
57
+
58
+ /**
59
+ * Render some popup html for a station. This contains custom logic for
60
+ * displaying rental vehicles in the TriMet MOD website that might not be
61
+ * applicable to other regions.
62
+ */
63
+ var StationPopup = function StationPopup(props) {
64
+ var intl = useIntl();
65
+ var configCompanies = props.configCompanies,
66
+ getStationName = props.getStationName,
67
+ setLocation = props.setLocation,
68
+ station = props.station;
69
+ var stationIsHub = station.bikesAvailable !== undefined && !station.isFloatingBike;
70
+ var getStationNameFunc = getStationName || makeDefaultGetStationName(intl);
71
+ var stationName = getStationNameFunc(configCompanies, station);
72
+ var location = {
73
+ lat: station.y,
74
+ lon: station.x,
75
+ name: stationName
76
+ };
77
+ return /*#__PURE__*/React.createElement(BaseMapStyled.MapOverlayPopup, null, /*#__PURE__*/React.createElement(BaseMapStyled.PopupTitle, null, stationName), stationIsHub && /*#__PURE__*/React.createElement(BaseMapStyled.PopupRow, null, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(FormattedMessage, {
78
+ defaultMessage: defaultMessages["otpUi.VehicleRentalOverlay.availableBikes"],
79
+ description: "Label text for the number of bikes available",
80
+ id: "otpUi.VehicleRentalOverlay.availableBikes",
81
+ values: {
82
+ value: station.bikesAvailable
83
+ }
84
+ })), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(FormattedMessage, {
85
+ defaultMessage: defaultMessages["otpUi.VehicleRentalOverlay.availableDocks"],
86
+ description: "Label text for the number of docks available",
87
+ id: "otpUi.VehicleRentalOverlay.availableDocks",
88
+ values: {
89
+ value: station.spacesAvailable
90
+ }
91
+ }))), /*#__PURE__*/React.createElement(BaseMapStyled.PopupRow, null, /*#__PURE__*/React.createElement(FromToLocationPicker, {
92
+ label: true,
93
+ location: location,
94
+ setLocation: setLocation
95
+ })));
96
+ };
97
+
98
+ export default StationPopup;
99
+ //# sourceMappingURL=StationPopup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/StationPopup.tsx"],"names":["Styled","BaseMapStyled","coreUtils","FromToLocationPicker","flatten","FormattedMessage","useIntl","React","defaultEnglishMessages","defaultMessages","makeDefaultGetStationName","intl","defaultGetStationName","configCompanies","station","stationNetworks","itinerary","getCompaniesLabelFromNetworks","networks","stationName","name","id","match","length","isFloatingBike","formatMessage","defaultMessage","description","isFloatingCar","company","isFloatingVehicle","StationPopup","props","getStationName","setLocation","stationIsHub","bikesAvailable","undefined","getStationNameFunc","location","lat","y","lon","x","value","spacesAvailable"],"mappings":"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","sourcesContent":["import { Styled as BaseMapStyled } from \"@opentripplanner/base-map\";\nimport coreUtils from \"@opentripplanner/core-utils\";\nimport FromToLocationPicker from \"@opentripplanner/from-to-location-picker\";\nimport {\n Company,\n ConfiguredCompany,\n MapLocationActionArg,\n Station\n} from \"@opentripplanner/types\";\nimport flatten from \"flat\";\nimport { FormattedMessage, IntlShape, useIntl } from \"react-intl\";\nimport React from \"react\";\n\n// Load the default messages.\n// @ts-expect-error why is this failing?\nimport defaultEnglishMessages from \"../i18n/en-US.yml\";\n\n// HACK: We should flatten the messages loaded above because\n// the YAML loaders behave differently between webpack and our version of jest:\n// - the yaml loader for webpack returns a nested object,\n// - the yaml loader for jest returns messages with flattened ids.\nconst defaultMessages = flatten(defaultEnglishMessages);\n\nfunction makeDefaultGetStationName(intl: IntlShape) {\n return function defaultGetStationName(\n configCompanies: Company[],\n station: Station\n ) {\n const stationNetworks = coreUtils.itinerary.getCompaniesLabelFromNetworks(\n station?.networks || [],\n configCompanies\n );\n let stationName = station.name || station.id;\n // If the station name or id is a giant UUID (with more than 3 \"-\" characters)\n // best not to show that at all and instead use the network name.\n if ((stationName.match(/-/g) || []).length > 3) {\n stationName = stationNetworks;\n }\n\n if (station.isFloatingBike) {\n stationName = intl.formatMessage(\n {\n defaultMessage:\n defaultEnglishMessages[\"otpUi.VehicleRentalOverlay.floatingBike\"],\n description: \"Popup title for a free-floating bike\",\n id: \"otpUi.VehicleRentalOverlay.floatingBike\"\n },\n { name: stationName }\n );\n } else if (station.isFloatingCar) {\n stationName = intl.formatMessage(\n {\n defaultMessage:\n defaultEnglishMessages[\"otpUi.VehicleRentalOverlay.floatingCar\"],\n description: \"Popup title for a free-floating car\",\n id: \"otpUi.VehicleRentalOverlay.floatingCar\"\n },\n {\n company: stationNetworks,\n name: stationName\n }\n );\n } else if (station.isFloatingVehicle) {\n // assumes that all floating vehicles are E-scooters\n stationName = intl.formatMessage(\n {\n defaultMessage:\n defaultEnglishMessages[\n \"otpUi.VehicleRentalOverlay.floatingEScooter\"\n ],\n description: \"Popup title for a free-floating e-scooter\",\n id: \"otpUi.VehicleRentalOverlay.floatingEScooter\"\n },\n { company: stationNetworks }\n );\n }\n return stationName;\n };\n}\n\ntype Props = {\n configCompanies: ConfiguredCompany[];\n getStationName: (configCompanies: Company[], station: Station) => string;\n setLocation: (arg: MapLocationActionArg) => void;\n station: Station;\n};\n/**\n * Render some popup html for a station. This contains custom logic for\n * displaying rental vehicles in the TriMet MOD website that might not be\n * applicable to other regions.\n */\nconst StationPopup = (props: Props): JSX.Element => {\n const intl = useIntl();\n const { configCompanies, getStationName, setLocation, station } = props;\n const stationIsHub =\n station.bikesAvailable !== undefined && !station.isFloatingBike;\n const getStationNameFunc = getStationName || makeDefaultGetStationName(intl);\n const stationName = getStationNameFunc(configCompanies, station);\n const location = {\n lat: station.y,\n lon: station.x,\n name: stationName\n };\n return (\n <BaseMapStyled.MapOverlayPopup>\n <BaseMapStyled.PopupTitle>{stationName}</BaseMapStyled.PopupTitle>\n\n {/* render dock info if it is available */}\n {stationIsHub && (\n <BaseMapStyled.PopupRow>\n <div>\n <FormattedMessage\n defaultMessage={\n defaultMessages[\"otpUi.VehicleRentalOverlay.availableBikes\"]\n }\n description=\"Label text for the number of bikes available\"\n id=\"otpUi.VehicleRentalOverlay.availableBikes\"\n values={{ value: station.bikesAvailable }}\n />\n </div>\n <div>\n <FormattedMessage\n defaultMessage={\n defaultMessages[\"otpUi.VehicleRentalOverlay.availableDocks\"]\n }\n description=\"Label text for the number of docks available\"\n id=\"otpUi.VehicleRentalOverlay.availableDocks\"\n values={{ value: station.spacesAvailable }}\n />\n </div>\n </BaseMapStyled.PopupRow>\n )}\n\n {/* Set as from/to toolbar */}\n <BaseMapStyled.PopupRow>\n <FromToLocationPicker\n label\n location={location}\n setLocation={setLocation}\n />\n </BaseMapStyled.PopupRow>\n </BaseMapStyled.MapOverlayPopup>\n );\n};\n\nexport default StationPopup;\n"],"file":"StationPopup.js"}
package/esm/index.js CHANGED
@@ -1,378 +1,170 @@
1
- import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
2
- import _createClass from "@babel/runtime/helpers/createClass";
3
- import _inherits from "@babel/runtime/helpers/inherits";
4
- import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
5
- import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
6
3
 
7
- function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
4
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
8
5
 
9
- function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
6
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
10
7
 
11
- import flatten from "flat";
12
- import { Styled as BaseMapStyled } from "@opentripplanner/base-map";
13
- import coreUtils from "@opentripplanner/core-utils";
14
- import FromToLocationPicker from "@opentripplanner/from-to-location-picker";
15
- import ZoomBasedMarkers from "@opentripplanner/zoom-based-markers";
16
- import PropTypes from "prop-types";
17
- import React from "react";
18
- import { FormattedMessage, injectIntl } from "react-intl";
19
- import { FeatureGroup, MapLayer, Popup, withLeaflet } from "react-leaflet";
20
- import { GenericMarker, HubAndFloatingBike, SharedBikeCircle } from "./DefaultMarkers"; // Load the default messages.
8
+ import { MarkerWithPopup } from "@opentripplanner/base-map";
9
+ import React, { useEffect, useState } from "react";
10
+ import { Layer, Popup, Source, useMap } from "react-map-gl";
11
+ import StationPopup from "./StationPopup";
12
+ import { BaseBikeRentalIcon, StationMarker } from "./styled"; // TODO: Make configurable?
21
13
 
22
- import defaultEnglishMessages from "../i18n/en-US.yml"; // HACK: We should flatten the messages loaded above because
23
- // the YAML loaders behave differently between webpack and our version of jest:
24
- // - the yaml loader for webpack returns a nested object,
25
- // - the yaml loader for jest returns messages with flattened ids.
14
+ var DETAILED_MARKER_CUTOFF = 16;
26
15
 
27
- var defaultMessages = flatten(defaultEnglishMessages);
16
+ var getColorForStation = function getColorForStation(v) {
17
+ if (v.isFloatingCar) return "#009cde";
18
+ if (v.isFloatingVehicle) return "#f5a729"; // TODO: nicer color to match transitive
28
19
 
29
- function makeDefaultGetStationName(intl) {
30
- return function defaultGetStationName(configCompanies, station) {
31
- var stationNetworks = coreUtils.itinerary.getCompaniesLabelFromNetworks(station.networks, configCompanies);
32
- var stationName = station.name || station.id; // If the station name or id is a giant UUID (with more than 3 "-" characters)
33
- // best not to show that at all and instead use the network name.
20
+ if (v.bikesAvailable !== undefined || v.isFloatingBike) return "#f00";
21
+ return "gray";
22
+ };
34
23
 
35
- if ((stationName.match(/-/g) || []).length > 3) {
36
- stationName = stationNetworks;
37
- }
24
+ var checkIfPositionInViewport = function checkIfPositionInViewport(bounds, lat, lng) {
25
+ var PADDING = 0.001; // @ts-expect-error types appear to be wrong? version issue?
26
+ // eslint-disable-next-line no-underscore-dangle
38
27
 
39
- if (station.isFloatingBike) {
40
- stationName = intl.formatMessage({
41
- defaultMessage: defaultEnglishMessages["otpUi.VehicleRentalOverlay.floatingBike"],
42
- description: "Popup title for a free-floating bike",
43
- id: "otpUi.VehicleRentalOverlay.floatingBike"
44
- }, {
45
- name: stationName
46
- });
47
- } else if (station.isFloatingCar) {
48
- stationName = intl.formatMessage({
49
- defaultMessage: defaultEnglishMessages["otpUi.VehicleRentalOverlay.floatingCar"],
50
- description: "Popup title for a free-floating car",
51
- id: "otpUi.VehicleRentalOverlay.floatingCar"
52
- }, {
53
- company: stationNetworks,
54
- name: stationName
55
- });
56
- } else if (station.isFloatingVehicle) {
57
- // assumes that all floating vehicles are E-scooters
58
- stationName = intl.formatMessage({
59
- defaultMessage: defaultEnglishMessages["otpUi.VehicleRentalOverlay.floatingEScooter"],
60
- description: "Popup title for a free-floating e-scooter",
61
- id: "otpUi.VehicleRentalOverlay.floatingEScooter"
62
- }, {
63
- company: stationNetworks
64
- });
65
- }
28
+ var _ref = [bounds._sw, bounds._ne],
29
+ sw = _ref[0],
30
+ ne = _ref[1];
31
+ if (!sw || !ne) return false;
32
+ return lat >= sw.lat - PADDING && lat <= ne.lat + PADDING && lng >= sw.lng - PADDING && lng <= ne.lng + PADDING;
33
+ };
66
34
 
67
- return stationName;
68
- };
69
- }
70
35
  /**
71
36
  * This vehicle rental overlay can be used to render vehicle rentals of various
72
37
  * types. This layer can be configured to show different styles of markers at
73
38
  * different zoom levels.
74
39
  */
75
-
76
-
77
- var VehicleRentalOverlay = /*#__PURE__*/function (_MapLayer) {
78
- _inherits(VehicleRentalOverlay, _MapLayer);
79
-
80
- var _super = _createSuper(VehicleRentalOverlay);
81
-
82
- function VehicleRentalOverlay(props) {
83
- var _this;
84
-
85
- _classCallCheck(this, VehicleRentalOverlay);
86
-
87
- _this = _super.call(this, props);
88
-
89
- _this.renderSymbolWithPopup = function (_Symbol) {
90
- var SymbolWrapper = function SymbolWrapper(_ref) {
91
- var station = _ref.entity,
92
- zoom = _ref.zoom;
93
- return /*#__PURE__*/React.createElement(_Symbol, {
94
- entity: station,
95
- zoom: zoom
96
- }, _this.renderPopupForStation(station, station.bikesAvailable !== undefined && !station.isFloatingBike));
97
- };
98
-
99
- SymbolWrapper.propTypes = {
100
- // entity: coreUtils.types.stationType.isRequired,
101
- zoom: PropTypes.number.isRequired
102
- };
103
- return SymbolWrapper;
104
- };
105
-
106
- _this.convertToZoomMarkerSymbols = function (mapSymbols) {
107
- return mapSymbols.map(function (mapSymbol) {
108
- // If mapSymbol uses zoomBasedSymbolType, use it as is.
109
- if (mapSymbol.symbol) {
110
- return mapSymbol;
111
- } // Otherwise, convert into zoomBasedType (no support for symbols by type).
112
-
113
-
114
- var symbol;
115
-
116
- switch (mapSymbol.type) {
117
- case "circle":
118
- symbol = SharedBikeCircle(mapSymbol);
119
- break;
120
-
121
- case "hubAndFloatingBike":
122
- symbol = HubAndFloatingBike;
123
- break;
124
-
125
- default:
126
- symbol = GenericMarker(mapSymbol);
127
- }
128
-
129
- return {
130
- minZoom: mapSymbol.minZoom,
131
- symbol: symbol
132
- };
133
- });
134
- };
135
-
136
- _this.onOverlayAdded = function () {
137
- _this.startRefreshing();
138
- };
139
-
140
- _this.onOverlayRemoved = function () {
141
- _this.stopRefreshing();
142
- };
143
-
144
- _this.onViewportChanged = function (viewport) {
145
- var newZoom = viewport.zoom;
146
-
147
- if (_this.state.zoom !== newZoom) {
148
- _this.setState({
149
- zoom: newZoom
150
- });
151
- }
152
- };
153
-
154
- _this.renderPopupForStation = function (station) {
155
- var stationIsHub = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
156
- var _this$props = _this.props,
157
- configCompanies = _this$props.configCompanies,
158
- getStationName = _this$props.getStationName,
159
- intl = _this$props.intl,
160
- setLocation = _this$props.setLocation;
161
- var getStationNameFunc = getStationName || makeDefaultGetStationName(intl);
162
- var stationName = getStationNameFunc(configCompanies, station);
163
- var location = {
164
- lat: station.y,
165
- lon: station.x,
166
- name: stationName
167
- };
168
- return /*#__PURE__*/React.createElement(Popup, null, /*#__PURE__*/React.createElement(BaseMapStyled.MapOverlayPopup, null, /*#__PURE__*/React.createElement(BaseMapStyled.PopupTitle, null, stationName), stationIsHub && /*#__PURE__*/React.createElement(BaseMapStyled.PopupRow, null, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(FormattedMessage, {
169
- defaultMessage: defaultMessages["otpUi.VehicleRentalOverlay.availableBikes"],
170
- description: "Label text for the number of bikes available",
171
- id: "otpUi.VehicleRentalOverlay.availableBikes",
172
- values: {
173
- value: station.bikesAvailable
174
- }
175
- })), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(FormattedMessage, {
176
- defaultMessage: defaultMessages["otpUi.VehicleRentalOverlay.availableDocks"],
177
- description: "Label text for the number of docks available",
178
- id: "otpUi.VehicleRentalOverlay.availableDocks",
179
- values: {
180
- value: station.spacesAvailable
181
- }
182
- }))), /*#__PURE__*/React.createElement(BaseMapStyled.PopupRow, null, /*#__PURE__*/React.createElement(FromToLocationPicker, {
183
- label: true,
184
- location: location,
185
- setLocation: setLocation
186
- }))));
187
- };
188
-
189
- _this.state = {
190
- zoom: null
191
- };
192
- return _this;
193
- }
194
- /**
195
- * This helper method will be passed to the ZoomBasedMarkers symbolTransform prop.
196
- * It creates a component that inserts a popup
197
- * as a child of the specified symbol from the mapSymbols prop.
198
- */
199
-
200
-
201
- _createClass(VehicleRentalOverlay, [{
202
- key: "createLeafletElement",
203
- value: function createLeafletElement() {}
204
- }, {
205
- key: "updateLeafletElement",
206
- value: function updateLeafletElement() {}
207
- }, {
208
- key: "startRefreshing",
209
- value: function startRefreshing() {
210
- var refreshVehicles = this.props.refreshVehicles; // Create the timer only if refreshVehicles is a valid function.
211
-
212
- if (typeof refreshVehicles === "function") {
213
- // initial station retrieval
214
- refreshVehicles(); // set up timer to refresh stations periodically
215
-
216
- this.refreshTimer = setInterval(function () {
217
- refreshVehicles();
218
- }, 30000); // defaults to every 30 sec. TODO: make this configurable?
219
- }
220
- }
221
- }, {
222
- key: "stopRefreshing",
223
- value: function stopRefreshing() {
224
- if (this.refreshTimer) clearInterval(this.refreshTimer);
40
+ var VehicleRentalOverlay = function VehicleRentalOverlay(_ref2) {
41
+ var companies = _ref2.companies,
42
+ configCompanies = _ref2.configCompanies,
43
+ getStationName = _ref2.getStationName,
44
+ id = _ref2.id,
45
+ refreshVehicles = _ref2.refreshVehicles,
46
+ _setLocation = _ref2.setLocation,
47
+ stations = _ref2.stations,
48
+ visible = _ref2.visible;
49
+
50
+ var _useMap = useMap(),
51
+ map = _useMap.current;
52
+
53
+ var zoom = map === null || map === void 0 ? void 0 : map.getZoom();
54
+ var bounds = map === null || map === void 0 ? void 0 : map.getBounds();
55
+ var layerId = "rental-vehicles-".concat(id);
56
+
57
+ var _useState = useState(null),
58
+ _useState2 = _slicedToArray(_useState, 2),
59
+ clickedVehicle = _useState2[0],
60
+ setClickedVehicle = _useState2[1];
61
+
62
+ useEffect(function () {
63
+ // TODO: Make 30s configurable?
64
+ if (!refreshVehicles || typeof refreshVehicles !== "function") {
65
+ return;
225
66
  }
226
- /**
227
- * When the layer is added (or toggled on, or its visibility becomes true),
228
- * start refreshing vehicle positions.
229
- */
230
67
 
231
- }, {
232
- key: "componentDidMount",
233
- value:
234
- /**
235
- * Upon mounting, see whether the vehicles should be fetched,
236
- * and also call the register overlay prop that the
237
- * @opentripplanner/base-map package has injected to listen to zoom/position changes.
238
- */
239
- function componentDidMount() {
240
- var _this$props2 = this.props,
241
- leaflet = _this$props2.leaflet,
242
- registerOverlay = _this$props2.registerOverlay,
243
- visible = _this$props2.visible;
244
- this.setState({
245
- zoom: leaflet.map.getZoom()
68
+ refreshVehicles();
69
+ setInterval(refreshVehicles, 30000);
70
+ }, [refreshVehicles]);
71
+ useEffect(function () {
72
+ var VEHICLE_LAYERS = [layerId];
73
+ VEHICLE_LAYERS.forEach(function (stopLayer) {
74
+ map === null || map === void 0 ? void 0 : map.on("mouseenter", stopLayer, function () {
75
+ map.getCanvas().style.cursor = "pointer";
246
76
  });
247
- if (visible) this.startRefreshing();
248
-
249
- if (typeof registerOverlay === "function") {
250
- registerOverlay(this);
251
- }
252
- }
253
- }, {
254
- key: "componentWillUnmount",
255
- value: function componentWillUnmount() {
256
- this.stopRefreshing();
257
- }
258
- /**
259
- * Render some popup html for a station. This contains custom logic for
260
- * displaying rental vehicles in the TriMet MOD website that might not be
261
- * applicable to other regions.
262
- */
263
-
264
- }, {
265
- key: "render",
266
- value: function render() {
267
- var _this$props3 = this.props,
268
- companies = _this$props3.companies,
269
- leaflet = _this$props3.leaflet,
270
- mapSymbols = _this$props3.mapSymbols,
271
- stations = _this$props3.stations;
272
- var _this$state$zoom = this.state.zoom,
273
- zoom = _this$state$zoom === void 0 ? leaflet.map.getZoom() : _this$state$zoom; // Render an empty FeatureGroup if the rental vehicles should not be visible
274
- // on the map. Otherwise previous stations may still be shown due to some
275
- // react-leaflet internals, maybe? Also, do not return null because that will
276
- // prevent the overlay from appearing in the layer controls.
277
-
278
- var filteredStations = stations;
279
-
280
- if (companies) {
281
- filteredStations = stations.filter(function (station) {
282
- return station.networks.filter(function (value) {
283
- return companies.includes(value);
284
- }).length > 0;
285
- });
286
- }
77
+ map === null || map === void 0 ? void 0 : map.on("mouseleave", stopLayer, function () {
78
+ map.getCanvas().style.cursor = "";
79
+ });
80
+ map === null || map === void 0 ? void 0 : map.on("click", stopLayer, function (event) {
81
+ var _event$features;
287
82
 
288
- if (!filteredStations || filteredStations.length === 0) {
289
- return /*#__PURE__*/React.createElement(FeatureGroup, null);
290
- } // Convert map symbols for this overlay to zoomBasedSymbolType.
83
+ setClickedVehicle((_event$features = event.features) === null || _event$features === void 0 ? void 0 : _event$features[0].properties);
84
+ });
85
+ });
86
+ }, [map]); // Don't render if no map or no stops are defined.
291
87
 
88
+ if (visible === false || !stations || stations.length === 0) {
89
+ // Null can't be returned here -- react-map-gl dislikes null values as children
90
+ return /*#__PURE__*/React.createElement(React.Fragment, null);
91
+ }
292
92
 
293
- var symbols = this.convertToZoomMarkerSymbols(mapSymbols);
294
- return /*#__PURE__*/React.createElement(FeatureGroup, null, /*#__PURE__*/React.createElement(ZoomBasedMarkers, {
295
- entities: filteredStations,
296
- symbols: symbols,
297
- symbolTransform: this.renderSymbolWithPopup,
298
- zoom: zoom
299
- }));
93
+ var vehiclesGeoJSON = {
94
+ type: "FeatureCollection",
95
+ features: stations.filter(function (vehicle) {
96
+ return (// Include specified companies only if companies is specified and network info is available
97
+ !companies || !vehicle.networks || companies.includes(vehicle.networks[0])
98
+ );
99
+ }).map(function (vehicle) {
100
+ return {
101
+ type: "Feature",
102
+ geometry: {
103
+ type: "Point",
104
+ coordinates: [vehicle.x, vehicle.y]
105
+ },
106
+ properties: _objectSpread(_objectSpread({}, vehicle), {}, {
107
+ networks: JSON.stringify(vehicle.networks),
108
+ "stroke-width": vehicle.isFloatingBike || vehicle.isFloatingVehicle ? 1 : 2,
109
+ color: getColorForStation(vehicle)
110
+ })
111
+ };
112
+ })
113
+ };
114
+ return /*#__PURE__*/React.createElement(React.Fragment, null, zoom < DETAILED_MARKER_CUTOFF && /*#__PURE__*/React.createElement(Source, {
115
+ type: "geojson",
116
+ data: vehiclesGeoJSON
117
+ }, /*#__PURE__*/React.createElement(Layer, {
118
+ id: layerId,
119
+ paint: {
120
+ "circle-color": ["get", "color"],
121
+ "circle-opacity": 0.9,
122
+ "circle-stroke-color": "#333",
123
+ "circle-stroke-width": ["get", "stroke-width"]
124
+ },
125
+ type: "circle"
126
+ })), zoom >= DETAILED_MARKER_CUTOFF && stations.filter(function (station) {
127
+ return checkIfPositionInViewport(bounds, station.y, station.x);
128
+ }).map(function (station) {
129
+ return /*#__PURE__*/React.createElement(MarkerWithPopup, {
130
+ key: station.id,
131
+ popupContents: /*#__PURE__*/React.createElement(StationPopup, {
132
+ configCompanies: configCompanies,
133
+ setLocation: function setLocation(location) {
134
+ setClickedVehicle(null);
135
+
136
+ _setLocation(location);
137
+ },
138
+ getStationName: getStationName,
139
+ station: station
140
+ }),
141
+ position: [station.y, station.x]
142
+ }, station.bikesAvailable !== undefined && !station.isFloatingBike && !station.isFloatingVehicle && station.spacesAvailable !== undefined ? /*#__PURE__*/React.createElement(BaseBikeRentalIcon, {
143
+ percent: (station === null || station === void 0 ? void 0 : station.bikesAvailable) / ((station === null || station === void 0 ? void 0 : station.bikesAvailable) + (station === null || station === void 0 ? void 0 : station.spacesAvailable))
144
+ }) : /*#__PURE__*/React.createElement(StationMarker, {
145
+ width: 12,
146
+ color: getColorForStation(station)
147
+ }));
148
+ }), clickedVehicle && /*#__PURE__*/React.createElement(Popup, {
149
+ latitude: clickedVehicle.y,
150
+ longitude: clickedVehicle.x,
151
+ maxWidth: "100%",
152
+ onClose: function onClose() {
153
+ setClickedVehicle(null);
300
154
  }
301
- }]);
302
-
303
- return VehicleRentalOverlay;
304
- }(MapLayer);
305
-
306
- VehicleRentalOverlay.props = {
307
- /**
308
- * The entire companies config array.
309
- */
310
- // configCompanies: PropTypes.arrayOf(coreUtils.types.companyType.isRequired)
311
- // .isRequired,
312
-
313
- /**
314
- * A list of companies that are applicable to just this instance of the
315
- * overlay.
316
- */
317
- companies: PropTypes.arrayOf(PropTypes.string.isRequired),
318
-
319
- /**
320
- * An optional custom function to create a string name of a particular vehicle
321
- * rental station. This function takes two arguments of the configCompanies
322
- * prop and a vehicle rental station. The function must return a string.
323
- */
324
- getStationName: PropTypes.func,
325
-
326
- /**
327
- * A configuration of what map markers or symbols to show at various
328
- * zoom levels.
329
- */
330
- // mapSymbols: coreUtils.types.vehicleRentalMapOverlaySymbolsType,
331
-
332
- /**
333
- * If specified, a function that will be triggered every 30 seconds whenever this layer is
334
- * visible.
335
- */
336
- refreshVehicles: PropTypes.func,
337
-
338
- /**
339
- * A callback for when a user clicks on setting this stop as either the from
340
- * or to location of a new search.
341
- *
342
- * This will be dispatched with the following argument:
343
- *
344
- * ```js
345
- * {
346
- * location: {
347
- * lat: number,
348
- * lon: number,
349
- * name: string
350
- * },
351
- * locationType: "from" or "to"
352
- * }
353
- * ```
354
- */
355
- setLocation: PropTypes.func.isRequired,
356
-
357
- /**
358
- * A list of the vehicle rental stations specific to this overlay instance.
359
- */
360
- // stations: PropTypes.arrayOf(coreUtils.types.stationType),
361
-
362
- /**
363
- * Whether the overlay is currently visible.
364
- */
365
- visible: PropTypes.bool
366
- };
367
- VehicleRentalOverlay.defaultProps = {
368
- getStationName: null,
369
- mapSymbols: [{
370
- zoom: 0,
371
- symbol: GenericMarker
372
- }],
373
- refreshVehicles: null,
374
- stations: [],
375
- visible: false
155
+ }, /*#__PURE__*/React.createElement(StationPopup, {
156
+ configCompanies: configCompanies,
157
+ getStationName: getStationName,
158
+ setLocation: function setLocation(location) {
159
+ setClickedVehicle(null);
160
+
161
+ _setLocation(location);
162
+ },
163
+ station: _objectSpread(_objectSpread({}, clickedVehicle), {}, {
164
+ networks: JSON.parse(clickedVehicle.networks)
165
+ })
166
+ })));
376
167
  };
377
- export default withLeaflet(injectIntl(VehicleRentalOverlay));
168
+
169
+ export default VehicleRentalOverlay;
378
170
  //# sourceMappingURL=index.js.map