react-mapfilter
Version:
These components are designed for viewing data in Mapeo. They share a common interface:
288 lines (238 loc) • 11.6 kB
JavaScript
;
var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
require("core-js/modules/es.function.name");
require("core-js/modules/es.object.to-string");
require("core-js/modules/es.regexp.to-string");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _getIterator2 = _interopRequireDefault(require("@babel/runtime-corejs3/core-js/get-iterator"));
var _isArray = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/array/is-array"));
var _getIteratorMethod2 = _interopRequireDefault(require("@babel/runtime-corejs3/core-js/get-iterator-method"));
var _symbol = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/symbol"));
var _from = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/array/from"));
var _slice = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/slice"));
var _extends2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/extends"));
var _find = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/find"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/slicedToArray"));
var _react = _interopRequireWildcard(require("react"));
var _reactIntl = require("react-intl");
var _reactMapboxGl = _interopRequireDefault(require("react-mapbox-gl"));
var _mapboxGl = _interopRequireDefault(require("mapbox-gl"));
var _helpers = require("../utils/helpers");
var _styles = require("@material-ui/core/styles");
var _ObservationLayer = _interopRequireDefault(require("./ObservationLayer"));
var _Popup = _interopRequireDefault(require("./Popup"));
function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof _symbol.default === "undefined" || (0, _getIteratorMethod2.default)(o) == null) { if ((0, _isArray.default)(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = (0, _getIterator2.default)(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray(o, minLen) { var _context; if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = (0, _slice.default)(_context = Object.prototype.toString.call(o)).call(_context, 8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return (0, _from.default)(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
var useStyles = (0, _styles.makeStyles)({
container: {
flex: 1
},
'@global': {
// The "Improve Map" link does not work when Mapeo Desktop is used offline,
// and since the data the user is looking at is mainly data that is not in
// OpenStreetMap, this link does not make much sense to the user.
'.mapbox-improve-map': {
display: 'none'
}
}
});
var fitBoundsOptions = {
duration: 0,
padding: 10
};
var noop = function noop() {};
var MapViewContent = function MapViewContent(_ref, ref) {
var observations = _ref.observations,
mapboxAccessToken = _ref.mapboxAccessToken,
getPreset = _ref.getPreset,
getMedia = _ref.getMedia,
onClick = _ref.onClick,
_ref$initialMapPositi = _ref.initialMapPosition,
initialMapPosition = _ref$initialMapPositi === void 0 ? {} : _ref$initialMapPositi,
_ref$onMapMove = _ref.onMapMove,
onMapMove = _ref$onMapMove === void 0 ? noop : _ref$onMapMove,
_ref$mapStyle = _ref.mapStyle,
mapStyle = _ref$mapStyle === void 0 ? 'mapbox://styles/mapbox/outdoors-v10' : _ref$mapStyle,
_ref$print = _ref.print,
print = _ref$print === void 0 ? false : _ref$print;
var map = (0, _react.useRef)();
var classes = useStyles();
var intl = (0, _reactIntl.useIntl)();
var _useState = (0, _react.useState)(null),
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
hovered = _useState2[0],
setHovered = _useState2[1];
var _useState3 = (0, _react.useState)(false),
_useState4 = (0, _slicedToArray2.default)(_useState3, 2),
styleLoaded = _useState4[0],
setStyleLoaded = _useState4[1];
(0, _react.useImperativeHandle)(ref, function () {
return {
fitBounds: function fitBounds() {
if (!map.current) return;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
map.current.fitBounds.apply(map.current, args);
},
flyTo: function flyTo() {
if (!map.current) return;
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
map.current.flyTo.apply(map.current, args);
}
};
}); // We don't want to change the map viewport if the observations array changes,
// which it will do if the filter changes. We only set the bounds for the very
// initial render, and only if initialMapPosition zoom and center are not set.
var initialBounds = (0, _react.useMemo)(function () {
return initialMapPosition.center == null && initialMapPosition.zoom == null ? getBounds(observations) : undefined;
}, // eslint-disable-next-line react-hooks/exhaustive-deps
[]);
(0, _react.useEffect)(function () {
if (!map.current || !observations || !observations.length || map.current.__hasMoved || initialMapPosition.center != null && initialMapPosition.zoom != null) return;
map.current.__hasMoved = true;
var bounds = getBounds(observations);
map.current.flyTo({
center: [bounds[0][0] + (bounds[1][0] - bounds[0][0]) / 2, bounds[0][1] + (bounds[1][1] - bounds[0][1]) / 2],
zoom: 9,
bearing: 0,
pitch: 0
});
}, [initialMapPosition.center, initialMapPosition.zoom, observations, styleLoaded]); // We don't allow the map to be a controlled component - position can only be
// set when the map is initially mounted and after that state is internal
var position = (0, _react.useMemo)(function () {
var center = initialMapPosition.center,
zoom = initialMapPosition.zoom,
bearing = initialMapPosition.bearing,
pitch = initialMapPosition.pitch;
var bounds = getBounds(observations); // initialMapPosition overrides default behaviour of fitting the map to the
// bounds of the observations, but if any properties of initialMapPosition are
// we set some default values
return {
center: center || [bounds[0][0] + (bounds[1][0] - bounds[0][0]) / 2, bounds[0][1] + (bounds[1][1] - bounds[0][1]) / 2],
zoom: zoom ? [zoom] : [9],
bearing: bearing ? [bearing] : [0],
pitch: pitch ? [pitch] : [0]
}; // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
var Mapbox = (0, _react.useMemo)(function () {
return (0, _reactMapboxGl.default)({
accessToken: mapboxAccessToken,
dragRotate: false,
pitchWithRotate: false,
attributionControl: false,
logoPosition: 'bottom-right',
scrollZoom: !print,
injectCSS: false
});
}, [mapboxAccessToken, print]);
var handleStyleLoad = (0, _react.useCallback)(function (mapInstance) {
mapInstance.addControl(new _mapboxGl.default.NavigationControl({}));
mapInstance.addControl(new _mapboxGl.default.ScaleControl({}));
mapInstance.addControl(new _mapboxGl.default.AttributionControl({
compact: true
}));
map.current = mapInstance;
setStyleLoaded(true);
}, []);
var handleMouseMove = (0, _react.useCallback)(function (e) {
if (e.features.length === 0) return setHovered(null);
var obs = (0, _find.default)(observations).call(observations, function (obs) {
return obs.id === e.features[0].properties.id;
});
setHovered(obs);
}, [observations]);
var handleMouseLeave = (0, _react.useCallback)(function (e) {
setHovered(null);
}, []);
var handleMapMove = (0, _react.useCallback)(function (map, e) {
onMapMove({
center: map.getCenter().toArray(),
zoom: map.getZoom(),
bearing: map.getBearing(),
pitch: map.getPitch()
});
}, [onMapMove]);
function getLastImageUrl(observation
/*: Observation*/
)
/*: string | void*/
{
var lastImageAttachment = (0, _helpers.getLastImage)(observation);
if (!lastImageAttachment) return;
var media = getMedia(lastImageAttachment, {
width: _Popup.default.imageSize,
height: _Popup.default.imageSize
});
if (media) return media.src;
}
function getName(observation
/*: Observation*/
)
/*: string*/
{
var preset = getPreset(observation);
return preset && preset.name || 'Observation';
}
return /*#__PURE__*/_react.default.createElement(Mapbox, (0, _extends2.default)({
style: mapStyle,
className: classes.container,
fitBounds: initialBounds,
fitBoundsOptions: fitBoundsOptions,
onStyleLoad: handleStyleLoad,
onMove: handleMapMove
}, position), /*#__PURE__*/_react.default.createElement(_ObservationLayer.default, {
observations: observations,
onClick: onClick,
onMouseLeave: handleMouseLeave,
onMouseMove: handleMouseMove,
print: print
}), hovered && /*#__PURE__*/_react.default.createElement(_Popup.default, {
imageUrl: getLastImageUrl(hovered),
title: getName(hovered),
subtitle: intl.formatTime(hovered.created_at, {
year: 'numeric',
month: 'long',
day: '2-digit'
}),
coordinates: // $FlowFixMe - these are always non-nullish when on a map
[hovered.lon, hovered.lat]
}));
};
var _default = /*#__PURE__*/_react.default.forwardRef(MapViewContent);
exports.default = _default;
function getBounds(observations
/*: Observation[]*/
)
/*: [[number, number], [number, number]]*/
{
var extent = [[-180, -85], [180, 85]];
var _iterator = _createForOfIteratorHelper(observations),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var _step$value = _step.value,
lat = _step$value.lat,
lon = _step$value.lon;
if (lon == null || lat == null) continue;
if (extent[0][0] < lon) extent[0][0] = lon;
if (extent[0][1] < lat) extent[0][1] = lat;
if (extent[1][0] > lon) extent[1][0] = lon;
if (extent[1][1] > lat) extent[1][1] = lat;
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return extent;
}
//# sourceMappingURL=MapViewContent.js.map