/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import {CanvasForm, CanvasSpace, Font, Group, Pt, Triangle} from 'pts'; import SelectedFrameHelper from './SelectedFrameHelper'; import {PADDING_BOTTOM, PADDING_TOP} from './VideoFilmstrip'; export function getPointerPosition( event: React.PointerEvent, ) { const rect = event.currentTarget.getBoundingClientRect(); return new Pt(event.clientX - rect.left, event.clientY - rect.top); } export function drawFilmstrip( filmstrip: ImageBitmap | null, space: CanvasSpace | undefined, form: CanvasForm | undefined, ) { if (filmstrip == null || space == undefined || form?.ctx == undefined) { return; } const ratio = filmstrip.width / (filmstrip.height + PADDING_TOP + PADDING_BOTTOM); form.image( [ [0, PADDING_TOP], [space.size.x, space.size.x / ratio], ], filmstrip, ); } export function getTimeFromFrame(frame: number, fps: number): string { const seconds = Math.floor(frame / fps); const frameRemaining = frame - fps * seconds; return `${seconds}:${frameRemaining.toFixed().toString().padStart(2, '0')}`; } export function drawMarker( space: CanvasSpace | undefined, form: CanvasForm | undefined, selectedFrameHelper: SelectedFrameHelper, pointerPosition: Pt | null, scanLabel: string | false, fps: number, ) { if (space == undefined || form?.ctx == undefined) { return; } const marker = Group.fromArray([ [0, PADDING_TOP], [0, space.height - PADDING_BOTTOM], ]); const currentMarker = marker .clone() .add(Math.max(5, selectedFrameHelper.position), 0); const getTextPosition = (label: string, marker: Group) => { const textWidth = form.ctx.measureText(label).width; return marker[0] .$subtract(textWidth / 2, 0) .$min(space.width - textWidth, PADDING_TOP - 10) .$max(textWidth / 2 - 2, 0); }; // draw current marker form .strokeOnly('#00000066', 5) .line(currentMarker) .strokeOnly('#fff', 1) .line(currentMarker) .fill('#000') .polygon( Triangle.fromCenter(currentMarker[0].$add(0, 10), 5).rotate2D(Math.PI), ); // draw text const frameLabel = getTimeFromFrame(selectedFrameHelper.index, fps); form .font(new Font(12, 'monospace')) .fillOnly('#fff') .text(getTextPosition(frameLabel, currentMarker), frameLabel); // draw scanning ghost marker if ( selectedFrameHelper.isScanning && pointerPosition != null && scanLabel != false ) { const scanMarker = marker.clone().add(pointerPosition.x, 0); form.strokeOnly('#ffffff66', 5).line(scanMarker); form .font(new Font(12, 'monospace')) .fillOnly('#8595A4') .text(getTextPosition(scanLabel, scanMarker), scanLabel); } }