Skip to content
Snippets Groups Projects
Select Git revision
  • a1bf526724b74a35e4d6fd24d0ba545542353ed1
  • demo_ci_gitlab_pages default
  • demo_gitlab_ci
  • 5-images-in-annotations
  • 5-final-images
  • 5-chpk-images-in-annot
  • tetras-main protected
  • 5-rebase-images-in-annot
  • 5-wip-images-in-annot
  • tmp
  • 1-edit-annotations-on-videos
  • 5-old-images-in-annotations
  • old_demo_ci_gitlab_pages
  • images_annotations
  • wip
  • devsetup
  • wip-annot-video-ui
  • wip-annotations-on-videos
  • master
  • v0.4.0_react16
  • wip-debugging-annotations
21 results

AnnotationCreation.js

Blame
  • Forked from IIIF / Mirador / Mirador annotations
    464 commits behind the upstream repository.
    user avatar
    Jack Reed authored
    a1bf5267
    History
    AnnotationCreation.js 10.54 KiB
    import React, { Component } from 'react';
    import PropTypes from 'prop-types';
    import Button from '@material-ui/core/Button';
    import Typography from '@material-ui/core/Typography';
    import Paper from '@material-ui/core/Paper';
    import Grid from '@material-ui/core/Grid';
    import ToggleButton from '@material-ui/lab/ToggleButton';
    import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
    import RectangleIcon from '@material-ui/icons/CheckBoxOutlineBlank';
    import CircleIcon from '@material-ui/icons/RadioButtonUnchecked';
    import PolygonIcon from '@material-ui/icons/Timeline';
    import FormatColorFillIcon from '@material-ui/icons/FormatColorFill';
    import StrokeColorIcon from '@material-ui/icons/BorderColor';
    import LineWeightIcon from '@material-ui/icons/LineWeight';
    import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
    import Popover from '@material-ui/core/Popover';
    import Divider from '@material-ui/core/Divider';
    import MenuItem from '@material-ui/core/MenuItem';
    import ClickAwayListener from '@material-ui/core/ClickAwayListener';
    import MenuList from '@material-ui/core/MenuList';
    import { SketchPicker } from 'react-color';
    import { v4 as uuid } from 'uuid';
    import { withStyles } from '@material-ui/core/styles';
    import AnnotationDrawing from './AnnotationDrawing';
    import TextEditor from './TextEditor';
    import WebAnnotation from './WebAnnotation';
    import CursorIcon from './icons/Cursor';
    
    /** */
    class AnnotationCreation extends Component {
      /** */
      constructor(props) {
        super(props);
        this.state = {
          activeTool: 'cursor',
          annoBody: '',
          colorPopoverOpen: false,
          currentColorType: false,
          fillColor: null,
          lineWeightPopoverOpen: false,
          popoverAnchorEl: null,
          popoverLineWeightAnchorEl: null,
          strokeColor: '#00BFFF',
          strokeWidth: 1,
          svg: null,
          xywh: null,
        };
    
        this.submitForm = this.submitForm.bind(this);
        this.updateBody = this.updateBody.bind(this);
        this.updateGeometry = this.updateGeometry.bind(this);
        this.changeTool = this.changeTool.bind(this);
        this.openChooseColor = this.openChooseColor.bind(this);
        this.openChooseLineWeight = this.openChooseLineWeight.bind(this);
        this.handleLineWeightSelect = this.handleLineWeightSelect.bind(this);
        this.handleCloseLineWeight = this.handleCloseLineWeight.bind(this);
        this.closeChooseColor = this.closeChooseColor.bind(this);
        this.updateStrokeColor = this.updateStrokeColor.bind(this);
      }
    
      /** */
      openChooseColor(e) {
        this.setState({
          colorPopoverOpen: true,
          currentColorType: e.currentTarget.value,
          popoverAnchorEl: e.currentTarget,
        });
      }
    
      /** */
      openChooseLineWeight(e) {
        this.setState({
          lineWeightPopoverOpen: true,
          popoverLineWeightAnchorEl: e.currentTarget,
        });
      }
    
      /** */
      handleLineWeightSelect(e) {
        this.setState({
          lineWeightPopoverOpen: false,
          popoverLineWeightAnchorEl: null,
          strokeWidth: e.currentTarget.value,
        });
      }
    
      /** */
      handleCloseLineWeight(e) {
        this.setState({
          lineWeightPopoverOpen: false,
          popoverLineWeightAnchorEl: null,
        });
      }
    
      /** */
      closeChooseColor(e) {
        this.setState({
          colorPopoverOpen: false,
          currentColorType: null,
          popoverAnchorEl: null,
        });
      }
    
      /** */
      updateStrokeColor(color) {
        const { currentColorType } = this.state;
        this.setState({
          [currentColorType]: color.hex,
        });
      }
    
      /** */
      submitForm(e) {
        e.preventDefault();
        const {
          canvases, parentactions, receiveAnnotation, config,
        } = this.props;
        const { annoBody, xywh, svg } = this.state;
        canvases.forEach((canvas) => {
          const localStorageAdapter = config.annotation.adapter(canvas.id);
          const anno = new WebAnnotation({
            body: annoBody,
            canvasId: canvas.id,
            id: `https://example.org/iiif/book1/page/manifest/${uuid()}`,
            svg,
            xywh,
          }).toJson();
          const newAnnoPage = localStorageAdapter.create(anno);
          receiveAnnotation(canvas.id, localStorageAdapter.annotationPageId, newAnnoPage);
        });
        this.setState({
          activeTool: null,
        });
        parentactions.closeCompanionWindow();
      }
    
      /** */
      changeTool(e, tool) {
        this.setState({
          activeTool: tool,
        });
      }
    
      /** */
      updateBody(annoBody) {
        this.setState({ annoBody });
      }
    
      /** */
      updateGeometry({ svg, xywh }) {
        this.setState({
          svg, xywh,
        });
      }
    
      /** */
      render() {
        const { classes, parentactions, windowId } = this.props;
        const {
          activeTool, colorPopoverOpen, currentColorType, fillColor, popoverAnchorEl, strokeColor,
          popoverLineWeightAnchorEl, lineWeightPopoverOpen, strokeWidth,
        } = this.state;
        return (
          <Paper className={classes.root}>
            <AnnotationDrawing
              activeTool={activeTool}
              fillColor={fillColor}
              strokeColor={strokeColor}
              strokeWidth={strokeWidth}
              updateGeometry={this.updateGeometry}
              windowId={windowId}
            />
            <form onSubmit={this.submitForm}>
              <Grid container>
                <Grid item xs={12}>
                  <Typography variant="overline">
                    Target
                  </Typography>
                </Grid>
                <Grid item xs={12}>
                  <Paper elevation={0} className={classes.paper}>
                    <ToggleButtonGroup
                      className={classes.grouped}
                      value={activeTool}
                      exclusive
                      onChange={this.changeTool}
                      aria-label="tool selection"
                      size="small"
                    >
                      <ToggleButton value="cursor" aria-label="select cursor">
                        <CursorIcon />
                      </ToggleButton>
                    </ToggleButtonGroup>
                    <Divider flexItem orientation="vertical" className={classes.divider} />
                    <ToggleButtonGroup
                      className={classes.grouped}
                      value={activeTool}
                      exclusive
                      onChange={this.changeTool}
                      aria-label="tool selection"
                      size="small"
                    >
                      <ToggleButton value="rectangle" aria-label="add a rectangle">
                        <RectangleIcon />
                      </ToggleButton>
                      <ToggleButton value="circle" aria-label="add a circle">
                        <CircleIcon />
                      </ToggleButton>
                      <ToggleButton value="polygon" aria-label="add a polygon">
                        <PolygonIcon />
                      </ToggleButton>
                    </ToggleButtonGroup>
                  </Paper>
                </Grid>
              </Grid>
              <Grid container>
                <Grid item xs={12}>
                  <Typography variant="overline">
                    Style
                  </Typography>
                </Grid>
                <Grid item xs={12}>
                  <ToggleButtonGroup
                    aria-label="style selection"
                    size="small"
                  >
                    <ToggleButton
                      value="strokeColor"
                      aria-label="select color"
                      onClick={this.openChooseColor}
                    >
                      <StrokeColorIcon style={{ fill: strokeColor }} />
                      <ArrowDropDownIcon />
                    </ToggleButton>
                    <ToggleButton
                      value="strokeColor"
                      aria-label="select line weight"
                      onClick={this.openChooseLineWeight}
                    >
                      <LineWeightIcon />
                      <ArrowDropDownIcon />
                    </ToggleButton>
                    <ToggleButton
                      value="fillColor"
                      aria-label="select color"
                      onClick={this.openChooseColor}
                    >
                      <FormatColorFillIcon style={{ fill: fillColor }} />
                      <ArrowDropDownIcon />
                    </ToggleButton>
                  </ToggleButtonGroup>
                </Grid>
              </Grid>
              <Grid container>
                <Grid item xs={12}>
                  <Typography variant="overline">
                    Content
                  </Typography>
                </Grid>
                <Grid item xs={12}>
                  <TextEditor
                    updateAnnotationBody={this.updateBody}
                  />
                </Grid>
              </Grid>
              <Button onClick={parentactions.closeCompanionWindow}>
                Cancel
              </Button>
              <Button variant="contained" color="primary" type="submit">
                Save
              </Button>
            </form>
            <Popover
              open={lineWeightPopoverOpen}
              anchorEl={popoverLineWeightAnchorEl}
            >
              <Paper>
                <ClickAwayListener onClickAway={this.handleCloseLineWeight}>
                  <MenuList>
                    {[1, 3, 5, 10, 50].map((option, index) => (
                      <MenuItem
                        key={option}
                        onClick={this.handleLineWeightSelect}
                        value={option}
                      >
                        {option}
                      </MenuItem>
                    ))}
                  </MenuList>
                </ClickAwayListener>
              </Paper>
            </Popover>
            <Popover
              open={colorPopoverOpen}
              anchorEl={popoverAnchorEl}
              onClose={this.closeChooseColor}
            >
              <SketchPicker
                // eslint-disable-next-line react/destructuring-assignment
                color={this.state[currentColorType] || {}}
                onChangeComplete={this.updateStrokeColor}
              />
            </Popover>
          </Paper>
        );
      }
    }
    
    /** */
    const styles = (theme) => ({
      divider: {
        margin: theme.spacing(1, 0.5),
      },
      grouped: {
        '&:first-child': {
          borderRadius: theme.shape.borderRadius,
        },
        '&:not(:first-child)': {
          borderRadius: theme.shape.borderRadius,
        },
        border: 'none',
        margin: theme.spacing(0.5),
      },
      paper: {
        display: 'flex',
        flexWrap: 'wrap',
      },
      root: {
        padding: theme.spacing(1),
      },
    });
    
    AnnotationCreation.propTypes = {
      canvases: PropTypes.arrayOf(
        PropTypes.shape({ id: PropTypes.string, index: PropTypes.number }),
      ),
      classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
      config: PropTypes.shape({
        annotation: PropTypes.shape({
          adapter: PropTypes.func,
        }),
      }).isRequired,
      parentactions: PropTypes.shape({
        closeCompanionWindow: PropTypes.func,
      }),
      receiveAnnotation: PropTypes.func.isRequired,
      windowId: PropTypes.string.isRequired,
    };
    
    AnnotationCreation.defaultProps = {
      canvases: [],
      parentactions: {},
    };
    
    
    export default withStyles(styles)(AnnotationCreation);