@vis.gl/react-google-maps
Version:
React components and hooks for the Google Maps JavaScript API
418 lines (407 loc) • 16.3 kB
JavaScript
(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
* // ¢er=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