Skip to content
Snippets Groups Projects
Verified Commit 7af2d10f authored by Loïs Poujade's avatar Loïs Poujade
Browse files

Sync drawing canvas size to annotation canvas

parent 46b5896a
No related branches found
No related tags found
No related merge requests found
import React, { Component } from 'react'; import React, { Component } from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ResizeObserver from 'react-resize-observer';
import { OSDReferences } from 'mirador/dist/es/src/plugins/OSDReferences'; import { OSDReferences } from 'mirador/dist/es/src/plugins/OSDReferences';
import { VideoViewersReferences } from 'mirador/dist/es/src/plugins/VideoViewersReferences'; import { VideosReferences } from 'mirador/dist/es/src/plugins/VideosReferences';
import { renderWithPaperScope, PaperContainer } from '@psychobolt/react-paperjs'; import { renderWithPaperScope, PaperContainer } from '@psychobolt/react-paperjs';
import import
{ {
...@@ -17,27 +18,83 @@ import flatten from 'lodash/flatten'; ...@@ -17,27 +18,83 @@ import flatten from 'lodash/flatten';
import EditTool from './EditTool'; import EditTool from './EditTool';
import { mapChildren } from './utils'; import { mapChildren } from './utils';
/** Use a canvas "like a OSD viewport" (temporary) */ /** Create a portal with a drawing canvas and a form to fill annotations details */
function viewportFromAnnotationOverlayVideo(annotationOverlayVideo) {
const { canvas } = annotationOverlayVideo;
return {
getCenter: () => ({ x: canvas.getWidth() / 2, y: canvas.getHeight() / 2 }),
getFlip: () => false,
getRotation: () => false,
getZoom: () => 1,
};
}
/** */
class AnnotationDrawing extends Component { class AnnotationDrawing extends Component {
/** */ /** */
constructor(props) { constructor(props) {
super(props); super(props);
this.paper = null;
this.getDisplayProps = this.getDisplayProps.bind(this);
this.onPaperResize = this.onPaperResize.bind(this);
this.paperDidMount = this.paperDidMount.bind(this);
this.addPath = this.addPath.bind(this); this.addPath = this.addPath.bind(this);
} }
/** */ /** Sync drawing canvas on componentDidMount */
componentDidMount() {
this.onPaperResize();
}
/** Sync drawing canvas on componentDidUpdate */
componentDidUpdate() {
this.onPaperResize();
}
/** Sync drawing canvas size/zoom with annotations canvas */
onPaperResize(ev) {
const { windowId } = this.props;
if (VideosReferences.get(windowId) && this.paper) {
const { canvasOverlay } = VideosReferences.get(windowId);
const { height } = canvasOverlay.ref.current;
const { width } = canvasOverlay.ref.current;
this.paper.view.viewSize = new this.paper.Size(width, height);
this.paper.view.zoom = canvasOverlay.scale;
}
}
/** Build parameters to paperjs View and canvas */
getDisplayProps() {
const { windowId } = this.props;
const osdref = OSDReferences.get(windowId);
const videoref = VideosReferences.get(windowId);
if (osdref && videoref) {
console.error('Unhandled case: both OpenSeadragon (picture viewer) and video player on the same canvas');
}
if (osdref) {
const { viewport } = osdref.current;
const img = osdref.current.world.getItemAt(0);
const center = img.viewportToImageCoordinates(viewport.getCenter(true));
return {
canvasProps: { style: { height: '100%', width: '100%' } },
viewProps: {
center: new Point(center.x, center.y),
rotation: viewport.getRotation(),
scaling: new Point(viewport.getFlip() ? -1 : 1, 1),
zoom: img.viewportToImageZoom(viewport.getZoom()),
},
};
}
if (videoref) {
const { height, width } = videoref.canvasOverlay.ref.current;
return {
canvasProps: { height, style: { left: 0, position: 'absolute', top: 0 }, width },
viewProps: {
center: new Point(width / 2, height / 2),
height,
width,
zoom: videoref.canvasOverlay.scale,
},
};
}
throw new Error('Unknown or missing data player, not OpenSeadragon (picture viewer) nor the video player');
}
/** Draw SVG on canvas */
addPath(path) { addPath(path) {
const { closed, strokeWidth, updateGeometry } = this.props; const { closed, strokeWidth, updateGeometry } = this.props;
// TODO: Compute xywh of bounding container of layers // TODO: Compute xywh of bounding container of layers
...@@ -65,36 +122,18 @@ class AnnotationDrawing extends Component { ...@@ -65,36 +122,18 @@ class AnnotationDrawing extends Component {
}); });
} }
/** Save paperjs ref once created */
paperDidMount(paper) {
this.paper = paper;
}
/** */ /** */
paperThing() { paperThing() {
const { windowId } = this.props; const { viewProps, canvasProps } = this.getDisplayProps();
let viewport = null;
let img = null;
if (OSDReferences.get(windowId)) {
console.debug('[annotation-plugin] OSD reference: ', OSDReferences.get(windowId));
viewport = OSDReferences.get(windowId).current.viewport;
img = OSDReferences.get(windowId).current.world.getItemAt(0);
} else if (VideoViewersReferences.get(windowId)) {
console.debug('[annotation-plugin] VideoViewers reference: ', VideoViewersReferences.get(windowId));
viewport = viewportFromAnnotationOverlayVideo(VideoViewersReferences.get(windowId).props);
}
const { const {
activeTool, fillColor, strokeColor, strokeWidth, svg, activeTool, fillColor, strokeColor, strokeWidth, svg,
} = this.props; } = this.props;
if (!activeTool || activeTool === 'cursor') return null; if (!activeTool || activeTool === 'cursor') return null;
// Setup Paper View to have the same center and zoom as the OSD Viewport/video canvas
const center = img
? img.viewportToImageCoordinates(viewport.getCenter(true))
: viewport.getCenter();
const flipped = viewport.getFlip();
const viewProps = {
center: new Point(center.x, center.y),
rotation: viewport.getRotation(),
scaling: new Point(flipped ? -1 : 1, 1),
zoom: img ? img.viewportToImageZoom(viewport.getZoom()) : viewport.getZoom(),
};
let ActiveTool = RectangleTool; let ActiveTool = RectangleTool;
switch (activeTool) { switch (activeTool) {
case 'rectangle': case 'rectangle':
...@@ -118,14 +157,14 @@ class AnnotationDrawing extends Component { ...@@ -118,14 +157,14 @@ class AnnotationDrawing extends Component {
return ( return (
<div <div
className="foo"
style={{ style={{
height: '100%', left: 0, position: 'absolute', top: 0, width: '100%', height: '100%', left: 0, position: 'absolute', top: 0, width: '100%',
}} }}
> >
<PaperContainer <PaperContainer
canvasProps={{ style: { height: '100%', width: '100%' } }} canvasProps={canvasProps}
viewProps={viewProps} viewProps={viewProps}
onMount={this.paperDidMount}
> >
{renderWithPaperScope((paper) => { {renderWithPaperScope((paper) => {
const paths = flatten(paper.project.layers.map((layer) => ( const paths = flatten(paper.project.layers.map((layer) => (
...@@ -149,6 +188,7 @@ class AnnotationDrawing extends Component { ...@@ -149,6 +188,7 @@ class AnnotationDrawing extends Component {
); );
})} })}
</PaperContainer> </PaperContainer>
<ResizeObserver onResize={this.onPaperResize} />
</div> </div>
); );
} }
...@@ -156,10 +196,14 @@ class AnnotationDrawing extends Component { ...@@ -156,10 +196,14 @@ class AnnotationDrawing extends Component {
/** */ /** */
render() { render() {
const { windowId } = this.props; const { windowId } = this.props;
const container = OSDReferences.get(windowId) const osdref = OSDReferences.get(windowId);
? OSDReferences.get(windowId).current.element const videoref = VideosReferences.get(windowId);
: VideoViewersReferences.get(windowId).apiRef.current; if (!osdref && !videoref) {
throw new Error("Unknown or missing data player, didn't found OpenSeadragon (image viewer) nor the video player");
}
const container = osdref
? osdref.current.element
: videoref.ref.current.parentElement;
return ( return (
ReactDOM.createPortal(this.paperThing(), container) ReactDOM.createPortal(this.paperThing(), container)
); );
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment