@opentripplanner/vehicle-rental-overlay 1.4.3 → 2.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/StationPopup.js +99 -0
- package/esm/StationPopup.js.map +1 -0
- package/esm/index.js +145 -355
- package/esm/index.js.map +1 -1
- package/esm/styled.js +48 -50
- package/esm/styled.js.map +1 -1
- package/lib/StationPopup.d.ts +15 -0
- package/lib/StationPopup.d.ts.map +1 -0
- package/lib/StationPopup.js +119 -0
- package/lib/StationPopup.js.map +1 -0
- package/lib/index.d.ts +61 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +126 -334
- package/lib/index.js.map +1 -1
- package/lib/styled.d.ts +11 -0
- package/lib/styled.d.ts.map +1 -0
- package/lib/styled.js +48 -63
- package/lib/styled.js.map +1 -1
- package/package.json +8 -6
- package/src/StationPopup.tsx +146 -0
- package/src/VehicleRentalOverlay.story.tsx +124 -0
- package/src/index.tsx +255 -0
- package/src/styled.ts +52 -0
- package/tsconfig.json +15 -0
- package/tsconfig.tsbuildinfo +4891 -0
- package/esm/DefaultMarkers/index.js +0 -140
- package/esm/DefaultMarkers/index.js.map +0 -1
- package/esm/bike-icons.js +0 -21
- package/esm/bike-icons.js.map +0 -1
- package/lib/DefaultMarkers/index.js +0 -165
- package/lib/DefaultMarkers/index.js.map +0 -1
- package/lib/bike-icons.js +0 -38
- package/lib/bike-icons.js.map +0 -1
- package/src/DefaultMarkers/index.js +0 -130
- package/src/VehicleRentalOverlay.story.js +0 -284
- package/src/bike-icons.js +0 -23
- package/src/index.js +0 -377
- package/src/styled.js +0 -78
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Company, Station, MapLocationActionArg, ConfiguredCompany } from "@opentripplanner/types";
|
|
2
|
+
declare type Props = {
|
|
3
|
+
/**
|
|
4
|
+
* The entire companies config array.
|
|
5
|
+
*/
|
|
6
|
+
configCompanies: ConfiguredCompany[];
|
|
7
|
+
/**
|
|
8
|
+
* A list of companies that are applicable to just this instance of the
|
|
9
|
+
* overlay.
|
|
10
|
+
*/
|
|
11
|
+
companies?: string[];
|
|
12
|
+
/**
|
|
13
|
+
* An id, used to make this layer uniquely identifiable
|
|
14
|
+
*/
|
|
15
|
+
id: string;
|
|
16
|
+
/**
|
|
17
|
+
* An optional custom function to create a string name of a particular vehicle
|
|
18
|
+
* rental station. This function takes two arguments of the configCompanies
|
|
19
|
+
* prop and a vehicle rental station. The function must return a string.
|
|
20
|
+
*/
|
|
21
|
+
getStationName?: (configCompanies: Company[], station: Station) => string;
|
|
22
|
+
/**
|
|
23
|
+
* If specified, a function that will be triggered every 30 seconds whenever this layer is
|
|
24
|
+
* visible.
|
|
25
|
+
*/
|
|
26
|
+
refreshVehicles?: () => void;
|
|
27
|
+
/**
|
|
28
|
+
* A callback for when a user clicks on setting this stop as either the from
|
|
29
|
+
* or to location of a new search.
|
|
30
|
+
*
|
|
31
|
+
* This will be dispatched with the following argument:
|
|
32
|
+
*
|
|
33
|
+
* ```js
|
|
34
|
+
* {
|
|
35
|
+
* location: {
|
|
36
|
+
* lat: number,
|
|
37
|
+
* lon: number,
|
|
38
|
+
* name: string
|
|
39
|
+
* },
|
|
40
|
+
* locationType: "from" or "to"
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
setLocation?: (arg: MapLocationActionArg) => void;
|
|
45
|
+
/**
|
|
46
|
+
* A list of the vehicle rental stations specific to this overlay instance.
|
|
47
|
+
*/
|
|
48
|
+
stations: Station[];
|
|
49
|
+
/**
|
|
50
|
+
* Whether the overlay is currently visible.
|
|
51
|
+
*/
|
|
52
|
+
visible?: boolean;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* This vehicle rental overlay can be used to render vehicle rentals of various
|
|
56
|
+
* types. This layer can be configured to show different styles of markers at
|
|
57
|
+
* different zoom levels.
|
|
58
|
+
*/
|
|
59
|
+
declare const VehicleRentalOverlay: (props: Props) => JSX.Element;
|
|
60
|
+
export default VehicleRentalOverlay;
|
|
61
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,OAAO,EACP,OAAO,EACP,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAmChC,aAAK,KAAK,GAAG;IACX;;OAEG;IACH,eAAe,EAAE,iBAAiB,EAAE,CAAC;IACrC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,eAAe,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IAC1E;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B;;;;;;;;;;;;;;;;OAgBG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAClD;;OAEG;IACH,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CAInB,CAAC;AAEF;;;;GAIG;AACH,QAAA,MAAM,oBAAoB,UAAW,KAAK,KAAG,WAqJ5C,CAAC;AACF,eAAe,oBAAoB,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -7,366 +7,158 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
});
|
|
8
8
|
exports.default = void 0;
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var _reactMapGl = require("react-map-gl");
|
|
11
11
|
|
|
12
|
-
var
|
|
13
|
-
|
|
14
|
-
var _coreUtils = _interopRequireDefault(require("@opentripplanner/core-utils"));
|
|
15
|
-
|
|
16
|
-
var _fromToLocationPicker = _interopRequireDefault(require("@opentripplanner/from-to-location-picker"));
|
|
17
|
-
|
|
18
|
-
var _zoomBasedMarkers = _interopRequireDefault(require("@opentripplanner/zoom-based-markers"));
|
|
19
|
-
|
|
20
|
-
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
12
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
21
13
|
|
|
22
|
-
var
|
|
14
|
+
var _baseMap = require("@opentripplanner/base-map");
|
|
23
15
|
|
|
24
|
-
var
|
|
16
|
+
var _StationPopup = _interopRequireDefault(require("./StationPopup"));
|
|
25
17
|
|
|
26
|
-
var
|
|
18
|
+
var _styled = require("./styled");
|
|
27
19
|
|
|
28
|
-
|
|
20
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
29
21
|
|
|
30
|
-
var
|
|
22
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
31
23
|
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
// the YAML loaders behave differently between webpack and our version of jest:
|
|
35
|
-
// - the yaml loader for webpack returns a nested object,
|
|
36
|
-
// - the yaml loader for jest returns messages with flattened ids.
|
|
37
|
-
const defaultMessages = (0, _flat.default)(_enUS.default);
|
|
24
|
+
// TODO: Make configurable?
|
|
25
|
+
const DETAILED_MARKER_CUTOFF = 16;
|
|
38
26
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
27
|
+
const getColorForStation = v => {
|
|
28
|
+
if (v.isFloatingCar) return "#009cde";
|
|
29
|
+
if (v.isFloatingVehicle) return "#f5a729"; // TODO: nicer color to match transitive
|
|
42
30
|
|
|
43
|
-
|
|
44
|
-
|
|
31
|
+
if (v.bikesAvailable !== undefined || v.isFloatingBike) return "#f00";
|
|
32
|
+
return "gray";
|
|
33
|
+
};
|
|
45
34
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
const checkIfPositionInViewport = (bounds, lat, lng) => {
|
|
36
|
+
const PADDING = 0.001; // @ts-expect-error types appear to be wrong? version issue?
|
|
37
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
49
38
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
id: "otpUi.VehicleRentalOverlay.floatingBike"
|
|
55
|
-
}, {
|
|
56
|
-
name: stationName
|
|
57
|
-
});
|
|
58
|
-
} else if (station.isFloatingCar) {
|
|
59
|
-
stationName = intl.formatMessage({
|
|
60
|
-
defaultMessage: _enUS.default["otpUi.VehicleRentalOverlay.floatingCar"],
|
|
61
|
-
description: "Popup title for a free-floating car",
|
|
62
|
-
id: "otpUi.VehicleRentalOverlay.floatingCar"
|
|
63
|
-
}, {
|
|
64
|
-
company: stationNetworks,
|
|
65
|
-
name: stationName
|
|
66
|
-
});
|
|
67
|
-
} else if (station.isFloatingVehicle) {
|
|
68
|
-
// assumes that all floating vehicles are E-scooters
|
|
69
|
-
stationName = intl.formatMessage({
|
|
70
|
-
defaultMessage: _enUS.default["otpUi.VehicleRentalOverlay.floatingEScooter"],
|
|
71
|
-
description: "Popup title for a free-floating e-scooter",
|
|
72
|
-
id: "otpUi.VehicleRentalOverlay.floatingEScooter"
|
|
73
|
-
}, {
|
|
74
|
-
company: stationNetworks
|
|
75
|
-
});
|
|
76
|
-
}
|
|
39
|
+
const [sw, ne] = [bounds._sw, bounds._ne];
|
|
40
|
+
if (!sw || !ne) return false;
|
|
41
|
+
return lat >= sw.lat - PADDING && lat <= ne.lat + PADDING && lng >= sw.lng - PADDING && lng <= ne.lng + PADDING;
|
|
42
|
+
};
|
|
77
43
|
|
|
78
|
-
return stationName;
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
44
|
/**
|
|
82
45
|
* This vehicle rental overlay can be used to render vehicle rentals of various
|
|
83
46
|
* types. This layer can be configured to show different styles of markers at
|
|
84
47
|
* different zoom levels.
|
|
85
48
|
*/
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
this.convertToZoomMarkerSymbols = mapSymbols => mapSymbols.map(mapSymbol => {
|
|
109
|
-
// If mapSymbol uses zoomBasedSymbolType, use it as is.
|
|
110
|
-
if (mapSymbol.symbol) {
|
|
111
|
-
return mapSymbol;
|
|
112
|
-
} // Otherwise, convert into zoomBasedType (no support for symbols by type).
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
let symbol;
|
|
116
|
-
|
|
117
|
-
switch (mapSymbol.type) {
|
|
118
|
-
case "circle":
|
|
119
|
-
symbol = (0, _DefaultMarkers.SharedBikeCircle)(mapSymbol);
|
|
120
|
-
break;
|
|
121
|
-
|
|
122
|
-
case "hubAndFloatingBike":
|
|
123
|
-
symbol = _DefaultMarkers.HubAndFloatingBike;
|
|
124
|
-
break;
|
|
125
|
-
|
|
126
|
-
default:
|
|
127
|
-
symbol = (0, _DefaultMarkers.GenericMarker)(mapSymbol);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
minZoom: mapSymbol.minZoom,
|
|
132
|
-
symbol
|
|
133
|
-
};
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
this.onOverlayAdded = () => {
|
|
137
|
-
this.startRefreshing();
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
this.onOverlayRemoved = () => {
|
|
141
|
-
this.stopRefreshing();
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
this.onViewportChanged = viewport => {
|
|
145
|
-
const {
|
|
146
|
-
zoom: newZoom
|
|
147
|
-
} = viewport;
|
|
148
|
-
|
|
149
|
-
if (this.state.zoom !== newZoom) {
|
|
150
|
-
this.setState({
|
|
151
|
-
zoom: newZoom
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
this.renderPopupForStation = (station, stationIsHub = false) => {
|
|
157
|
-
const {
|
|
158
|
-
configCompanies,
|
|
159
|
-
getStationName,
|
|
160
|
-
intl,
|
|
161
|
-
setLocation
|
|
162
|
-
} = this.props;
|
|
163
|
-
const getStationNameFunc = getStationName || makeDefaultGetStationName(intl);
|
|
164
|
-
const stationName = getStationNameFunc(configCompanies, station);
|
|
165
|
-
const location = {
|
|
166
|
-
lat: station.y,
|
|
167
|
-
lon: station.x,
|
|
168
|
-
name: stationName
|
|
169
|
-
};
|
|
170
|
-
return /*#__PURE__*/_react.default.createElement(_reactLeaflet.Popup, null, /*#__PURE__*/_react.default.createElement(_baseMap.Styled.MapOverlayPopup, null, /*#__PURE__*/_react.default.createElement(_baseMap.Styled.PopupTitle, null, stationName), stationIsHub && /*#__PURE__*/_react.default.createElement(_baseMap.Styled.PopupRow, null, /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, {
|
|
171
|
-
defaultMessage: defaultMessages["otpUi.VehicleRentalOverlay.availableBikes"],
|
|
172
|
-
description: "Label text for the number of bikes available",
|
|
173
|
-
id: "otpUi.VehicleRentalOverlay.availableBikes",
|
|
174
|
-
values: {
|
|
175
|
-
value: station.bikesAvailable
|
|
176
|
-
}
|
|
177
|
-
})), /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, {
|
|
178
|
-
defaultMessage: defaultMessages["otpUi.VehicleRentalOverlay.availableDocks"],
|
|
179
|
-
description: "Label text for the number of docks available",
|
|
180
|
-
id: "otpUi.VehicleRentalOverlay.availableDocks",
|
|
181
|
-
values: {
|
|
182
|
-
value: station.spacesAvailable
|
|
183
|
-
}
|
|
184
|
-
}))), /*#__PURE__*/_react.default.createElement(_baseMap.Styled.PopupRow, null, /*#__PURE__*/_react.default.createElement(_fromToLocationPicker.default, {
|
|
185
|
-
label: true,
|
|
186
|
-
location: location,
|
|
187
|
-
setLocation: setLocation
|
|
188
|
-
}))));
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
this.state = {
|
|
192
|
-
zoom: null
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* This helper method will be passed to the ZoomBasedMarkers symbolTransform prop.
|
|
197
|
-
* It creates a component that inserts a popup
|
|
198
|
-
* as a child of the specified symbol from the mapSymbols prop.
|
|
199
|
-
*/
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
createLeafletElement() {}
|
|
203
|
-
|
|
204
|
-
updateLeafletElement() {}
|
|
205
|
-
|
|
206
|
-
startRefreshing() {
|
|
207
|
-
const {
|
|
208
|
-
refreshVehicles
|
|
209
|
-
} = this.props; // Create the timer only if refreshVehicles is a valid function.
|
|
210
|
-
|
|
211
|
-
if (typeof refreshVehicles === "function") {
|
|
212
|
-
// initial station retrieval
|
|
213
|
-
refreshVehicles(); // set up timer to refresh stations periodically
|
|
214
|
-
|
|
215
|
-
this.refreshTimer = setInterval(() => {
|
|
216
|
-
refreshVehicles();
|
|
217
|
-
}, 30000); // defaults to every 30 sec. TODO: make this configurable?
|
|
49
|
+
const VehicleRentalOverlay = props => {
|
|
50
|
+
const {
|
|
51
|
+
mainMap
|
|
52
|
+
} = (0, _reactMapGl.useMap)();
|
|
53
|
+
const zoom = mainMap === null || mainMap === void 0 ? void 0 : mainMap.getZoom();
|
|
54
|
+
const bounds = mainMap === null || mainMap === void 0 ? void 0 : mainMap.getBounds();
|
|
55
|
+
const {
|
|
56
|
+
configCompanies,
|
|
57
|
+
companies,
|
|
58
|
+
getStationName,
|
|
59
|
+
id,
|
|
60
|
+
refreshVehicles,
|
|
61
|
+
setLocation,
|
|
62
|
+
stations,
|
|
63
|
+
visible
|
|
64
|
+
} = props;
|
|
65
|
+
const layerId = `rental-vehicles-${id}`;
|
|
66
|
+
const [clickedVehicle, setClickedVehicle] = (0, _react.useState)(null);
|
|
67
|
+
(0, _react.useEffect)(() => {
|
|
68
|
+
// TODO: Make 30s configurable?
|
|
69
|
+
if (!refreshVehicles || typeof refreshVehicles !== "function") {
|
|
70
|
+
return;
|
|
218
71
|
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
stopRefreshing() {
|
|
222
|
-
if (this.refreshTimer) clearInterval(this.refreshTimer);
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* When the layer is added (or toggled on, or its visibility becomes true),
|
|
226
|
-
* start refreshing vehicle positions.
|
|
227
|
-
*/
|
|
228
72
|
|
|
73
|
+
refreshVehicles();
|
|
74
|
+
setInterval(refreshVehicles, 30_000);
|
|
75
|
+
}, [refreshVehicles]);
|
|
76
|
+
(0, _react.useEffect)(() => {
|
|
77
|
+
const VEHICLE_LAYERS = [layerId];
|
|
78
|
+
VEHICLE_LAYERS.forEach(stopLayer => {
|
|
79
|
+
mainMap === null || mainMap === void 0 ? void 0 : mainMap.on("mouseenter", stopLayer, () => {
|
|
80
|
+
mainMap.getCanvas().style.cursor = "pointer";
|
|
81
|
+
});
|
|
82
|
+
mainMap === null || mainMap === void 0 ? void 0 : mainMap.on("mouseleave", stopLayer, () => {
|
|
83
|
+
mainMap.getCanvas().style.cursor = "";
|
|
84
|
+
});
|
|
85
|
+
mainMap === null || mainMap === void 0 ? void 0 : mainMap.on("click", stopLayer, event => {
|
|
86
|
+
var _event$features;
|
|
229
87
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
* and also call the register overlay prop that the
|
|
233
|
-
* @opentripplanner/base-map package has injected to listen to zoom/position changes.
|
|
234
|
-
*/
|
|
235
|
-
componentDidMount() {
|
|
236
|
-
const {
|
|
237
|
-
leaflet,
|
|
238
|
-
registerOverlay,
|
|
239
|
-
visible
|
|
240
|
-
} = this.props;
|
|
241
|
-
this.setState({
|
|
242
|
-
zoom: leaflet.map.getZoom()
|
|
88
|
+
setClickedVehicle((_event$features = event.features) === null || _event$features === void 0 ? void 0 : _event$features[0].properties);
|
|
89
|
+
});
|
|
243
90
|
});
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (typeof registerOverlay === "function") {
|
|
247
|
-
registerOverlay(this);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
91
|
+
}, [mainMap]); // Don't render if no map or no stops are defined.
|
|
250
92
|
|
|
251
|
-
|
|
252
|
-
|
|
93
|
+
if (visible === false || !stations || stations.length === 0) {
|
|
94
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null);
|
|
253
95
|
}
|
|
254
|
-
/**
|
|
255
|
-
* Render some popup html for a station. This contains custom logic for
|
|
256
|
-
* displaying rental vehicles in the TriMet MOD website that might not be
|
|
257
|
-
* applicable to other regions.
|
|
258
|
-
*/
|
|
259
96
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
97
|
+
const vehiclesGeoJSON = {
|
|
98
|
+
type: "FeatureCollection",
|
|
99
|
+
features: stations.filter(vehicle => // Include specified companies only if companies is specified and network info is available
|
|
100
|
+
!companies || !vehicle.networks || companies.includes(vehicle.networks[0])).map(vehicle => ({
|
|
101
|
+
type: "Feature",
|
|
102
|
+
properties: { ...vehicle,
|
|
103
|
+
networks: JSON.stringify(vehicle.networks),
|
|
104
|
+
"stroke-width": vehicle.isFloatingBike || vehicle.isFloatingVehicle ? 1 : 2,
|
|
105
|
+
color: getColorForStation(vehicle)
|
|
106
|
+
},
|
|
107
|
+
geometry: {
|
|
108
|
+
type: "Point",
|
|
109
|
+
coordinates: [vehicle.x, vehicle.y]
|
|
110
|
+
}
|
|
111
|
+
}))
|
|
112
|
+
};
|
|
113
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, zoom < DETAILED_MARKER_CUTOFF && /*#__PURE__*/_react.default.createElement(_reactMapGl.Source, {
|
|
114
|
+
type: "geojson",
|
|
115
|
+
data: vehiclesGeoJSON
|
|
116
|
+
}, /*#__PURE__*/_react.default.createElement(_reactMapGl.Layer, {
|
|
117
|
+
id: layerId,
|
|
118
|
+
type: "circle",
|
|
119
|
+
paint: {
|
|
120
|
+
"circle-color": ["get", "color"],
|
|
121
|
+
"circle-opacity": 0.9,
|
|
122
|
+
"circle-stroke-width": ["get", "stroke-width"],
|
|
123
|
+
"circle-stroke-color": "#333"
|
|
279
124
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
getStationName: _propTypes.default.func,
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* A configuration of what map markers or symbols to show at various
|
|
319
|
-
* zoom levels.
|
|
320
|
-
*/
|
|
321
|
-
// mapSymbols: coreUtils.types.vehicleRentalMapOverlaySymbolsType,
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* If specified, a function that will be triggered every 30 seconds whenever this layer is
|
|
325
|
-
* visible.
|
|
326
|
-
*/
|
|
327
|
-
refreshVehicles: _propTypes.default.func,
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
* A callback for when a user clicks on setting this stop as either the from
|
|
331
|
-
* or to location of a new search.
|
|
332
|
-
*
|
|
333
|
-
* This will be dispatched with the following argument:
|
|
334
|
-
*
|
|
335
|
-
* ```js
|
|
336
|
-
* {
|
|
337
|
-
* location: {
|
|
338
|
-
* lat: number,
|
|
339
|
-
* lon: number,
|
|
340
|
-
* name: string
|
|
341
|
-
* },
|
|
342
|
-
* locationType: "from" or "to"
|
|
343
|
-
* }
|
|
344
|
-
* ```
|
|
345
|
-
*/
|
|
346
|
-
setLocation: _propTypes.default.func.isRequired,
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* A list of the vehicle rental stations specific to this overlay instance.
|
|
350
|
-
*/
|
|
351
|
-
// stations: PropTypes.arrayOf(coreUtils.types.stationType),
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Whether the overlay is currently visible.
|
|
355
|
-
*/
|
|
356
|
-
visible: _propTypes.default.bool
|
|
357
|
-
};
|
|
358
|
-
VehicleRentalOverlay.defaultProps = {
|
|
359
|
-
getStationName: null,
|
|
360
|
-
mapSymbols: [{
|
|
361
|
-
zoom: 0,
|
|
362
|
-
symbol: _DefaultMarkers.GenericMarker
|
|
363
|
-
}],
|
|
364
|
-
refreshVehicles: null,
|
|
365
|
-
stations: [],
|
|
366
|
-
visible: false
|
|
125
|
+
})), zoom >= DETAILED_MARKER_CUTOFF && stations.filter(station => checkIfPositionInViewport(bounds, station.y, station.x)).map(station => /*#__PURE__*/_react.default.createElement(_baseMap.MarkerWithPopup, {
|
|
126
|
+
key: station.id,
|
|
127
|
+
position: [station.y, station.x],
|
|
128
|
+
popupContents: /*#__PURE__*/_react.default.createElement(_StationPopup.default, {
|
|
129
|
+
configCompanies: configCompanies,
|
|
130
|
+
setLocation: location => {
|
|
131
|
+
setClickedVehicle(null);
|
|
132
|
+
setLocation(location);
|
|
133
|
+
},
|
|
134
|
+
getStationName: getStationName,
|
|
135
|
+
station: station
|
|
136
|
+
})
|
|
137
|
+
}, station.bikesAvailable !== undefined && !station.isFloatingBike && !station.isFloatingVehicle && station.spacesAvailable !== undefined ? /*#__PURE__*/_react.default.createElement(_styled.BaseBikeRentalIcon, {
|
|
138
|
+
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))
|
|
139
|
+
}) : /*#__PURE__*/_react.default.createElement(_styled.StationMarker, {
|
|
140
|
+
width: 12,
|
|
141
|
+
color: getColorForStation(station)
|
|
142
|
+
}))), clickedVehicle && /*#__PURE__*/_react.default.createElement(_reactMapGl.Popup, {
|
|
143
|
+
onClose: () => {
|
|
144
|
+
setClickedVehicle(null);
|
|
145
|
+
},
|
|
146
|
+
longitude: clickedVehicle.x,
|
|
147
|
+
latitude: clickedVehicle.y,
|
|
148
|
+
maxWidth: "100%"
|
|
149
|
+
}, /*#__PURE__*/_react.default.createElement(_StationPopup.default, {
|
|
150
|
+
configCompanies: configCompanies,
|
|
151
|
+
setLocation: location => {
|
|
152
|
+
setClickedVehicle(null);
|
|
153
|
+
setLocation(location);
|
|
154
|
+
},
|
|
155
|
+
getStationName: getStationName,
|
|
156
|
+
station: { ...clickedVehicle,
|
|
157
|
+
networks: JSON.parse(clickedVehicle.networks)
|
|
158
|
+
}
|
|
159
|
+
})));
|
|
367
160
|
};
|
|
368
161
|
|
|
369
|
-
var _default =
|
|
370
|
-
|
|
162
|
+
var _default = VehicleRentalOverlay;
|
|
371
163
|
exports.default = _default;
|
|
372
164
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.js"],"names":["defaultMessages","defaultEnglishMessages","makeDefaultGetStationName","intl","defaultGetStationName","configCompanies","station","stationNetworks","coreUtils","itinerary","getCompaniesLabelFromNetworks","networks","stationName","name","id","match","length","isFloatingBike","formatMessage","defaultMessage","description","isFloatingCar","company","isFloatingVehicle","VehicleRentalOverlay","MapLayer","constructor","props","renderSymbolWithPopup","Symbol","SymbolWrapper","entity","zoom","renderPopupForStation","bikesAvailable","undefined","propTypes","PropTypes","number","isRequired","convertToZoomMarkerSymbols","mapSymbols","map","mapSymbol","symbol","type","HubAndFloatingBike","minZoom","onOverlayAdded","startRefreshing","onOverlayRemoved","stopRefreshing","onViewportChanged","viewport","newZoom","state","setState","stationIsHub","getStationName","setLocation","getStationNameFunc","location","lat","y","lon","x","value","spacesAvailable","createLeafletElement","updateLeafletElement","refreshVehicles","refreshTimer","setInterval","clearInterval","componentDidMount","leaflet","registerOverlay","visible","getZoom","componentWillUnmount","render","companies","stations","filteredStations","filter","includes","symbols","arrayOf","string","func","bool","defaultProps","GenericMarker"],"mappings":"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","sourcesContent":["import flatten from \"flat\";\nimport { Styled as BaseMapStyled } from \"@opentripplanner/base-map\";\nimport coreUtils from \"@opentripplanner/core-utils\";\nimport FromToLocationPicker from \"@opentripplanner/from-to-location-picker\";\nimport ZoomBasedMarkers from \"@opentripplanner/zoom-based-markers\";\nimport PropTypes from \"prop-types\";\nimport React from \"react\";\nimport { FormattedMessage, injectIntl } from \"react-intl\";\nimport { FeatureGroup, MapLayer, Popup, withLeaflet } from \"react-leaflet\";\n\nimport {\n GenericMarker,\n HubAndFloatingBike,\n SharedBikeCircle\n} from \"./DefaultMarkers\";\n\n// Load the default messages.\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) {\n return function defaultGetStationName(configCompanies, station) {\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\n/**\n * This vehicle rental overlay can be used to render vehicle rentals of various\n * types. This layer can be configured to show different styles of markers at\n * different zoom levels.\n */\nclass VehicleRentalOverlay extends MapLayer {\n constructor(props) {\n super(props);\n this.state = {\n zoom: null\n };\n }\n\n /**\n * This helper method will be passed to the ZoomBasedMarkers symbolTransform prop.\n * It creates a component that inserts a popup\n * as a child of the specified symbol from the mapSymbols prop.\n */\n renderSymbolWithPopup = Symbol => {\n const SymbolWrapper = ({ entity: station, zoom }) => (\n <Symbol entity={station} zoom={zoom}>\n {this.renderPopupForStation(\n station,\n station.bikesAvailable !== undefined && !station.isFloatingBike\n )}\n </Symbol>\n );\n SymbolWrapper.propTypes = {\n // entity: coreUtils.types.stationType.isRequired,\n zoom: PropTypes.number.isRequired\n };\n\n return SymbolWrapper;\n };\n\n /**\n * Convert map symbols to zoomBasedSymbolType.\n */\n convertToZoomMarkerSymbols = mapSymbols =>\n mapSymbols.map(mapSymbol => {\n // If mapSymbol uses zoomBasedSymbolType, use it as is.\n if (mapSymbol.symbol) {\n return mapSymbol;\n }\n\n // Otherwise, convert into zoomBasedType (no support for symbols by type).\n let symbol;\n switch (mapSymbol.type) {\n case \"circle\":\n symbol = SharedBikeCircle(mapSymbol);\n break;\n case \"hubAndFloatingBike\":\n symbol = HubAndFloatingBike;\n break;\n default:\n symbol = GenericMarker(mapSymbol);\n }\n\n return {\n minZoom: mapSymbol.minZoom,\n symbol\n };\n });\n\n createLeafletElement() {}\n\n updateLeafletElement() {}\n\n startRefreshing() {\n const { refreshVehicles } = this.props;\n\n // Create the timer only if refreshVehicles is a valid function.\n if (typeof refreshVehicles === \"function\") {\n // initial station retrieval\n refreshVehicles();\n\n // set up timer to refresh stations periodically\n this.refreshTimer = setInterval(() => {\n refreshVehicles();\n }, 30000); // defaults to every 30 sec. TODO: make this configurable?\n }\n }\n\n stopRefreshing() {\n if (this.refreshTimer) clearInterval(this.refreshTimer);\n }\n\n /**\n * When the layer is added (or toggled on, or its visibility becomes true),\n * start refreshing vehicle positions.\n */\n onOverlayAdded = () => {\n this.startRefreshing();\n };\n\n /**\n * When the layer is removed (or toggled off, or its visibility becomes false),\n * stop refreshing vehicle positions.\n */\n onOverlayRemoved = () => {\n this.stopRefreshing();\n };\n\n /**\n * Listen to changes on the BaseMap's center or zoom.\n * @param viewport The viewport data. See https://github.com/PaulLeCam/react-leaflet/blob/master/example/components/viewport.js for details.\n */\n onViewportChanged = viewport => {\n const { zoom: newZoom } = viewport;\n if (this.state.zoom !== newZoom) {\n this.setState({ zoom: newZoom });\n }\n };\n\n /**\n * Upon mounting, see whether the vehicles should be fetched,\n * and also call the register overlay prop that the\n * @opentripplanner/base-map package has injected to listen to zoom/position changes.\n */\n componentDidMount() {\n const { leaflet, registerOverlay, visible } = this.props;\n this.setState({\n zoom: leaflet.map.getZoom()\n });\n if (visible) this.startRefreshing();\n if (typeof registerOverlay === \"function\") {\n registerOverlay(this);\n }\n }\n\n componentWillUnmount() {\n this.stopRefreshing();\n }\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 */\n renderPopupForStation = (station, stationIsHub = false) => {\n const { configCompanies, getStationName, intl, setLocation } = this.props;\n const getStationNameFunc =\n 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 <Popup>\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 </Popup>\n );\n };\n\n render() {\n const { companies, leaflet, mapSymbols, stations } = this.props;\n const { zoom = leaflet.map.getZoom() } = this.state;\n // Render an empty FeatureGroup if the rental vehicles should not be visible\n // on the map. Otherwise previous stations may still be shown due to some\n // react-leaflet internals, maybe? Also, do not return null because that will\n // prevent the overlay from appearing in the layer controls.\n\n let filteredStations = stations;\n if (companies) {\n filteredStations = stations.filter(\n station =>\n station.networks.filter(value => companies.includes(value)).length > 0\n );\n }\n\n if (!filteredStations || filteredStations.length === 0) {\n return <FeatureGroup />;\n }\n\n // Convert map symbols for this overlay to zoomBasedSymbolType.\n const symbols = this.convertToZoomMarkerSymbols(mapSymbols);\n\n return (\n <FeatureGroup>\n <ZoomBasedMarkers\n entities={filteredStations}\n symbols={symbols}\n symbolTransform={this.renderSymbolWithPopup}\n zoom={zoom}\n />\n </FeatureGroup>\n );\n }\n}\n\nVehicleRentalOverlay.props = {\n /**\n * The entire companies config array.\n */\n // configCompanies: PropTypes.arrayOf(coreUtils.types.companyType.isRequired)\n // .isRequired,\n /**\n * A list of companies that are applicable to just this instance of the\n * overlay.\n */\n companies: PropTypes.arrayOf(PropTypes.string.isRequired),\n /**\n * An optional custom function to create a string name of a particular vehicle\n * rental station. This function takes two arguments of the configCompanies\n * prop and a vehicle rental station. The function must return a string.\n */\n getStationName: PropTypes.func,\n /**\n * A configuration of what map markers or symbols to show at various\n * zoom levels.\n */\n // mapSymbols: coreUtils.types.vehicleRentalMapOverlaySymbolsType,\n /**\n * If specified, a function that will be triggered every 30 seconds whenever this layer is\n * visible.\n */\n refreshVehicles: PropTypes.func,\n /**\n * A callback for when a user clicks on setting this stop as either the from\n * or to location of a new search.\n *\n * This will be dispatched with the following argument:\n *\n * ```js\n * {\n * location: {\n * lat: number,\n * lon: number,\n * name: string\n * },\n * locationType: \"from\" or \"to\"\n * }\n * ```\n */\n setLocation: PropTypes.func.isRequired,\n /**\n * A list of the vehicle rental stations specific to this overlay instance.\n */\n // stations: PropTypes.arrayOf(coreUtils.types.stationType),\n /**\n * Whether the overlay is currently visible.\n */\n visible: PropTypes.bool\n};\n\nVehicleRentalOverlay.defaultProps = {\n getStationName: null,\n mapSymbols: [\n {\n zoom: 0,\n symbol: GenericMarker\n }\n ],\n refreshVehicles: null,\n stations: [],\n visible: false\n};\n\nexport default withLeaflet(injectIntl(VehicleRentalOverlay));\n"],"file":"index.js"}
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"names":["DETAILED_MARKER_CUTOFF","getColorForStation","v","isFloatingCar","isFloatingVehicle","bikesAvailable","undefined","isFloatingBike","checkIfPositionInViewport","bounds","lat","lng","PADDING","sw","ne","_sw","_ne","VehicleRentalOverlay","props","mainMap","zoom","getZoom","getBounds","configCompanies","companies","getStationName","id","refreshVehicles","setLocation","stations","visible","layerId","clickedVehicle","setClickedVehicle","setInterval","VEHICLE_LAYERS","forEach","stopLayer","on","getCanvas","style","cursor","event","features","properties","length","vehiclesGeoJSON","type","filter","vehicle","networks","includes","map","JSON","stringify","color","geometry","coordinates","x","y","station","location","spacesAvailable","parse"],"mappings":"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","sourcesContent":["import { Source, Layer, useMap, Popup } from \"react-map-gl\";\nimport { EventData } from \"mapbox-gl\";\nimport React, { useEffect, useState } from \"react\";\nimport {\n Company,\n Station,\n MapLocationActionArg,\n ConfiguredCompany\n} from \"@opentripplanner/types\";\nimport { MarkerWithPopup } from \"@opentripplanner/base-map\";\nimport StationPopup from \"./StationPopup\";\nimport { BaseBikeRentalIcon, StationMarker } from \"./styled\";\n\n// TODO: Make configurable?\nconst DETAILED_MARKER_CUTOFF = 16;\n\nconst getColorForStation = (v: Station) => {\n if (v.isFloatingCar) return \"#009cde\";\n if (v.isFloatingVehicle) return \"#f5a729\";\n // TODO: nicer color to match transitive\n if (v.bikesAvailable !== undefined || v.isFloatingBike) return \"#f00\";\n return \"gray\";\n};\n\nconst checkIfPositionInViewport = (\n bounds: mapboxgl.LngLatBounds,\n lat: number,\n lng: number\n): boolean => {\n const PADDING = 0.001;\n // @ts-expect-error types appear to be wrong? version issue?\n // eslint-disable-next-line no-underscore-dangle\n const [sw, ne] = [bounds._sw, bounds._ne];\n if (!sw || !ne) return false;\n\n return (\n lat >= sw.lat - PADDING &&\n lat <= ne.lat + PADDING &&\n lng >= sw.lng - PADDING &&\n lng <= ne.lng + PADDING\n );\n};\n\ntype Props = {\n /**\n * The entire companies config array.\n */\n configCompanies: ConfiguredCompany[];\n /**\n * A list of companies that are applicable to just this instance of the\n * overlay.\n */\n companies?: string[];\n /**\n * An id, used to make this layer uniquely identifiable\n */\n id: string;\n /**\n * An optional custom function to create a string name of a particular vehicle\n * rental station. This function takes two arguments of the configCompanies\n * prop and a vehicle rental station. The function must return a string.\n */\n getStationName?: (configCompanies: Company[], station: Station) => string;\n /**\n * If specified, a function that will be triggered every 30 seconds whenever this layer is\n * visible.\n */\n refreshVehicles?: () => void;\n /**\n * A callback for when a user clicks on setting this stop as either the from\n * or to location of a new search.\n *\n * This will be dispatched with the following argument:\n *\n * ```js\n * {\n * location: {\n * lat: number,\n * lon: number,\n * name: string\n * },\n * locationType: \"from\" or \"to\"\n * }\n * ```\n */\n setLocation?: (arg: MapLocationActionArg) => void;\n /**\n * A list of the vehicle rental stations specific to this overlay instance.\n */\n stations: Station[];\n /**\n * Whether the overlay is currently visible.\n */\n visible?: boolean;\n /**\n * TODO: Add props for overriding symbols?\n */\n};\n\n/**\n * This vehicle rental overlay can be used to render vehicle rentals of various\n * types. This layer can be configured to show different styles of markers at\n * different zoom levels.\n */\nconst VehicleRentalOverlay = (props: Props): JSX.Element => {\n const { mainMap } = useMap();\n const zoom = mainMap?.getZoom();\n const bounds = mainMap?.getBounds();\n\n const {\n configCompanies,\n companies,\n getStationName,\n id,\n refreshVehicles,\n setLocation,\n stations,\n visible\n } = props;\n const layerId = `rental-vehicles-${id}`;\n const [clickedVehicle, setClickedVehicle] = useState(null);\n\n useEffect(() => {\n // TODO: Make 30s configurable?\n if (!refreshVehicles || typeof refreshVehicles !== \"function\") {\n return;\n }\n\n refreshVehicles();\n setInterval(refreshVehicles, 30_000);\n }, [refreshVehicles]);\n\n useEffect(() => {\n const VEHICLE_LAYERS = [layerId];\n VEHICLE_LAYERS.forEach(stopLayer => {\n mainMap?.on(\"mouseenter\", stopLayer, () => {\n mainMap.getCanvas().style.cursor = \"pointer\";\n });\n mainMap?.on(\"mouseleave\", stopLayer, () => {\n mainMap.getCanvas().style.cursor = \"\";\n });\n mainMap?.on(\"click\", stopLayer, (event: EventData) => {\n setClickedVehicle(event.features?.[0].properties);\n });\n });\n }, [mainMap]);\n\n // Don't render if no map or no stops are defined.\n if (visible === false || !stations || stations.length === 0) {\n return <></>;\n }\n\n const vehiclesGeoJSON: GeoJSON.FeatureCollection = {\n type: \"FeatureCollection\",\n features: stations\n .filter(\n vehicle =>\n // Include specified companies only if companies is specified and network info is available\n !companies ||\n !vehicle.networks ||\n companies.includes(vehicle.networks[0])\n )\n .map(vehicle => ({\n type: \"Feature\",\n properties: {\n ...vehicle,\n networks: JSON.stringify(vehicle.networks),\n \"stroke-width\":\n vehicle.isFloatingBike || vehicle.isFloatingVehicle ? 1 : 2,\n color: getColorForStation(vehicle)\n },\n geometry: { type: \"Point\", coordinates: [vehicle.x, vehicle.y] }\n }))\n };\n\n return (\n <>\n {zoom < DETAILED_MARKER_CUTOFF && (\n <Source type=\"geojson\" data={vehiclesGeoJSON}>\n <Layer\n id={layerId}\n type=\"circle\"\n paint={{\n \"circle-color\": [\"get\", \"color\"],\n \"circle-opacity\": 0.9,\n \"circle-stroke-width\": [\"get\", \"stroke-width\"],\n \"circle-stroke-color\": \"#333\"\n }}\n />\n {/* this is where we add the symbols layer. add a second layer that gets swapped in and out dynamically */}\n </Source>\n )}\n {zoom >= DETAILED_MARKER_CUTOFF &&\n stations\n .filter(station =>\n checkIfPositionInViewport(bounds, station.y, station.x)\n )\n .map(station => (\n <MarkerWithPopup\n key={station.id}\n position={[station.y, station.x]}\n popupContents={\n <StationPopup\n configCompanies={configCompanies}\n setLocation={location => {\n setClickedVehicle(null);\n setLocation(location);\n }}\n getStationName={getStationName}\n station={station}\n />\n }\n >\n {station.bikesAvailable !== undefined &&\n !station.isFloatingBike &&\n !station.isFloatingVehicle &&\n station.spacesAvailable !== undefined ? (\n <BaseBikeRentalIcon\n percent={\n station?.bikesAvailable /\n (station?.bikesAvailable + station?.spacesAvailable)\n }\n />\n ) : (\n <StationMarker width={12} color={getColorForStation(station)} />\n )}\n </MarkerWithPopup>\n ))}\n {clickedVehicle && (\n <Popup\n onClose={() => {\n setClickedVehicle(null);\n }}\n longitude={clickedVehicle.x}\n latitude={clickedVehicle.y}\n maxWidth=\"100%\"\n >\n <StationPopup\n configCompanies={configCompanies}\n setLocation={location => {\n setClickedVehicle(null);\n setLocation(location);\n }}\n getStationName={getStationName}\n station={{\n ...clickedVehicle,\n networks: JSON.parse(clickedVehicle.networks)\n }}\n />\n </Popup>\n )}\n </>\n );\n};\nexport default VehicleRentalOverlay;\n"],"file":"index.js"}
|
package/lib/styled.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bike rental icons are different from other vehicle rental types since they
|
|
3
|
+
* typically have stations in addition to free-floating bikes. The stations are
|
|
4
|
+
* drawn as svgs marking how full the stations are while the floating bikes have
|
|
5
|
+
* their own unique icon.
|
|
6
|
+
*/
|
|
7
|
+
export declare const BaseBikeRentalIcon: import("styled-components").StyledComponent<"div", any, {
|
|
8
|
+
percent: number;
|
|
9
|
+
}, never>;
|
|
10
|
+
export declare const StationMarker: import("styled-components").StyledComponent<import("@styled-icons/styled-icon").StyledIcon, any, {}, never>;
|
|
11
|
+
//# sourceMappingURL=styled.d.ts.map
|