Moved part of the presentation display calculations to the server side

This commit is contained in:
Oleksandr Zhurbenko 2017-09-18 15:20:44 -07:00
parent d57f60fe09
commit 537175dad2
5 changed files with 88 additions and 34 deletions

View File

@ -0,0 +1,14 @@
const calculateSlideData = (slideData) => {
const { width, height, xOffset, yOffset, widthRatio, heightRatio } = slideData;
// calculating viewBox and offsets for the current presentation
return {
x: ((-xOffset * 2) * width) / 100,
y: ((-yOffset * 2) * height) / 100,
viewBoxWidth: (width * widthRatio) / 100,
viewBoxHeight: (height * heightRatio) / 100,
};
};
export default calculateSlideData;

View File

@ -6,6 +6,7 @@ import RedisPubSub from '/imports/startup/server/redis2x';
import Slides from '/imports/api/2.0/slides';
import Logger from '/imports/startup/server/logger';
import { SVG, PNG } from '/imports/utils/mimeTypes';
import { calculateSlideData } from '/imports/api/2.0/slides/server/helpers';
const requestWhiteboardHistory = (meetingId, slideId) => {
const REDIS_CONFIG = Meteor.settings.redis;
@ -26,7 +27,9 @@ const fetchImageSizes = imageUri =>
probe(imageUri)
.then((result) => {
if (!SUPPORTED_TYPES.includes(result.mime)) {
throw `Invalid image type, received ${result.mime} expecting ${SUPPORTED_TYPES.join()}`;
throw new Meteor.Error(
'invalid-image-type', `received ${result.mime} expecting ${SUPPORTED_TYPES.join()}`,
);
}
return {
@ -90,8 +93,20 @@ export default function addSlide(meetingId, presentationId, slide) {
return fetchImageSizes(imageUri)
.then(({ width, height }) => {
modifier.$set.width = width;
modifier.$set.height = height;
// pre-calculating the width, height, and vieBox coordinates / dimensions
// to unload the client-side
const slideData = {
width,
height,
xOffset: modifier.$set.xOffset,
yOffset: modifier.$set.yOffset,
widthRatio: modifier.$set.widthRatio,
heightRatio: modifier.$set.heightRatio,
};
modifier.$set.calculatedData = calculateSlideData(slideData);
modifier.$set.calculatedData.imageUri = imageUri;
modifier.$set.calculatedData.width = width;
modifier.$set.calculatedData.height = height;
return Slides.upsert(selector, modifier, cb);
})

View File

@ -1,6 +1,7 @@
import { check } from 'meteor/check';
import Slides from '/imports/api/2.0/slides';
import Logger from '/imports/startup/server/logger';
import { calculateSlideData } from '/imports/api/2.0/slides/server/helpers';
export default function resizeSlide(meetingId, slide) {
check(meetingId, String);
@ -23,6 +24,24 @@ export default function resizeSlide(meetingId, slide) {
},
};
// fetching the current slide data
// and pre-calculating the width, height, and vieBox coordinates / sizes
// to reduce the client-side load
const _slide = Slides.findOne(selector);
const slideData = {
width: _slide.calculatedData.width,
height: _slide.calculatedData.height,
xOffset,
yOffset,
widthRatio,
heightRatio,
};
const calculatedData = calculateSlideData(slideData);
calculatedData.imageUri = _slide.calculatedData.imageUri;
calculatedData.width = _slide.calculatedData.width;
calculatedData.height = _slide.calculatedData.height;
modifier.$set.calculatedData = calculatedData;
const cb = (err, numChanged) => {
if (err) {
return Logger.error(`Resizing slide id=${pageId}: ${err}`);

View File

@ -96,8 +96,8 @@ export default class PresentationArea extends React.Component {
}
calculateSize() {
const originalWidth = this.props.currentSlide.width;
const originalHeight = this.props.currentSlide.height;
const originalWidth = this.props.currentSlide.calculatedData.width;
const originalHeight = this.props.currentSlide.calculatedData.height;
const { presentationHeight, presentationWidth } = this.state;
let adjustedWidth;
@ -133,8 +133,9 @@ export default class PresentationArea extends React.Component {
renderPresentationArea() {
// sometimes tomcat publishes the slide url, but the actual file is not accessible (why?)
if (this.props.currentSlide &&
this.props.currentSlide.width &&
this.props.currentSlide.height) {
this.props.currentSlide.calculatedData &&
this.props.currentSlide.calculatedData.width &&
this.props.currentSlide.calculatedData.height) {
// to control the size of the svg wrapper manually
// and adjust cursor's thickness, so that svg didn't scale it automatically
const adjustedSizes = this.calculateSize();
@ -142,18 +143,16 @@ export default class PresentationArea extends React.Component {
// a reference to the slide object
const slideObj = this.props.currentSlide;
// svgWidth and svgHeight are needed to set the svg's coordinate system
const svgWidth = slideObj.width;
const svgHeight = slideObj.height;
// calculating viewBox and offsets for the current presentation
const x = ((-slideObj.xOffset * 2) * svgWidth) / 100;
const y = ((-slideObj.yOffset * 2) * svgHeight) / 100;
const viewBoxWidth = (svgWidth * slideObj.widthRatio) / 100;
const viewBoxHeight = (svgHeight * slideObj.heightRatio) / 100;
// Uri for the slide
const imageUri = this.props.currentSlide.svgUri || this.props.currentSlide.pngUri;
// retrieving the pre-calculated data from the slide object
const {
x,
y,
width,
height,
viewBoxWidth,
viewBoxHeight,
imageUri,
} = slideObj.calculatedData;
return (
<div
@ -179,8 +178,8 @@ export default class PresentationArea extends React.Component {
transitionLeaveTimeout={400}
>
<svg
width={svgWidth}
height={svgHeight}
width={width}
height={height}
ref={(ref) => { if (ref != null) { this.svggroup = ref; } }}
viewBox={`${x} ${y} ${viewBoxWidth} ${viewBoxHeight}`}
version="1.1"
@ -197,32 +196,32 @@ export default class PresentationArea extends React.Component {
<Slide
id="slideComponent"
imageUri={imageUri}
svgWidth={svgWidth}
svgHeight={svgHeight}
svgWidth={width}
svgHeight={height}
/>
<AnnotationGroupContainer
width={svgWidth}
height={svgHeight}
width={width}
height={height}
whiteboardId={slideObj.id}
/>
<CursorWrapperContainer
widthRatio={slideObj.widthRatio}
physicalWidthRatio={adjustedSizes.width / svgWidth}
slideWidth={svgWidth}
slideHeight={svgHeight}
physicalWidthRatio={adjustedSizes.width / width}
slideWidth={width}
slideHeight={height}
/>
</g>
{this.props.userIsPresenter || this.props.multiUser ?
<PresentationOverlayContainer
slideWidth={svgWidth}
slideHeight={svgHeight}
slideWidth={width}
slideHeight={height}
getSvgRef={this.getSvgRef}
>
<WhiteboardOverlayContainer
getSvgRef={this.getSvgRef}
whiteboardId={slideObj.id}
slideWidth={svgWidth}
slideHeight={svgHeight}
slideWidth={width}
slideHeight={height}
viewBoxX={x}
viewBoxY={y}
viewBoxWidth={viewBoxWidth}
@ -299,8 +298,6 @@ PresentationArea.propTypes = {
meetingId: PropTypes.string,
presentationId: PropTypes.string.isRequired,
current: PropTypes.bool.isRequired,
height: PropTypes.number.isRequired,
width: PropTypes.number.isRequired,
heightRatio: PropTypes.number.isRequired,
widthRatio: PropTypes.number.isRequired,
xOffset: PropTypes.number.isRequired,
@ -313,6 +310,15 @@ PresentationArea.propTypes = {
swfUri: PropTypes.string.isRequired,
thumbUri: PropTypes.string.isRequired,
txtUri: PropTypes.string.isRequired,
calculatedData: PropTypes.shape({
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
width: PropTypes.number.isRequired,
viewBoxWidth: PropTypes.number.isRequired,
viewBoxHeight: PropTypes.number.isRequired,
imageUri: PropTypes.string.isRequired,
}).isRequired,
}),
// current multi-user status
multiUser: PropTypes.bool.isRequired,