UNPKG

@vis.gl/react-google-maps

Version:

React components and hooks for the Google Maps JavaScript API

418 lines (407 loc) 16.3 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) : typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) : (global = global || self, factory(global.reactGoogleMaps = {}, global.React)); })(this, (function (exports, React) { function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var React__default = /*#__PURE__*/_interopDefaultLegacy(React); 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 _createForOfIteratorHelperLoose(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (t) return (t = t.call(r)).next.bind(t); if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var o = 0; return function () { return o >= r.length ? { done: !0 } : { done: !1, value: r[o++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } 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; } } /** * Formats a location into a string representation suitable for Google Static Maps API. * * @param location - The location to format, can be either a string or an object with lat/lng properties * @returns A string representation of the location in the format "lat,lng" or the original string * * @example * // Returns "40.714728,-73.998672" * formatLocation({ lat: 40.714728, lng: -73.998672 }) * * @example * // Returns "New York, NY" * formatLocation("New York, NY") */ function formatLocation(location) { return typeof location === 'string' ? location : location.lat + "," + location.lng; } // Used for removing the leading pipe from the param string function formatParam(string) { return string.slice(1); } /** * Assembles marker parameters for static maps. * * This function takes an array of markers and groups them by their style properties. * It then creates a string representation of these markers, including their styles and locations, * which can be used as parameters for static map APIs. * * @param {StaticMapsMarker[]} [markers=[]] - An array of markers to be processed. Each marker can have properties such as color, label, size, scale, icon, anchor, and location. * @returns {string[]} An array of strings, each representing a group of markers with their styles and locations. * * @example * const markers = [ * { color: 'blue', label: 'A', size: 'mid', location: '40.714728,-73.998672' }, * { color: 'blue', label: 'B', size: 'mid', location: '40.714728,-73.998672' }, * { icon: 'http://example.com/icon.png', location: { lat: 40.714728, lng: -73.998672 } } * ]; * const params = assembleMarkerParams(markers); * // Params will be an array of strings representing the marker parameters * Example output: [ * "color:blue|label:A|size:mid|40.714728,-73.998672|40.714728,-73.998672", * "color:blue|label:B|size:mid|40.714728,-73.998672|40.714728,-73.998672", * "icon:http://example.com/icon.png|40.714728,-73.998672" * ] */ function assembleMarkerParams(markers) { var _markers; if (markers === void 0) { markers = []; } var markerParams = []; // Group markers by style var markersByStyle = (_markers = markers) == null ? void 0 : _markers.reduce(function (styles, marker) { var _marker$color = marker.color, color = _marker$color === void 0 ? 'red' : _marker$color, label = marker.label, size = marker.size, scale = marker.scale, icon = marker.icon, anchor = marker.anchor; // Create a unique style key based on either icon properties or standard marker properties var relevantProps = icon ? [icon, anchor, scale] : [color, label, size]; var key = relevantProps.filter(Boolean).join('-'); styles[key] = styles[key] || []; styles[key].push(marker); return styles; }, {}); Object.values(markersByStyle != null ? markersByStyle : {}).forEach(function (markers) { var markerParam = ''; var icon = markers[0].icon; // Create marker style from first marker in group since all markers share the same style. Object.entries(markers[0]).forEach(function (_ref) { var key = _ref[0], value = _ref[1]; // Determine which properties to include based on whether marker uses custom icon var relevantKeys = icon ? ['icon', 'anchor', 'scale'] : ['color', 'label', 'size']; if (relevantKeys.includes(key)) { markerParam += "|" + key + ":" + value; } }); // Add location coordinates for each marker in the style group // Handles both string locations and lat/lng object formats. for (var _iterator = _createForOfIteratorHelperLoose(markers), _step; !(_step = _iterator()).done;) { var marker = _step.value; var location = typeof marker.location === 'string' ? marker.location : marker.location.lat + "," + marker.location.lng; markerParam += "|" + location; } markerParams.push(markerParam); }); return markerParams.map(formatParam); } // Style properties that can be applied to paths in the Static Maps API var PATH_STYLE_KEYS = ['color', 'weight', 'fillcolor', 'geodesic']; /** * Builds the style portion of a path parameter string. * @param path - The path object containing style properties * @returns A string with style parameters in the format "|key:value" */ function buildStyleParams(path) { var styleParams = ''; PATH_STYLE_KEYS.forEach(function (key) { if (path[key] !== undefined) { styleParams += "|" + key + ":" + path[key]; } }); return styleParams; } /** * Builds the coordinates portion of a path parameter string. * @param coordinates - Either a string or array of location objects * @returns A string with coordinates in the format "|lat,lng|lat,lng" */ function buildCoordinateParams(coordinates) { if (typeof coordinates === 'string') { return "|" + decodeURIComponent(coordinates); } return coordinates.map(function (location) { return "|" + formatLocation(location); }).join(''); } /** * Assembles path parameters for the Static Maps API from an array of paths. * * This function constructs a string of path parameters for each path. Each path parameter string * includes the style properties and the coordinates of the paths. * * @param {Array<StaticMapsPath>} [paths=[]] - An array of paths to be assembled into path parameters. * @returns {Array<string>} An array of path parameter strings. * * @example * ```typescript * const paths = [ * { * color: 'red', * weight: 5, * coordinates: [ * { lat: 40.714728, lng: -73.998672 }, * { lat: 40.718217, lng: -73.998284 } * ] * } * ]; * * const pathParams = assemblePathParams(paths); * // Output: ['color:red|weight:5|40.714728,-73.998672|40.718217,-73.998284'] * ``` */ function assemblePathParams(paths) { if (paths === void 0) { paths = []; } return paths.map(function (path) { var styleParams = buildStyleParams(path); var coordinateParams = buildCoordinateParams(path.coordinates); var pathParam = styleParams + coordinateParams; return formatParam(pathParam); }); } /** * Converts an array of Google Maps style objects into an array of style strings * compatible with the Google Static Maps API. * * @param styles - An array of Google Maps MapTypeStyle objects that define the styling rules * @returns An array of formatted style strings ready to be used with the Static Maps API * * @example * const styles = [{ * featureType: "road", * elementType: "geometry", * stylers: [{color: "#ff0000"}, {weight: 1}] * }]; * * const styleStrings = assembleMapTypeStyles(styles); * // Returns: ["|feature:road|element:geometry|color:0xff0000|weight:1"] * * Each style string follows the format: * "feature:{featureType}|element:{elementType}|{stylerName}:{stylerValue}" * * Note: Color values with hexadecimal notation (#) are automatically converted * to the required 0x format for the Static Maps API. */ function assembleMapTypeStyles(styles) { return styles.map(function (mapTypeStyle) { var featureType = mapTypeStyle.featureType, elementType = mapTypeStyle.elementType, _mapTypeStyle$stylers = mapTypeStyle.stylers, stylers = _mapTypeStyle$stylers === void 0 ? [] : _mapTypeStyle$stylers; var styleString = ''; if (featureType) { styleString += "|feature:" + featureType; } if (elementType) { styleString += "|element:" + elementType; } for (var _iterator = _createForOfIteratorHelperLoose(stylers), _step; !(_step = _iterator()).done;) { var styler = _step.value; Object.entries(styler).forEach(function (_ref) { var name = _ref[0], value = _ref[1]; styleString += "|" + name + ":" + String(value).replace('#', '0x'); }); } return styleString; }).map(formatParam); } var STATIC_MAPS_BASE = 'https://maps.googleapis.com/maps/api/staticmap'; /** * Creates a URL for the Google Static Maps API with the specified parameters. * * @param {Object} options - The configuration options for the static map * @param {string} options.apiKey - Your Google Maps API key (required) * @param {number} options.width - The width of the map image in pixels (required) * @param {number} options.height - The height of the map image in pixels (required) * @param {StaticMapsLocation} [options.center] - The center point of the map (lat/lng or address). * Required if no markers or paths or "visible locations" are provided. * @param {number} [options.zoom] - The zoom level of the map. Required if no markers or paths or "visible locations" are provided. * @param {1|2|4} [options.scale] - The resolution of the map (1, 2, or 4) * @param {string} [options.format] - The image format (png, png8, png32, gif, jpg, jpg-baseline) * @param {string} [options.mapType] - The type of map (roadmap, satellite, terrain, hybrid) * @param {string} [options.language] - The language of the map labels * @param {string} [options.region] - The region code for the map * @param {string} [options.map_id] - The Cloud-based map style ID * @param {StaticMapsMarker[]} [options.markers=[]] - Array of markers to display on the map * @param {StaticMapsPath[]} [options.paths=[]] - Array of paths to display on the map * @param {StaticMapsLocation[]} [options.visible=[]] - Array of locations that should be visible on the map * @param {MapTypeStyle[]} [options.style=[]] - Array of style objects to customize the map appearance * * @returns {string} The complete Google Static Maps API URL * * @throws {Error} If API key is not provided * @throws {Error} If width or height is not provided * * @example * const url = createStaticMapsUrl({ * apiKey: 'YOUR_API_KEY', * width: 600, * height: 400, * center: { lat: 40.714728, lng: -73.998672 }, * zoom: 12, * markers: [ * { * location: { lat: 40.714728, lng: -73.998672 }, * color: 'red', * label: 'A' * } * ], * paths: [ * { * coordinates: [ * { lat: 40.714728, lng: -73.998672 }, * { lat: 40.719728, lng: -73.991672 } * ], * color: '0x0000ff', * weight: 5 * } * ], * style: [ * { * featureType: 'road', * elementType: 'geometry', * stylers: [{color: '#00ff00'}] * } * ] * }); * * // Results in URL similar to: * // https://maps.googleapis.com/maps/api/staticmap?key=YOUR_API_KEY * // &size=600x400 * // &center=40.714728,-73.998672&zoom=12 * // &markers=color:red|label:A|40.714728,-73.998672 * // &path=color:0x0000ff|weight:5|40.714728,-73.998672|40.719728,-73.991672 * // &style=feature:road|element:geometry|color:0x00ff00 */ function createStaticMapsUrl(_ref) { var apiKey = _ref.apiKey, width = _ref.width, height = _ref.height, center = _ref.center, zoom = _ref.zoom, scale = _ref.scale, format = _ref.format, mapType = _ref.mapType, language = _ref.language, region = _ref.region, mapId = _ref.mapId, _ref$markers = _ref.markers, markers = _ref$markers === void 0 ? [] : _ref$markers, _ref$paths = _ref.paths, paths = _ref$paths === void 0 ? [] : _ref$paths, _ref$visible = _ref.visible, visible = _ref$visible === void 0 ? [] : _ref$visible, _ref$style = _ref.style, style = _ref$style === void 0 ? [] : _ref$style; if (!apiKey) { console.warn('API key is required'); } if (!width || !height) { console.warn('Width and height are required'); } var params = _extends({ key: apiKey, size: width + "x" + height }, center && { center: formatLocation(center) }, zoom && { zoom: zoom }, scale && { scale: scale }, format && { format: format }, mapType && { maptype: mapType }, language && { language: language }, region && { region: region }, mapId && { map_id: mapId }); var url = new URL(STATIC_MAPS_BASE); // Params that don't need special handling Object.entries(params).forEach(function (_ref2) { var key = _ref2[0], value = _ref2[1]; url.searchParams.append(key, String(value)); }); // Assemble Markers for (var _iterator = _createForOfIteratorHelperLoose(assembleMarkerParams(markers)), _step; !(_step = _iterator()).done;) { var markerParam = _step.value; url.searchParams.append('markers', markerParam); } // Assemble Paths for (var _iterator2 = _createForOfIteratorHelperLoose(assemblePathParams(paths)), _step2; !(_step2 = _iterator2()).done;) { var pathParam = _step2.value; url.searchParams.append('path', pathParam); } // Assemble visible locations if (visible.length) { url.searchParams.append('visible', visible.map(function (location) { return formatLocation(location); }).join('|')); } // Assemble Map Type Styles for (var _iterator3 = _createForOfIteratorHelperLoose(assembleMapTypeStyles(style)), _step3; !(_step3 = _iterator3()).done;) { var styleString = _step3.value; url.searchParams.append('style', styleString); } return url.toString(); } var StaticMap = function StaticMap(props) { var url = props.url, className = props.className; if (!url) throw new Error('URL is required'); return /*#__PURE__*/React__default["default"].createElement("img", { className: className, src: url, width: "100%" }); }; exports.StaticMap = StaticMap; exports.createStaticMapsUrl = createStaticMapsUrl; })); //# sourceMappingURL=index.umd.js.map