65 lines
1.6 KiB
TypeScript
65 lines
1.6 KiB
TypeScript
import React from 'react';
|
|||
|
|
import type { Rect } from '../lib/coordinateMapping';
|
||
|
|
|
||
|
|
export interface Annotation {
|
||
|
|
id: string;
|
||
|
|
type: 'highlight' | 'signature' | 'strikeout' | 'comment';
|
||
|
|
bbox: Rect;
|
||
|
|
color?: string;
|
||
|
|
author: string;
|
||
|
|
content?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
interface AnnotationLayerProps {
|
||
|
|
pageIndex: number;
|
||
|
|
width: number;
|
||
|
|
height: number;
|
||
|
|
zoom: number;
|
||
|
|
annotations: Annotation[];
|
||
|
|
onAnnotationClick?: (annotation: Annotation) => void;
|
||
|
|
}
|
||
|
|
|
||
|
|
export const AnnotationLayer: React.FC<AnnotationLayerProps> = ({
|
||
|
|
width,
|
||
|
|
height,
|
||
|
|
zoom,
|
||
|
|
annotations,
|
||
|
|
onAnnotationClick,
|
||
|
|
}) => {
|
||
|
|
return (
|
||
|
|
<div
|
||
|
|
className="annotation-layer"
|
||
|
|
style={{ width: `${width}px`, height: `${height}px` }}
|
||
|
|
>
|
||
|
|
{annotations
|
||
|
|
.filter((anno) => anno.type === 'highlight' || anno.type === 'comment')
|
||
|
|
.map((anno) => {
|
||
|
|
const scaledBbox = {
|
||
|
|
x: anno.bbox.x * zoom,
|
||
|
|
y: anno.bbox.y * zoom,
|
||
|
|
width: anno.bbox.width * zoom,
|
||
|
|
height: anno.bbox.height * zoom,
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div
|
||
|
|
key={anno.id}
|
||
|
|
onClick={(e) => {
|
||
|
|
e.stopPropagation();
|
||
|
|
onAnnotationClick?.(anno);
|
||
|
|
}}
|
||
|
|
className={`highlight-box type-${anno.type}`}
|
||
|
|
style={{
|
||
|
|
left: `${scaledBbox.x}px`,
|
||
|
|
top: `${scaledBbox.y}px`,
|
||
|
|
width: `${scaledBbox.width}px`,
|
||
|
|
height: `${scaledBbox.height}px`,
|
||
|
|
}}
|
||
|
|
title={`${anno.author}: ${anno.content || ''}`}
|
||
|
|
/>
|
||
|
|
);
|
||
|
|
})}
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
};
|