From 2815a5275b7c371b3df97566ae0bc8fa08e3da41 Mon Sep 17 00:00:00 2001 From: Tim Nikischin <49103409+nikischin@users.noreply.github.com> Date: Sat, 27 Apr 2024 18:50:50 +0200 Subject: [PATCH] Implement custom callout (#55) * Implement draggable option * appearanceAnimation implemented with story * Implemented drag events * Implement size and padding * Fix padding and implement anchorOffset * First implementation of callouts * Working but ugly example without JSX * React 17 sample implementation * Minor Code modifications * Working implementation * Annotation implementation * Storybook examples * Apply suggestions from code review Co-authored-by: Nicolas Ettlin * Remove ForAnnotation from prop name * Minor adaptions from Review * Implement Annotation Storybook example * Implement display priority conversion * Remove extended callout descriptions --------- Co-authored-by: Nicolas Ettlin --- src/components/Annotation.tsx | 144 ++++++++++++++++++++++++++- src/components/AnnotationProps.tsx | 68 ++++++++++++- src/components/CalloutContainer.tsx | 15 +++ src/components/Marker.tsx | 148 +++++++++++++++++++++++++++- src/components/MarkerProps.tsx | 69 ++++++++++++- src/stories/Annotation.stories.tsx | 41 ++++++++ src/stories/Marker.stories.tsx | 99 ++++++++++++++++++- src/stories/stories.css | 73 ++++++++++++++ src/util/parameters.ts | 40 ++++++++ support.md | 33 ++++--- 10 files changed, 707 insertions(+), 23 deletions(-) create mode 100644 src/components/CalloutContainer.tsx diff --git a/src/components/Annotation.tsx b/src/components/Annotation.tsx index 3a606f6..d9db29f 100644 --- a/src/components/Annotation.tsx +++ b/src/components/Annotation.tsx @@ -1,13 +1,16 @@ -import { +import React, { useContext, useEffect, useState, useMemo, + useRef, } from 'react'; import { createPortal } from 'react-dom'; import MapContext from '../context/MapContext'; import AnnotationProps from './AnnotationProps'; import forwardMapkitEvent from '../util/forwardMapkitEvent'; +import CalloutContainer from './CalloutContainer'; +import { toMapKitDisplayPriority } from '../util/parameters'; export default function Annotation({ latitude, @@ -39,6 +42,18 @@ export default function Annotation({ visible = true, clusteringIdentifier = null, + displayPriority = undefined, + collisionMode = undefined, + + calloutElement = undefined, + calloutContent = undefined, + calloutLeftAccessory = undefined, + calloutRightAccessory = undefined, + + calloutEnabled = undefined, + calloutOffsetX = 0, + calloutOffsetY = 0, + draggable = false, enabled = true, @@ -76,6 +91,87 @@ export default function Annotation({ annotation.anchorOffset = new DOMPoint(anchorOffsetX, anchorOffsetY); }, [annotation, anchorOffsetX, anchorOffsetY]); + // CalloutOffset + useEffect(() => { + if (!annotation) return; + annotation.calloutOffset = new DOMPoint(calloutOffsetX, calloutOffsetY); + }, [annotation, calloutOffsetX, calloutOffsetY]); + + const calloutLeftAccessoryRef = useRef(null); + const calloutRightAccessoryRef = useRef(null); + const calloutContentRef = useRef(null); + const calloutElementRef = useRef(null); + + // Callout + useEffect(() => { + if (!annotation) return; + + const callOutObj: mapkit.AnnotationCalloutDelegate = {}; + if (calloutElement && calloutElementRef.current !== null) { + // @ts-expect-error + callOutObj.calloutElementForAnnotation = () => calloutElementRef.current; + } + if ( + calloutLeftAccessory + && calloutLeftAccessoryRef.current !== null + ) { + // @ts-expect-error + callOutObj.calloutLeftAccessoryForAnnotation = () => calloutLeftAccessoryRef + .current; + } + if ( + calloutRightAccessory + && calloutRightAccessoryRef.current !== null + ) { + // @ts-expect-error + callOutObj.calloutRightAccessoryForAnnotation = () => calloutRightAccessoryRef + .current; + } + if (calloutContent && calloutContentRef.current !== null) { + // @ts-expect-error + callOutObj.calloutContentForAnnotation = () => calloutContentRef.current; + } + if (Object.keys(callOutObj).length > 0) { + annotation.callout = callOutObj; + } else { + // @ts-expect-error + delete annotation.callout; + } + }, [ + annotation, + calloutElement, + calloutLeftAccessory, + calloutRightAccessory, + calloutContent, + calloutElementRef.current, + calloutLeftAccessoryRef.current, + calloutRightAccessoryRef.current, + calloutContentRef.current, + ]); + + // Collision Mode + useEffect(() => { + if (!annotation) return; + + if (collisionMode === 'Circle') { + annotation.collisionMode = mapkit.Annotation.CollisionMode.Circle; + } else if (collisionMode === 'Rectangle') { + annotation.collisionMode = mapkit.Annotation.CollisionMode.Rectangle; + } else { + // @ts-ignore + delete annotation.collisionMode; + } + }, [annotation, collisionMode]); + + // Display Priority + useEffect(() => { + if (!annotation) return; + // @ts-ignore + if (displayPriority === undefined) { delete annotation.displayPriority; return; } + // @ts-ignore + annotation.displayPriority = toMapKitDisplayPriority(displayPriority); + }, [annotation, displayPriority]); + // Simple values properties const properties = { title, @@ -90,7 +186,10 @@ export default function Annotation({ draggable, enabled, visible, + clusteringIdentifier, + + calloutEnabled, }; Object.entries(properties).forEach(([propertyName, prop]) => { useEffect(() => { @@ -124,5 +223,48 @@ export default function Annotation({ forwardMapkitEvent(annotation, 'drag-end', onDragEnd, dragEndParameters); forwardMapkitEvent(annotation, 'dragging', onDragging, draggingParameters); + if (calloutEnabled) { + return ( + <> + {calloutContent !== undefined && createPortal( + + {calloutContent} + , + document.body, + )} + {calloutLeftAccessory !== undefined && createPortal( + + {calloutLeftAccessory} + , + document.body, + )} + {calloutRightAccessory !== undefined && createPortal( + + {calloutRightAccessory} + , + document.body, + )} + {calloutElement !== undefined && createPortal( + + {calloutElement} + , + document.body, + )} + {createPortal(children, contentEl)} + + ); + } return createPortal(children, contentEl); } diff --git a/src/components/AnnotationProps.tsx b/src/components/AnnotationProps.tsx index ad30f8e..8aba63d 100644 --- a/src/components/AnnotationProps.tsx +++ b/src/components/AnnotationProps.tsx @@ -1,3 +1,4 @@ +import { ReactNode } from 'react'; import { Coordinate } from '../util/parameters'; export default interface AnnotationProps { @@ -142,5 +143,70 @@ export default interface AnnotationProps { * An annotation needs a clusteringIdentifier to be part of an annotation cluster. * @see {@link https://developer.apple.com/documentation/mapkitjs/mapkit/annotations/clustering_annotations} */ - clusteringIdentifier?: string | null + clusteringIdentifier?: string | null; + + /** + * A mode that determines the shape of the collision frame. + * Rectangle | Circle | None + * @see {@link https://developer.apple.com/documentation/mapkitjs/mapkit/annotation/2973822-collisionmode} + * @see {@link https://developer.apple.com/documentation/mapkitjs/mapkit/annotation/collisionmode} + */ + collisionMode?: 'Rectangle' | 'Circle' | null; + + /** + * A numeric hint that the map uses to prioritize how it displays annotations. + * + * Is either any number from `0` to `1000`, + * or a preset value: `"low"` (250), `"high"` (750), or `"required"` (1000). + * + * @see {@link https://developer.apple.com/documentation/mapkitjs/mapkit/annotation/2973825-displaypriority} + */ + displayPriority?: number | 'low' | 'high' | 'required'; + + /** + * An X offset that changes the annotation callout’s default placement. + * @see {@link https://developer.apple.com/documentation/mapkitjs/mapkit/annotation/2973821-calloutoffset} + */ + calloutOffsetX?: number; + + /** + * An Y offset that changes the annotation callout’s default placement. + * @see {@link https://developer.apple.com/documentation/mapkitjs/mapkit/annotation/2973821-calloutoffset} + */ + calloutOffsetY?: number; + + /** + * A Boolean value that determines whether the map shows an annotation’s callout. + * If the title is empty, the framework can’t show the standard callout even if property is true. + * @see {@link https://developer.apple.com/documentation/mapkitjs/mapkit/annotation/2973820-calloutenabled} + */ + calloutEnabled?: boolean; + + /** + * Returns an element to use as a custom accessory on the left side of the callout content area. + * + * @see {@link https://developer.apple.com/documentation/mapkitjs/annotationcalloutdelegate/2991150-calloutleftaccessoryforannotatio} + */ + calloutLeftAccessory?: ReactNode; + + /** + * Returns an element to use as a custom accessory on the right side of the callout content area. + * + * @see {@link https://developer.apple.com/documentation/mapkitjs/annotationcalloutdelegate/2991151-calloutrightaccessoryforannotati} + */ + calloutRightAccessory?: ReactNode; + + /** + * Returns custom content for the callout bubble. + * + * @see {@link https://developer.apple.com/documentation/mapkitjs/annotationcalloutdelegate/2991148-calloutcontentforannotation} + */ + calloutContent?: ReactNode; + + /** + * Returns an element representing a custom callout. + * + * @see {@link https://developer.apple.com/documentation/mapkitjs/annotationcalloutdelegate/2991148-calloutcontentforannotation} + */ + calloutElement?: ReactNode; } diff --git a/src/components/CalloutContainer.tsx b/src/components/CalloutContainer.tsx new file mode 100644 index 0000000..fd971b1 --- /dev/null +++ b/src/components/CalloutContainer.tsx @@ -0,0 +1,15 @@ +import React, { ReactNode } from 'react'; + +const CalloutContainer = React.forwardRef< + HTMLDivElement, + React.PropsWithChildren<{ children: ReactNode, type?: string }> +>(( + { children, type = 'container' }, + ref, +) => ( +
+ {children} +
+)); + +export default CalloutContainer; diff --git a/src/components/Marker.tsx b/src/components/Marker.tsx index 9a1de25..90135fb 100644 --- a/src/components/Marker.tsx +++ b/src/components/Marker.tsx @@ -1,8 +1,12 @@ -import { useContext, useEffect, useState } from 'react'; +import React, { + useContext, useEffect, useRef, useState, +} from 'react'; +import { createPortal } from 'react-dom'; import MapContext from '../context/MapContext'; -import { FeatureVisibility, toMapKitFeatureVisibility } from '../util/parameters'; +import { FeatureVisibility, toMapKitDisplayPriority, toMapKitFeatureVisibility } from '../util/parameters'; import MarkerProps from './MarkerProps'; import forwardMapkitEvent from '../util/forwardMapkitEvent'; +import CalloutContainer from './CalloutContainer'; export default function Marker({ latitude, @@ -13,10 +17,13 @@ export default function Marker({ accessibilityLabel = null, subtitleVisibility = FeatureVisibility.Adaptive, titleVisibility = FeatureVisibility.Adaptive, + clusteringIdentifier = null, + displayPriority = undefined, + collisionMode = undefined, + color = '#ff5b40', glyphColor = 'white', - glyphText = '', glyphImage = null, selectedGlyphImage = null, @@ -28,6 +35,15 @@ export default function Marker({ anchorOffsetX = 0, anchorOffsetY = 0, + calloutElement = undefined, + calloutContent = undefined, + calloutLeftAccessory = undefined, + calloutRightAccessory = undefined, + + calloutEnabled = undefined, + calloutOffsetX = 0, + calloutOffsetY = 0, + selected = false, animates = true, appearanceAnimation = '', @@ -82,6 +98,87 @@ export default function Marker({ marker.anchorOffset = new DOMPoint(anchorOffsetX, anchorOffsetY); }, [marker, anchorOffsetX, anchorOffsetY]); + // CalloutOffset + useEffect(() => { + if (!marker) return; + marker.calloutOffset = new DOMPoint(calloutOffsetX, calloutOffsetY); + }, [marker, calloutOffsetX, calloutOffsetY]); + + const calloutLeftAccessoryRef = useRef(null); + const calloutRightAccessoryRef = useRef(null); + const calloutContentRef = useRef(null); + const calloutElementRef = useRef(null); + + // Callout + useEffect(() => { + if (!marker) return; + + const callOutObj: mapkit.AnnotationCalloutDelegate = {}; + if (calloutElement && calloutElementRef.current !== null) { + // @ts-expect-error + callOutObj.calloutElementForAnnotation = () => calloutElementRef.current; + } + if ( + calloutLeftAccessory + && calloutLeftAccessoryRef.current !== null + ) { + // @ts-expect-error + callOutObj.calloutLeftAccessoryForAnnotation = () => calloutLeftAccessoryRef + .current; + } + if ( + calloutRightAccessory + && calloutRightAccessoryRef.current !== null + ) { + // @ts-expect-error + callOutObj.calloutRightAccessoryForAnnotation = () => calloutRightAccessoryRef + .current; + } + if (calloutContent && calloutContentRef.current !== null) { + // @ts-expect-error + callOutObj.calloutContentForAnnotation = () => calloutContentRef.current; + } + if (Object.keys(callOutObj).length > 0) { + marker.callout = callOutObj; + } else { + // @ts-expect-error + delete marker.callout; + } + }, [ + marker, + calloutElement, + calloutLeftAccessory, + calloutRightAccessory, + calloutContent, + calloutElementRef.current, + calloutLeftAccessoryRef.current, + calloutRightAccessoryRef.current, + calloutContentRef.current, + ]); + + // Collision Mode + useEffect(() => { + if (!marker) return; + + if (collisionMode === 'Circle') { + marker.collisionMode = mapkit.MarkerAnnotation.CollisionMode.Circle; + } else if (collisionMode === 'Rectangle') { + marker.collisionMode = mapkit.MarkerAnnotation.CollisionMode.Rectangle; + } else { + // @ts-ignore + delete marker.collisionMode; + } + }, [marker, collisionMode]); + + // Display Priority + useEffect(() => { + if (!marker) return; + // @ts-ignore + if (displayPriority === undefined) { delete marker.displayPriority; return; } + // @ts-ignore + marker.displayPriority = toMapKitDisplayPriority(displayPriority); + }, [marker, displayPriority]); + // Simple values properties const properties = { title, @@ -96,12 +193,15 @@ export default function Marker({ selectedGlyphImage, clusteringIdentifier, + selected, animates, appearanceAnimation, draggable, enabled, visible, + + calloutEnabled, }; Object.entries(properties).forEach(([propertyName, prop]) => { useEffect(() => { @@ -135,5 +235,47 @@ export default function Marker({ forwardMapkitEvent(marker, 'drag-end', onDragEnd, dragEndParameters); forwardMapkitEvent(marker, 'dragging', onDragging, draggingParameters); + if (calloutEnabled) { + return ( + <> + {calloutContent !== undefined && createPortal( + + {calloutContent} + , + document.body, + )} + {calloutLeftAccessory !== undefined && createPortal( + + {calloutLeftAccessory} + , + document.body, + )} + {calloutRightAccessory !== undefined && createPortal( + + {calloutRightAccessory} + , + document.body, + )} + {calloutElement !== undefined && createPortal( + + {calloutElement} + , + document.body, + )} + + ); + } return null; } diff --git a/src/components/MarkerProps.tsx b/src/components/MarkerProps.tsx index 0670b20..221f4f9 100644 --- a/src/components/MarkerProps.tsx +++ b/src/components/MarkerProps.tsx @@ -1,3 +1,4 @@ +import { ReactNode } from 'react'; import { Coordinate, FeatureVisibility } from '../util/parameters'; export default interface MarkerProps { @@ -173,5 +174,71 @@ export default interface MarkerProps { * An annotation needs a clusteringIdentifier to be part of an annotation cluster. * @see {@link https://developer.apple.com/documentation/mapkitjs/mapkit/annotations/clustering_annotations} */ - clusteringIdentifier?: string | null + clusteringIdentifier?: string | null; + + /** + * A mode that determines the shape of the collision frame. + * Rectangle | Circle | None + * @see {@link https://developer.apple.com/documentation/mapkitjs/mapkit/annotation/2973822-collisionmode} + * @see {@link https://developer.apple.com/documentation/mapkitjs/mapkit/annotation/collisionmode} + */ + collisionMode?: 'Rectangle' | 'Circle' | null; + + /** + * A numeric hint that the map uses to prioritize how it displays annotations. + * + * Is either any number from `0` to `1000`, + * or a preset value: `"low"` (250), `"high"` (750), or `"required"` (1000). + * + * @see {@link https://developer.apple.com/documentation/mapkitjs/mapkit/annotation/2973825-displaypriority} + */ + displayPriority?: number | 'low' | 'high' | 'required'; + + /** + * An X offset that changes the annotation callout’s default placement. + * @see {@link https://developer.apple.com/documentation/mapkitjs/mapkit/annotation/2973821-calloutoffset} + */ + calloutOffsetX?: number; + + /** + * An Y offset that changes the annotation callout’s default placement. + * @see {@link https://developer.apple.com/documentation/mapkitjs/mapkit/annotation/2973821-calloutoffset} + */ + calloutOffsetY?: number; + + /** + * A Boolean value that determines whether the map shows an annotation’s callout. + * If the title is empty, the framework can’t show the standard callout even if property is true. + * @see {@link https://developer.apple.com/documentation/mapkitjs/mapkit/annotation/2973820-calloutenabled} + */ + calloutEnabled?: boolean; + + /** + * Returns an element to use as a custom accessory on the left side of the callout content area. + * + * @see {@link https://developer.apple.com/documentation/mapkitjs/annotationcalloutdelegate/2991150-calloutleftaccessoryforannotatio} + */ + calloutLeftAccessory?: ReactNode; + + /** + * Returns an element to use as a custom accessory on the right side of the callout content area. + * + * @see {@link https://developer.apple.com/documentation/mapkitjs/annotationcalloutdelegate/2991151-calloutrightaccessoryforannotati} + */ + calloutRightAccessory?: ReactNode; + + /** + * Returns custom content for the callout bubble. + * + * @see {@link https://developer.apple.com/documentation/mapkitjs/annotationcalloutdelegate/2991148-calloutcontentforannotation} + */ + calloutContent?: ReactNode; + + /** + * Returns an element representing a custom callout. + * + * @see {@link https://developer.apple.com/documentation/mapkitjs/annotationcalloutdelegate/2991148-calloutcontentforannotation} + */ + calloutElement?: ReactNode; + } diff --git a/src/stories/Annotation.stories.tsx b/src/stories/Annotation.stories.tsx index 1366a8f..b3ff26d 100644 --- a/src/stories/Annotation.stories.tsx +++ b/src/stories/Annotation.stories.tsx @@ -129,3 +129,44 @@ export const AnimatedAnnotation = () => { }; AnimatedAnnotation.storyName = 'Animated Annotation'; + +function CustomCalloutElement( + { title, subtitle, url }: { title: string, subtitle: string, url: string }, +) { + return ( +
+

{title ?? ''}

+
+

{subtitle ?? ''}

+

Website

+
+
+ ); +} + +export const CustomAnnotationCallout = () => { + const initialRegion: CoordinateRegion = useMemo(() => ({ + centerLatitude: 46.20738751546706, + centerLongitude: 6.155891756231, + latitudeDelta: 0.007, + longitudeDelta: 0.015, + }), []); + + return ( + + } + calloutEnabled + calloutOffsetX={-148} + calloutOffsetY={-82} + > + + + + ); +}; +CustomAnnotationCallout.storyName = 'Annotation with custom callout element'; diff --git a/src/stories/Marker.stories.tsx b/src/stories/Marker.stories.tsx index 243b08b..f0cc760 100644 --- a/src/stories/Marker.stories.tsx +++ b/src/stories/Marker.stories.tsx @@ -1,6 +1,6 @@ import React, { useId, useMemo, useState } from 'react'; import { Meta, StoryFn } from '@storybook/react'; - +import './stories.css'; import Map from '../components/Map'; import Marker from '../components/Marker'; import { CoordinateRegion, FeatureVisibility } from '../util/parameters'; @@ -182,6 +182,8 @@ export const MarkerClustering = () => { onSelect={() => setSelected(index + 1)} onDeselect={() => setSelected(null)} clusteringIdentifier={clusteringIdentifier} + collisionMode="Circle" + displayPriority={750} /> )) } @@ -197,3 +199,98 @@ export const MarkerClustering = () => { }; MarkerClustering.storyName = 'Clustering three markers into one'; + +function CustomCalloutElement( + { title, subtitle, url }: { title: string, subtitle: string, url: string }, +) { + return ( +
+

{title ?? ''}

+
+

{subtitle ?? ''}

+

Website

+
+
+ ); +} + +export const CustomMarkerCallout = () => { + const initialRegion: CoordinateRegion = useMemo(() => ({ + centerLatitude: 46.20738751546706, + centerLongitude: 6.155891756231, + latitudeDelta: 0.007, + longitudeDelta: 0.015, + }), []); + + return ( + + } + calloutEnabled + calloutOffsetX={-148} + calloutOffsetY={-78} + /> + + ); +}; +CustomMarkerCallout.storyName = 'Marker with custom callout element'; + +function CustomCalloutContent({ title, subtitle }: { title: string, subtitle: string }) { + return ( +
+

{title ?? ''}

+

{subtitle ?? ''}

+
+ ); +} + +function CustomCalloutLeftAccessory({ src }: { src: string }) { + return ( +
+ +
+ ); +} + +function CustomCalloutRightAccessory({ url }: { url: string }) { + return ( + + ); +} + +export const CustomMarkerCalloutContent = () => { + const initialRegion: CoordinateRegion = useMemo(() => ({ + centerLatitude: 46.20738751546706, + centerLongitude: 6.155891756231, + latitudeDelta: 0.007, + longitudeDelta: 0.015, + }), []); + + return ( + + } + calloutLeftAccessory={} + calloutRightAccessory={} + calloutEnabled + /> + + ); +}; +CustomMarkerCalloutContent.storyName = 'Marker with custom callout content'; diff --git a/src/stories/stories.css b/src/stories/stories.css index 295415a..98feadd 100644 --- a/src/stories/stories.css +++ b/src/stories/stories.css @@ -105,6 +105,79 @@ body { vertical-align: middle; } +.landmark { + width: 250px; + padding: 7px 0 0 0; + background: rgba(247, 247, 247, 0.75); + border-radius: 5px; + box-shadow: 10px 10px 50px rgba(0, 0, 0, 0.29); + font-family: Helvetica, Arial, sans-serif; + transform-origin: 0 10px; +} + +.landmark h1 { + margin-top: 0; + padding: 5px 15px; + background: #2aaef5; + color: rgba(255, 255, 255, 0.9); + font-size: 16px; + font-weight: 300; +} + +.landmark section { + padding: 0 15px 5px; + font-size: 14px; +} + +.landmark section p { + margin: 5px 0; +} + +.landmark:after { + content: ""; + position: absolute; + top: 7px; + left: -13px; + width: 0; + height: 0; + margin-bottom: -13px; + border-right: 13px solid #2aaef5; + border-top: 13px solid rgba(0, 0, 0, 0); + border-bottom: 13px solid rgba(0, 0, 0, 0); +} + +.custom-annotation-image { + width: 40px; + height: 40px; +} + +.custom-annotation-image img { + width: 100%; + height: 100%; + border-radius: 8px; +} + +.custom-annotation-content { + display: flex; + flex-direction: column; + gap: 5px; +} + +.custom-annotation-content h2 { + font-size: 20px; + font-weight: 600; + margin: 0; +} + +.custom-annotation-content p { + margin: 0; + font-size: 12px; +} + +.custom-annotation-info { + padding: 10px; +} + /* Animation FROM https: //codepen.io/nelledejones/pen/gOOPWrK */ @keyframes gelatine { diff --git a/src/util/parameters.ts b/src/util/parameters.ts index d614966..fcad9d1 100644 --- a/src/util/parameters.ts +++ b/src/util/parameters.ts @@ -193,6 +193,46 @@ export function toMapKitLoadPriority(loadPriority: LoadPriority): string | null } } +/** + * A value MapKit JS uses for prioritizing the visibility of specific annotations. + * @see {@link https://developer.apple.com/documentation/mapkitjs/annotationconstructoroptions/2991165-displaypriority} + */ +export enum DisplayPriority { + Low = 'low', + High = 'high', + Required = 'required', +} + +/** + * Converts a mapkit-react display priority to a MapKit JS display priority. + * Must be called after MapKit JS is loaded. + * @param displayPriority The mapkit-react display priority or a number 0 to 1000 + * @returns The MapKit JS display priority + */ +export function toMapKitDisplayPriority(displayPriority: DisplayPriority | number): number | null { + if (typeof displayPriority === 'number') { + if (displayPriority < 0 || displayPriority > 1000) { + throw new RangeError('Display priority is out of range (0 to 1000)'); + } else { + return displayPriority; + } + } + + switch (displayPriority) { + case DisplayPriority.Low: + // @ts-ignore + return mapkit.Annotation.DisplayPriority.Low; + case DisplayPriority.High: + // @ts-ignore + return mapkit.Annotation.DisplayPriority.High; + case DisplayPriority.Required: + // @ts-ignore + return mapkit.Annotation.DisplayPriority.Required; + default: + throw new RangeError('Invalid display priority'); + } +} + /** * Constants indicating the visibility of different adaptive map features. * @see {@link https://developer.apple.com/documentation/mapkitjs/featurevisibility} diff --git a/support.md b/support.md index 6749f24..cfbc425 100644 --- a/support.md +++ b/support.md @@ -227,15 +227,15 @@ To call methods on the `mapkit.Map` object, you can use the reference exposed by | AnnotationConstructorOptions.visible | ✅ | | AnnotationConstructorOptions.enabled | ✅ | | AnnotationConstructorOptions.selected | ✅ | -| AnnotationConstructorOptions.calloutEnabled | ❌ | +| AnnotationConstructorOptions.calloutEnabled | ✅ | | AnnotationConstructorOptions.animates | ✅ | | AnnotationConstructorOptions.appearanceAnimation | ✅ | | AnnotationConstructorOptions.anchorOffset | ✅ | -| AnnotationConstructorOptions.calloutOffset | ❌ | -| AnnotationConstructorOptions.callout | ❌ | +| AnnotationConstructorOptions.calloutOffset | ✅ | +| AnnotationConstructorOptions.callout | ✅ | | AnnotationConstructorOptions.size | ✅ | -| AnnotationConstructorOptions.displayPriority | ❌ | -| AnnotationConstructorOptions.collisionMode | ❌ | +| AnnotationConstructorOptions.displayPriority | ✅ | +| AnnotationConstructorOptions.collisionMode | ✅ | | AnnotationConstructorOptions.padding | ✅ | | AnnotationConstructorOptions.clusteringIdentifier | ✅ | @@ -252,7 +252,7 @@ To call methods on the `mapkit.Map` object, you can use the reference exposed by | Feature | Supported | | ------------------ | --------- | -| data | ❌ | +| data | ✅ | | title | ✅ | | subtitle | ✅ | | accessibilityLabel | ✅ | @@ -264,7 +264,7 @@ To call methods on the `mapkit.Map` object, you can use the reference exposed by | coordinate | ✅ | | anchorOffset | ✅ | | appearanceAnimation | ✅ | -| displayPriority | ❌ | +| displayPriority | ✅ | | padding | ✅ | | size | ✅ | | visible | ✅ | @@ -282,9 +282,9 @@ To call methods on the `mapkit.Map` object, you can use the reference exposed by | Feature | Supported | | -------------- | --------- | -| callout | ❌ | -| calloutEnabled | ❌ | -| calloutOffset | ❌ | +| callout | ✅ | +| calloutEnabled | ✅ | +| calloutOffset | ✅ | #### Clustering @@ -292,7 +292,7 @@ To call methods on the `mapkit.Map` object, you can use the reference exposed by | -------------------- | --------- | | memberAnnotations | ❌ | | clusteringIdentifier | ✅ | -| collisionMode | ❌ | +| collisionMode | ✅ | ### Events @@ -329,14 +329,15 @@ _❌ Not currently supported by mapkit-react._ | MarkerAnnotationConstructorOptions.visible | ✅ | | MarkerAnnotationConstructorOptions.enabled | ✅ | | MarkerAnnotationConstructorOptions.selected | ✅ | -| MarkerAnnotationConstructorOptions.calloutEnabled | ❌ | +| MarkerAnnotationConstructorOptions.calloutEnabled | ✅ | | MarkerAnnotationConstructorOptions.animates | ✅ | | MarkerAnnotationConstructorOptions.appearanceAnimation | ✅ | | MarkerAnnotationConstructorOptions.anchorOffset | ✅ | -| MarkerAnnotationConstructorOptions.calloutOffset | ❌ | -| MarkerAnnotationConstructorOptions.callout | ❌ | -| MarkerAnnotationConstructorOptions.displayPriority | ❌ | -| MarkerAnnotationConstructorOptions.collisionMode | ❌ | +| MarkerAnnotationConstructorOptions.calloutOffset | ✅ | +| MarkerAnnotationConstructorOptions.callout | ✅ | +| MarkerAnnotationConstructorOptions.size | ❌ | +| MarkerAnnotationConstructorOptions.displayPriority | ✅ | +| MarkerAnnotationConstructorOptions.collisionMode | ✅ | | MarkerAnnotationConstructorOptions.padding | ✅ | | MarkerAnnotationConstructorOptions.clusteringIdentifier | ✅ |