Skip to content
Snippets Groups Projects
Select Git revision
  • 086c6fdf540919c27163a4eb11826e031932835c
  • support-video default protected
2 results

AnnotationSvgDrawing.js

Blame
  • AnnotationSvgDrawing.js 7.07 KiB
    import React, { Component } from 'react';
    import ReactDOM from 'react-dom';
    import PropTypes from 'prop-types';
    import { OSDReferences } from 'mirador/dist/es/src/plugins/OSDReferences';
    import { VideosReferences } from 'mirador/dist/es/src/plugins/VideosReferences';
    import { renderWithPaperScope, PaperContainer } from '@psychobolt/react-paperjs';
    import {
      EllipseTool,
      RectangleTool,
      FreeformPathTool,
    } from '@psychobolt/react-paperjs-editor';
    import { Point } from 'paper';
    import flatten from 'lodash/flatten';
    import EditTool from './EditTool';
    import { mapChildren } from '../utils';
    
    /** */
    class AnnotationSvgDrawing extends Component {
      /** */
      constructor(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);
      }
    
      /** */
      componentDidMount() {
        const { windowId } = this.props;
        this.OSDReference = OSDReferences.get(windowId);
        this.onPaperResize();
      }
    
      /** Sync drawing canvas size/zoom with annotations canvas */
      onPaperResize(ev) {
        const { windowId } = this.props;
        if (VideosReferences.get(windowId) && this.paper) {
          const { canvasOverlay, video } = VideosReferences.get(windowId);
          const { height, width } = canvasOverlay.ref.current;
          const { videoHeight, videoWidth } = video;
          this.paper.view.center = new Point(videoWidth / 2, videoHeight / 2);
          this.paper.view.zoom = canvasOverlay.scale;
          this.paper.view.viewSize = new this.paper.Size(width, height);
        }
      }
    
      /** Save paperjs ref once created */
      paperDidMount(paper) {
        this.paper = paper;
      }
    
      /** */
      addPath(path) {
        const { closed, strokeWidth, updateGeometry } = this.props;
        path.closed = closed; // eslint-disable-line no-param-reassign
        // Reset strokeWidth for persistence
        path.strokeWidth = strokeWidth; // eslint-disable-line no-param-reassign
        path.data.state = null; // eslint-disable-line no-param-reassign
        const svgExports = flatten(path.project.layers.map((layer) => (
          flatten(mapChildren(layer)).map((aPath) => aPath.exportSVG({ asString: true }))
        )));
        updateGeometry({
          svg: svgExports.join(''),
        });
      }
    
      getDisplayProps() {
        const { windowId } = this.props;
        const osdref = OSDReferences.get(windowId);
        const videoref = VideosReferences.get(windowId);
    
        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,
              resize: 'true',
              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 (image viewer) nor the video player');
      }
    
      /** */
      paperThing() {
        const { viewProps, canvasProps } = this.getDisplayProps();
        const {
          activeTool, fillColor, strokeColor, strokeWidth, svg,
        } = this.props;
    
        if (!activeTool || activeTool === 'cursor') {
          return null;
        }
        // // Setup Paper View to have the same center and zoom as the OSD Viewport
        // const viewportZoom = this.OSDReference.viewport.getZoom(true);
        // const image1 = this.OSDReference.world.getItemAt(0);
        // const center = image1.viewportToImageCoordinates(
        //   this.OSDReference.viewport.getCenter(true),
        // );
        // const flipped = this.OSDReference.viewport.getFlip();
        //
        // const viewProps = {
        //   center: new Point(center.x, center.y),
        //   rotation: this.OSDReference.viewport.getRotation(),
        //   scaling: new Point(flipped ? -1 : 1, 1),
        //   zoom: image1.viewportToImageZoom(viewportZoom),
        // };
    
        let ActiveTool = RectangleTool;
        switch (activeTool) {
          case 'rectangle':
            ActiveTool = RectangleTool;
            break;
          case 'ellipse':
            ActiveTool = EllipseTool;
            break;
          case 'freehand':
            ActiveTool = FreeformPathTool;
            break;
          case 'edit':
            ActiveTool = EditTool;
            break;
          default:
            break;
        }
    
        return (
          <div
            className="foo"
            style={{
              height: '100%', left: 0, position: 'absolute', top: 0, width: '100%',
            }}
          >
            <PaperContainer
              canvasProps={{ style: { height: '100%', width: '100%' } }}
              viewProps={viewProps}
            >
              {renderWithPaperScope((paper) => {
                const paths = flatten(paper.project.layers.map((layer) => (
                  flatten(mapChildren(layer)).map((aPath) => aPath)
                )));
                if (svg && paths.length === 0) {
                  paper.project.importSVG(svg);
                }
                paper.settings.handleSize = 10; // eslint-disable-line no-param-reassign
                paper.settings.hitTolerance = 10; // eslint-disable-line no-param-reassign
                return (
                  <ActiveTool
                    pathProps={{
                      fillColor,
                      strokeColor,
                      strokeWidth: strokeWidth / paper.view.zoom,
                    }}
                    paper={paper}
                    onPathAdd={this.addPath}
                  />
                );
              })}
            </PaperContainer>
          </div>
        );
      }
    
      /** */
      render() {
        const { windowId } = this.props;
        const osdref = OSDReferences.get(windowId);
        const videoref = VideosReferences.get(windowId);
        if (!osdref && !videoref) {
          throw new Error("Unknown or missing data player, didn't found OpenSeadragon (image viewer) nor the video player");
        }
        if (osdref && videoref) {
          throw new Error('Unhandled case: both OpenSeadragon (image viewer) and video player on the same canvas');
        }
        const container = osdref
          ? osdref.current.element
          : videoref.ref.current.parentElement;
        return (
          ReactDOM.createPortal(this.paperThing(), container)
        );
      }
    }
    
    AnnotationSvgDrawing.propTypes = {
      activeTool: PropTypes.string,
      closed: PropTypes.bool,
      edit: PropTypes.bool,
      fillColor: PropTypes.string,
      strokeColor: PropTypes.string,
      strokeWidth: PropTypes.number,
      svg: PropTypes.string,
      updateGeometry: PropTypes.func.isRequired,
      windowId: PropTypes.string.isRequired
    }
    
    AnnotationSvgDrawing.defaultProps = {
      activeTool: null,
      closed: false,
      strokeColor: '#cc0000',
      strokeWidth: 3,
      fillColor: null,
      svg: null,
    };
    
    export default AnnotationSvgDrawing;