bigbluebutton-Github/bigbluebutton-html5/imports/ui/components/whiteboard/annotations/pencil/component.jsx

175 lines
5.9 KiB
React
Raw Normal View History

import React, { Component } from 'react';
import PropTypes from 'prop-types';
2020-04-07 04:34:08 +08:00
import { getFormattedColor, getStrokeWidth, denormalizeCoord } from '../helpers';
export default class PencilDrawComponent extends Component {
static getInitialCoordinates(annotation, slideWidth, slideHeight) {
const { points } = annotation;
2016-06-09 01:12:24 +08:00
let i = 2;
let path = '';
if (points && points.length >= 2) {
2020-04-07 04:34:08 +08:00
path = `M${denormalizeCoord(points[0], slideWidth)
}, ${denormalizeCoord(points[1], slideHeight)}`;
2016-06-09 01:12:24 +08:00
while (i < points.length) {
2020-04-07 04:34:08 +08:00
path = `${path} L${denormalizeCoord(points[i], slideWidth)
}, ${denormalizeCoord(points[i + 1], slideHeight)}`;
2016-06-09 01:12:24 +08:00
i += 2;
}
}
return { path, points };
}
static getFinalCoordinates(annotation, slideWidth, slideHeight) {
const { points, commands } = annotation;
let path = '';
let i;
let j;
for (i = 0, j = 0; i < commands.length; i += 1) {
switch (commands[i]) {
// MOVE_TO - consumes 1 pair of values
case 1:
2020-04-07 04:34:08 +08:00
path = `${path} M${denormalizeCoord(points[j], slideWidth)} ${denormalizeCoord(points[j + 1], slideHeight)}`;
j += 2;
break;
// LINE_TO - consumes 1 pair of values
case 2:
2020-04-07 04:34:08 +08:00
path = `${path} L${denormalizeCoord(points[j], slideWidth)} ${denormalizeCoord(points[j + 1], slideHeight)}`;
j += 2;
break;
// QUADRATIC_CURVE_TO - consumes 2 pairs of values
// 1st pair is a control point, second is a coordinate
case 3:
2020-04-07 04:34:08 +08:00
path = `${path} Q${denormalizeCoord(points[j], slideWidth)}, ${
denormalizeCoord(points[j + 1], slideHeight)}, ${denormalizeCoord(points[j + 2], slideWidth)}, ${
denormalizeCoord(points[j + 3], slideHeight)}`;
j += 4;
break;
// CUBIC_CURVE_TO - consumes 3 pairs of values
// 1st and 2nd are control points, 3rd is an end coordinate
case 4:
2020-04-07 04:34:08 +08:00
path = `${path} C${denormalizeCoord(points[j], slideWidth)}, ${
denormalizeCoord(points[j + 1], slideHeight)}, ${denormalizeCoord(points[j + 2], slideWidth)}, ${
denormalizeCoord(points[j + 3], slideHeight)}, ${denormalizeCoord(points[j + 4], slideWidth)}, ${
denormalizeCoord(points[j + 5], slideHeight)}`;
j += 6;
break;
default:
break;
}
}
// If that's just one coordinate at the end (dot) - we want to display it.
// So adding L with the same X and Y values to the path
if (path && points.length === 2) {
2020-04-07 04:34:08 +08:00
path = `${path} L${denormalizeCoord(points[0], slideWidth)} ${denormalizeCoord(points[1], slideHeight)}`;
}
return { path, points };
}
constructor(props) {
super(props);
const { annotation, slideWidth, slideHeight } = this.props;
this.path = this.getCoordinates(annotation, slideWidth, slideHeight);
this.getCurrentPath = this.getCurrentPath.bind(this);
this.getCoordinates = this.getCoordinates.bind(this);
}
shouldComponentUpdate(nextProps) {
2020-04-07 04:34:08 +08:00
const { version } = this.props;
return version !== nextProps.version;
}
componentWillUpdate(nextProps) {
const { annotation: nextAnnotation, slideWidth, slideHeight } = nextProps;
const { points: nextPoints } = nextAnnotation;
const { annotation } = this.props;
2020-04-07 04:34:08 +08:00
const { points } = annotation;
if (nextPoints.length !== points.length) {
this.path = this.getCoordinates(nextAnnotation, slideWidth, slideHeight);
}
}
getCoordinates(annotation, slideWidth, slideHeight) {
if ((!annotation || annotation.points.length === 0)
|| (annotation.status === 'DRAW_END' && !annotation.commands)) {
return undefined;
}
2017-09-06 09:36:15 +08:00
let data;
2017-08-30 04:58:48 +08:00
// Final message, display smoothes coordinates
if (annotation.status === 'DRAW_END') {
2017-09-06 09:36:15 +08:00
data = PencilDrawComponent.getFinalCoordinates(annotation, slideWidth, slideHeight);
2017-08-30 04:58:48 +08:00
// Not a final message, but rendering it for the first time, creating a new path
} else if (!this.path) {
2017-09-06 09:36:15 +08:00
data = PencilDrawComponent.getInitialCoordinates(annotation, slideWidth, slideHeight);
// If it's not the first 2 cases - means we just got an update, updating the coordinates
} else {
data = this.updateCoordinates(annotation, slideWidth, slideHeight);
}
this.points = data.points;
return data.path;
}
getCurrentPath() {
return this.path ? this.path : 'M -1 -1';
}
updateCoordinates(annotation, slideWidth, slideHeight) {
const { points } = annotation;
2020-04-07 04:34:08 +08:00
let i = this.points.length;
let path = '';
while (i < points.length) {
2020-04-07 04:34:08 +08:00
path = `${path} L${denormalizeCoord(points[i], slideWidth)
}, ${denormalizeCoord(points[i + 1], slideHeight)}`;
i += 2;
}
2020-04-07 04:34:08 +08:00
path = this.path + path;
return { path, points };
2016-06-09 01:12:24 +08:00
}
render() {
const { annotation, slideWidth } = this.props;
return (
<path
2016-06-09 01:12:24 +08:00
fill="none"
2020-04-07 04:34:08 +08:00
stroke={getFormattedColor(annotation.color)}
d={this.getCurrentPath()}
2020-04-07 04:34:08 +08:00
strokeWidth={getStrokeWidth(annotation.thickness, slideWidth)}
2016-06-09 01:12:24 +08:00
strokeLinejoin="round"
strokeLinecap="round"
style={{ WebkitTapHighlightColor: 'rgba(0, 0, 0, 0)' }}
data-test="pencilDraw"
2017-06-03 03:25:02 +08:00
/>
);
}
}
2016-06-09 01:12:24 +08:00
PencilDrawComponent.propTypes = {
// Defines a version of the shape, so that we know if we need to update the component or not
version: PropTypes.number.isRequired,
// Defines an annotation object, which contains all the basic info we need to draw with a pencil
annotation: PropTypes.shape({
points: PropTypes.arrayOf(PropTypes.number).isRequired,
color: PropTypes.number.isRequired,
thickness: PropTypes.number.isRequired,
}).isRequired,
// Defines the width of the slide (svg coordinate system), which needed in calculations
slideWidth: PropTypes.number.isRequired,
// Defines the height of the slide (svg coordinate system), which needed in calculations
slideHeight: PropTypes.number.isRequired,
2016-06-09 01:12:24 +08:00
};