UNPKG

@vis.gl/react-google-maps

Version:

React components and hooks for the Google Maps JavaScript API

360 lines (351 loc) 12.1 kB
import React from 'react'; 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); } /** * 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 = []) { const markerParams = []; // Group markers by style const markersByStyle = markers == null ? void 0 : markers.reduce((styles, marker) => { const { color = 'red', label, size, scale, icon, anchor } = marker; // Create a unique style key based on either icon properties or standard marker properties const relevantProps = icon ? [icon, anchor, scale] : [color, label, size]; const key = relevantProps.filter(Boolean).join('-'); styles[key] = styles[key] || []; styles[key].push(marker); return styles; }, {}); Object.values(markersByStyle != null ? markersByStyle : {}).forEach(markers => { let markerParam = ''; const { icon } = markers[0]; // Create marker style from first marker in group since all markers share the same style. Object.entries(markers[0]).forEach(([key, value]) => { // Determine which properties to include based on whether marker uses custom icon const 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 (const marker of markers) { const 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 const 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) { let styleParams = ''; PATH_STYLE_KEYS.forEach(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(location => `|${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 = []) { return paths.map(path => { const styleParams = buildStyleParams(path); const coordinateParams = buildCoordinateParams(path.coordinates); const 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(mapTypeStyle => { const { featureType, elementType, stylers = [] } = mapTypeStyle; let styleString = ''; if (featureType) { styleString += `|feature:${featureType}`; } if (elementType) { styleString += `|element:${elementType}`; } for (const styler of stylers) { Object.entries(styler).forEach(([name, value]) => { styleString += `|${name}:${String(value).replace('#', '0x')}`; }); } return styleString; }).map(formatParam); } const 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({ apiKey, width, height, center, zoom, scale, format, mapType, language, region, mapId, markers = [], paths = [], visible = [], style = [] }) { if (!apiKey) { console.warn('API key is required'); } if (!width || !height) { console.warn('Width and height are required'); } const params = _extends({ key: apiKey, size: `${width}x${height}` }, center && { center: formatLocation(center) }, zoom && { zoom }, scale && { scale }, format && { format }, mapType && { maptype: mapType }, language && { language }, region && { region }, mapId && { map_id: mapId }); const url = new URL(STATIC_MAPS_BASE); // Params that don't need special handling Object.entries(params).forEach(([key, value]) => { url.searchParams.append(key, String(value)); }); // Assemble Markers for (const markerParam of assembleMarkerParams(markers)) { url.searchParams.append('markers', markerParam); } // Assemble Paths for (const pathParam of assemblePathParams(paths)) { url.searchParams.append('path', pathParam); } // Assemble visible locations if (visible.length) { url.searchParams.append('visible', visible.map(location => formatLocation(location)).join('|')); } // Assemble Map Type Styles for (const styleString of assembleMapTypeStyles(style)) { url.searchParams.append('style', styleString); } return url.toString(); } const StaticMap = props => { const { url, className } = props; if (!url) throw new Error('URL is required'); return /*#__PURE__*/React.createElement("img", { className: className, src: url, width: "100%" }); }; export { StaticMap, createStaticMapsUrl }; //# sourceMappingURL=index.modern.mjs.map