Skip to content

Commit

Permalink
Merge 44f0e4a into 8422231
Browse files Browse the repository at this point in the history
  • Loading branch information
yen-tt committed Nov 15, 2022
2 parents 8422231 + 44f0e4a commit 9a87c80
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 72 deletions.
37 changes: 26 additions & 11 deletions src/components/MapboxMap.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useRef, useEffect } from 'react';
import { useRef, useEffect, useMemo } from 'react';
import mapboxgl, { Map, Marker, MapboxOptions, LngLatBounds, MarkerOptions, LngLat } from 'mapbox-gl';
import { Result, useSearchState } from '@yext/search-headless-react';
import { useDebouncedFunction } from '../hooks/useDebouncedFunction';
import ReactDOM from 'react-dom';
import { MapboxStaticImage } from './MapboxStaticImage';

/**
* A functional component that can be used to render a custom marker on the map.
Expand Down Expand Up @@ -103,25 +104,33 @@ export function MapboxMap<T>({
const locationResults = useSearchState(state => state.vertical.results) as Result<T>[];
const onDragDebounced = useDebouncedFunction(onDrag, 100);

const options: Omit<MapboxOptions, 'container'> = useMemo(() => {
return {
style: 'mapbox://styles/mapbox/streets-v11?optimize=true',
center: [-74.005371, 40.741611],
zoom: 9,
...mapboxOptions
};
}, [mapboxOptions]);

useEffect(() => {
if (mapContainer.current && !map.current) {
const options: MapboxOptions = {
const mapbox = new Map({
container: mapContainer.current,
style: 'mapbox://styles/mapbox/streets-v11',
center: [-74.005371, 40.741611],
zoom: 9,
...mapboxOptions
};
map.current = new Map(options);
const mapbox = map.current;
...options
});
map.current = mapbox;
mapbox.resize();
if (onDragDebounced) {
mapbox.on('drag', () => {
onDragDebounced(mapbox.getCenter(), mapbox.getBounds());
});
}
mapbox.on('load', () => {
mapbox.getContainer().style.visibility = 'visible';
});
}
}, [mapboxOptions, onDragDebounced]);
}, [options, onDragDebounced]);

useEffect(() => {
markers.current.forEach(marker => marker.remove());
Expand Down Expand Up @@ -161,7 +170,13 @@ export function MapboxMap<T>({
}, [PinComponent, getCoordinate, locationResults]);

return (
<div ref={mapContainer} className='h-full w-full' />
<div className='grid h-full w-full'>
<div ref={mapContainer} className="col-span-full row-span-full invisible"/>
<MapboxStaticImage
mapboxAccessToken={mapboxAccessToken}
mapboxOptions={options}
/>
</div>
);
}

Expand Down
81 changes: 81 additions & 0 deletions src/components/MapboxStaticImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { CSSProperties, useMemo, useRef, useState } from 'react';
import { MapboxOptions, LngLatLike } from 'mapbox-gl';
import useLayoutEffect from 'use-isomorphic-layout-effect';

/**
* Props for {@link MapboxStaticImage}
*/
export interface MapboxStaticImageProps {
/** Mapbox access token. */
mapboxAccessToken: string,
/** Map customization for Mapbox static image. */
mapboxOptions: Pick<MapboxOptions, 'center' | 'zoom' | 'style'>
}

/**
* Renders a static map image using Mapbox Static Image API
*
* @internal
*/
export function MapboxStaticImage({
mapboxAccessToken,
mapboxOptions
}: MapboxStaticImageProps): JSX.Element | null {
const mapContainer = useRef<HTMLDivElement>(null);
const [divDimension, setDivDimension] = useState<{ width: number, height: number }>();
useLayoutEffect(() => {
if (mapContainer.current) {
setDivDimension({
width: mapContainer.current.clientWidth,
height: mapContainer.current.clientHeight
});
}
}, []);

const staticMapboxStyle: CSSProperties | undefined = useMemo(() => {
const { style, center, zoom } = mapboxOptions;
if (!divDimension || !center || !zoom || typeof style !== 'string') {
return undefined;
}
const { width, height } = divDimension;
const url = getMapboxStaticImageUrl({ mapboxAccessToken, style, center, zoom, width, height });
if (!url) {
return undefined;
}
return {
backgroundImage: `url(${url})`
};
}, [divDimension, mapboxAccessToken, mapboxOptions]);

return <div ref={mapContainer} className='col-span-full row-span-full' style={staticMapboxStyle}/>;
}

/**
* The configuration for Mapbox Static Image API url
*/
interface MapboxStaticImageUrlConfig {
/** Mapbox access token. */
mapboxAccessToken: string,
/** Mapbox stylesheet url to apply to the static map. */
style: string,
/** Center point of the static map. */
center: LngLatLike,
/** Zoom level of the static map. */
zoom: number,
/** Width (in pixels) of the image. */
width: number,
/** Height (in pixels) of the image. */
height: number
}

function getMapboxStaticImageUrl(urlConfig: MapboxStaticImageUrlConfig): string | undefined {
const { mapboxAccessToken, style, center, zoom, width, height } = urlConfig;
// Mapbox Static Image API only support width and height between 1-1280 pixels.
if (width > 1280 || height > 1280) {
return undefined;
}
const stylesheet = style.split('mapbox://styles/')[1].split('?')[0];
const centerAndZoom = `${center[0]},${center[1]},${zoom}`;
const dimension = `${width}x${height}`;
return `https://api.mapbox.com/styles/v1/${stylesheet}/static/${centerAndZoom}/${dimension}?access_token=${mapboxAccessToken}`;
}
104 changes: 46 additions & 58 deletions test-site/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 9a87c80

Please sign in to comment.