You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
leaflet-components/src/elements/leaflet-video-overlay.ts

84 lines
2.6 KiB
TypeScript

import {
VideoOverlay,
type CrossOrigin,
type LatLngBoundsExpression,
type VideoOverlayOptions,
} from 'leaflet';
import {
bool,
choice,
json,
num,
positional,
str,
type PropDef,
type Positional,
} from '../core/props.ts';
import { getBounds, urlProp, type Sourced } from '../core/shared-props.ts';
import {
WithProps,
type LeafletAddEventListener,
type LeafletElementConstructor,
type LeafletRemoveEventListener,
} from '../core/with-props.ts';
import type { PathEvents } from '../core/event-types.ts';
// Playback options live on the <video> element Leaflet builds, so live updates
// go there rather than through a Leaflet setter.
function media(
key: 'loop' | 'autoplay' | 'muted' | 'playsInline',
): (obj: VideoOverlay, value: boolean) => void {
return (obj, value) => {
const el = obj.getElement();
if (el) el[key] = value;
};
}
const PROPS: {
url: Positional<string, Sourced>;
bounds: Positional<LatLngBoundsExpression, VideoOverlay>;
opacity: PropDef<number>;
alt: PropDef<string>;
interactive: PropDef<boolean>;
crossOrigin: PropDef<CrossOrigin>;
loop: PropDef<boolean, VideoOverlay>;
autoplay: PropDef<boolean, VideoOverlay>;
muted: PropDef<boolean, VideoOverlay>;
playsInline: PropDef<boolean, VideoOverlay>;
zIndex: PropDef<number>;
className: PropDef<string>;
keepAspectRatio: PropDef<boolean>;
errorOverlayUrl: PropDef<string>;
} = {
url: urlProp,
bounds: positional(json<LatLngBoundsExpression, VideoOverlay>([], { get: getBounds })),
opacity: num(1.0),
alt: str(),
interactive: bool(),
crossOrigin: choice<CrossOrigin>(''),
loop: bool(false, { set: media('loop') }),
autoplay: bool(false, { set: media('autoplay') }),
muted: bool(false, { set: media('muted') }),
playsInline: bool(false, { attribute: 'playsinline', set: media('playsInline') }),
zIndex: num(),
className: str(),
keepAspectRatio: bool(true),
errorOverlayUrl: str(),
};
const Base: LeafletElementConstructor<VideoOverlay, typeof PROPS> = WithProps(PROPS);
/** `<leaflet-video-overlay>` — a Leaflet `VideoOverlay` (a video pinned to geographic `bounds`). `loop` / `autoplay` / `muted` / `playsinline` map to the `<video>`. */
export default class LeafletVideoOverlayElement extends Base {
declare readonly leafletObject?: VideoOverlay;
declare addEventListener: LeafletAddEventListener<PathEvents>;
declare removeEventListener: LeafletRemoveEventListener<PathEvents>;
createLeafletObject(options: VideoOverlayOptions): VideoOverlay {
return new VideoOverlay(this.url, this.bounds, options);
}
getElement(): HTMLVideoElement | undefined {
return this.leafletObject?.getElement();
}
}