diff --git a/bigbluebutton-html5/imports/api/slides/server/methods/zoomSlide.js b/bigbluebutton-html5/imports/api/slides/server/methods/zoomSlide.js
new file mode 100644
index 0000000000000000000000000000000000000000..c546a88af87a3abf577c76a23a9ee7111ab48091
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/slides/server/methods/zoomSlide.js
@@ -0,0 +1,52 @@
+import Presentations from '/imports/api/presentations';
+import Slides from '/imports/api/slides';
+import { Meteor } from 'meteor/meteor';
+import { check } from 'meteor/check';
+import RedisPubSub from '/imports/startup/server/redis';
+
+export default function switchSlide(credentials, slideNumber, podId, widthRatio, heightRatio, x, y) {
+  const REDIS_CONFIG = Meteor.settings.private.redis;
+
+  const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
+  const EVENT_NAME = 'ResizeAndMovePagePubMsg';
+
+  const { meetingId, requesterUserId, requesterToken } = credentials;
+
+  check(meetingId, String);
+  check(requesterUserId, String);
+  check(requesterToken, String);
+
+  const selector = {
+    meetingId,
+    podId,
+    current: true,
+  };
+  const Presentation = Presentations.findOne(selector);
+
+  if (!Presentation) {
+    throw new Meteor.Error('presentation-not-found', 'You need a presentation to be able to switch slides');
+  }
+
+  const Slide = Slides.findOne({
+    meetingId,
+    podId,
+    presentationId: Presentation.id,
+    num: slideNumber,
+  });
+
+  if (!Slide) {
+    throw new Meteor.Error('slide-not-found', `Slide number ${slideNumber} not found in the current presentation`);
+  }
+
+  const payload = {
+    podId,
+    presentationId: Presentation.id,
+    pageId: Slide.id,
+    xOffset: x,
+    yOffset: y,
+    widthRatio,
+    heightRatio,
+  };
+
+  return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
+}
diff --git a/bigbluebutton-html5/imports/ui/components/presentation/presentation-overlay/component.jsx b/bigbluebutton-html5/imports/ui/components/presentation/presentation-overlay/component.jsx
index e0f81ab95b4795e0adaf9433e4ef720a31beefba..f639796bb79bc540716e1fb0494a84289ea51897 100755
--- a/bigbluebutton-html5/imports/ui/components/presentation/presentation-overlay/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/presentation/presentation-overlay/component.jsx
@@ -1,14 +1,17 @@
 import React, { Component } from 'react';
 import PropTypes from 'prop-types';
+import SlideViewModel from '/imports/utils/slideViewModel';
 
 const CURSOR_INTERVAL = 16;
-const MYSTERY_NUM = 2;
+const MYSTERY_NUM = 5;
 const HUNDRED_PERCENT = 100;
 
 export default class PresentationOverlay extends Component {
   constructor(props) {
     super(props);
 
+    this.SlideZoomData = new SlideViewModel(props.adjustedSizes.width, props.adjustedSizes.height, props.slideHeight, props.slideWidth);;
+
     // last sent coordinates
     this.lastSentClientX = 0;
     this.lastSentClientY = 0;
@@ -20,7 +23,7 @@ export default class PresentationOverlay extends Component {
     // id of the setInterval()
     this.intervalId = 0;
     this.state = {
-        zoomValue: 100,
+        zoom: 100,
     };
 
     // Mobile Firefox has a bug where e.preventDefault on touchstart doesn't prevent
@@ -89,76 +92,115 @@ export default class PresentationOverlay extends Component {
     return point;
   }
 
+  componentDidMount() {
+    this.SlideZoomData.viewportW = this.props.adjustedSizes.width;
+    this.SlideZoomData.viewportH = this.props.adjustedSizes.height;
+    this.SlideZoomData.pageOrigW = this.props.adjustedSizes.width;
+    this.SlideZoomData.pageOrigH = this.props.adjustedSizes.height;
+    this.SlideZoomData.parentW = document.querySelector('._imports_ui_components_presentation__styles__presentationArea').getBoundingClientRect().width;
+    this.SlideZoomData.parentH = document.querySelector('._imports_ui_components_presentation__styles__presentationArea').getBoundingClientRect().height;
+    console.error(this.SlideZoomData);
+    
+  }
 
   mouseZoomHandler(e) {
     // calc for sliderZoom
     // zoomSlide(zoom, (((slideLoader.content.width/2)*SlideViewModel.HUNDRED_PERCENT)/zoom), (((slideLoader.content.height/2)*SlideViewModel.HUNDRED_PERCENT)/zoom));
+    let zoom = this.state.zoom;
+    console.error(this.SlideZoomData.viewportW);
+    
+    if (e.deltaY < 0) {
+      zoom += 5;
+    }
+    if (e.deltaY > 0) {
+      zoom -= 5;
+    }
+    if (zoom <= HUNDRED_PERCENT) {
+      zoom = HUNDRED_PERCENT;
+    } else if (zoom >= 400) {
+      zoom = 400;
+    }
     const {
       zoomSlide,
       podId,
       currentSlideNum,
       slideWidth,
       slideHeight,
-      adjustedSizes
+      adjustedSizes,
+      updateCursor,
+      whiteboardId,
     } = this.props;
-
+    
     const mouseX = e.clientX;
     const mouseY = e.clientY;
+    const svgPosition = this.getTransformedSvgPoint(mouseX, mouseY);
+    const svgPercentage = this.svgCoordinateToPercentages(svgPosition);
+    console.error(this.state.zoom);
+    
+    this.SlideZoomData.onZoom(zoom, svgPosition.x, svgPosition.y);
 
+    zoomSlide(
+      currentSlideNum,
+      podId,
+      this.SlideZoomData.viewedRegionW,
+      this.SlideZoomData.viewedRegionH,
+      this.SlideZoomData.viewedRegionX,
+      this.SlideZoomData.viewedRegionY,
+    );
+    this.setState({ zoom });
+    updateCursor({
+      xPercent: svgPercentage.x,
+      yPercent: svgPercentage.y,
+      whiteboardId,
+    });
     // console.error('event', x,y);
-    const _pageOrigW = slideWidth;
-    const _pageOrigH = slideHeight;
-    const viewportW = adjustedSizes.width;
-    const viewportH = adjustedSizes.height;
+    // const _pageOrigW = slideWidth;
+    // const _pageOrigH = slideHeight;
+    // const viewportW = adjustedSizes.width;
+    // const viewportH = adjustedSizes.height;
 
-    let _calcPageW = viewportW/(100/HUNDRED_PERCENT);
-    let _calcPageH = viewportH/(100/HUNDRED_PERCENT);
-    let _calcPageX = (0/HUNDRED_PERCENT) * _calcPageW;
-    let _calcPageY =  (0/HUNDRED_PERCENT) * _calcPageH;	
+    // let _calcPageW = viewportW/(100/HUNDRED_PERCENT);
+    // let _calcPageH = viewportH/(100/HUNDRED_PERCENT);
+    // let _calcPageX = (0/HUNDRED_PERCENT) * _calcPageW;
+    // let _calcPageY =  (0/HUNDRED_PERCENT) * _calcPageH;	
 
-    const svgPosition = this.getTransformedSvgPoint(mouseX, mouseY);
-    const svgPercentage = this.svgCoordinateToPercentages(svgPosition);
+    // const svgPercentage = this.svgCoordinateToPercentages(svgPosition);
     
-    // console.error('svgPosition', svgPosition.x, svgPosition.y);
-    // console.error('svgPercentage', svgPercentage.x, svgPercentage.y);
+    // // console.error('svgPosition', svgPosition.x, svgPosition.y);
+    // // console.error('svgPercentage', svgPercentage.x, svgPercentage.y);
        
-    const relXcoordInPage = (svgPercentage.x) / 100;
-    const relYcoordInPage = (svgPercentage.y) / 100;
+    // const relXcoordInPage = (svgPercentage.x) / 100;
+    // const relYcoordInPage = (svgPercentage.y) / 100;
 
-    const zoomValue = this.state.zoomValue + 5;
+    // const zoomValue = this.state.zoomValue + 5;
 
-    console.error(zoomValue);
-    console.error(mouseX, mouseY);
+    // console.error(zoomValue);
+    // console.error(mouseX, mouseY);
 
-    _calcPageW = viewportW * zoomValue / HUNDRED_PERCENT;
-    _calcPageH = (_calcPageW / _pageOrigW) * _pageOrigH;
+    // _calcPageW = viewportW * zoomValue / HUNDRED_PERCENT;
+    // _calcPageH = (_calcPageW / _pageOrigW) * _pageOrigH;
 
-    console.error(_calcPageW, _calcPageH);
+    // console.error(_calcPageW, _calcPageH);
 
-    const absXcoordInPage = relXcoordInPage * _calcPageW;
-    const absYcoordInPage = relYcoordInPage * _calcPageH;
+    // const absXcoordInPage = relXcoordInPage * _calcPageW;
+    // const absYcoordInPage = relYcoordInPage * _calcPageH;
   
-    console.error(mouseX, mouseY);
-    console.error(svgPosition.x, svgPosition.y);
-    console.error(relXcoordInPage, relYcoordInPage);
-    console.error(absXcoordInPage, absYcoordInPage);
-
-    _calcPageX = (absXcoordInPage - mouseX) / MYSTERY_NUM;
-    _calcPageY = (absYcoordInPage - mouseY) / MYSTERY_NUM;
-
-    const offsetX = (_calcPageX * 100) / _calcPageW;
-    const offsetY = (_calcPageX * 100) / _calcPageW;
-    console.error(`(${_calcPageX} * 100) / ${_calcPageW}`, offsetX);
-    console.error(`(${_calcPageY} * 100) / ${_calcPageH}`, offsetY);
-
-    this.setState(
-      { zoomValue },
-      () => zoomSlide(currentSlideNum, podId, 
-        (this.state.zoomValue - 100) - 100,
-        offsetX,
-        offsetY
-      )
-    );
+    // console.error(mouseX, mouseY);
+    // console.error(svgPosition.x, svgPosition.y);
+    // console.error(relXcoordInPage, relYcoordInPage);
+    // console.error(absXcoordInPage, absYcoordInPage);
+
+    // _calcPageX = (absXcoordInPage - mouseX) / MYSTERY_NUM;
+    // _calcPageY = (absYcoordInPage - mouseY) / MYSTERY_NUM;
+
+    // const offsetX = (_calcPageX * 100) / _calcPageW;
+    // const offsetY = (_calcPageX * 100) / _calcPageW;
+    // const ration = HUNDRED_PERCENT - (this.state.zoomValue - HUNDRED_PERCENT);
+    // console.error(`(${_calcPageX} * 100) / ${_calcPageW}`, offsetX);
+    // console.error(`(${_calcPageY} * 100) / ${_calcPageH}`, offsetY);
+   
+    
+   
   }
 
 
diff --git a/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/service.js b/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/service.js
index d5870687fbe97fa018f6644a7d1cee2d6048019f..43d8bf9aee4bda7e8ea394b8366e678d4d9dbf4c 100644
--- a/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/service.js
+++ b/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/service.js
@@ -40,8 +40,8 @@ const nextSlide = (currentSlideNum, numberOfSlides, podId) => {
   }
 };
 
-const zoomSlide = (currentSlideNum, podId, value, xOffset, yOffset) => {
-  makeCall('zoomSlide', currentSlideNum, podId, value, xOffset, yOffset);
+const zoomSlide = (currentSlideNum, podId, widthRation, HeightRatio, xOffset, yOffset) => {
+  makeCall('zoomSlide', currentSlideNum, podId, widthRation, HeightRatio, xOffset, yOffset);
 };
 
 
diff --git a/bigbluebutton-html5/imports/utils/slideCalcUtils.js b/bigbluebutton-html5/imports/utils/slideCalcUtils.js
new file mode 100644
index 0000000000000000000000000000000000000000..d05b0d87aa6831caa26a531dc800317315cfaa4e
--- /dev/null
+++ b/bigbluebutton-html5/imports/utils/slideCalcUtils.js
@@ -0,0 +1,63 @@
+const HUNDRED_PERCENT = 100;
+const MYSTERY_NUM = 2;
+export default class SlideCalcUtil {
+  // After lots of trial and error on why synching doesn't work properly, I found I had to 
+  // multiply the coordinates by 2. There's something I don't understand probably on the
+  // canvas coordinate system. (ralam feb 22, 2012)
+
+  /**
+   * Calculate the viewed region width
+   */
+  static calcViewedRegionWidth(vpw, cpw) {
+    const width = (vpw / cpw) * HUNDRED_PERCENT;
+    if (width > HUNDRED_PERCENT) {
+      return HUNDRED_PERCENT;
+    }
+    return width;
+  }
+
+  static calcViewedRegionHeight(vph, cph) {
+    const height = (vph / cph) * HUNDRED_PERCENT;
+    if (height > HUNDRED_PERCENT) {
+      return HUNDRED_PERCENT;
+    }
+    return height;
+  }
+
+  static calcCalcPageSizeWidth(ftp, vpw, vrw) {
+    if (ftp) {
+      return (vpw / vrw) * HUNDRED_PERCENT;
+    }
+      return vpw;
+  }
+
+  static calcCalcPageSizeHeight(ftp, vph, vrh, cpw, cph, opw, oph) {
+    if (ftp) {
+      return (vph / vrh) * HUNDRED_PERCENT;
+    }
+      return (cpw / opw) * oph;
+  }
+
+  static calcViewedRegionX(cpx, cpw) {
+    return (cpx * HUNDRED_PERCENT) / cpw;
+  }
+
+  static calcViewedRegionY(cpy, cph) {
+    return (cpy * HUNDRED_PERCENT) / cph;
+  }
+
+  static calculateViewportX(vpw, pw) {
+    if (vpw == pw) {
+      return 0;
+    }
+      return (pw - vpw) / MYSTERY_NUM;
+  }
+
+  static calculateViewportY(vph, ph) {
+    if (vph == ph) {
+      return 0;
+    }
+    return (ph - vph) / MYSTERY_NUM;
+    
+  }
+}
\ No newline at end of file
diff --git a/bigbluebutton-html5/imports/utils/slideViewModel.js b/bigbluebutton-html5/imports/utils/slideViewModel.js
new file mode 100644
index 0000000000000000000000000000000000000000..ad69c3f06240a606d9c908a59b0623a0c4e56218
--- /dev/null
+++ b/bigbluebutton-html5/imports/utils/slideViewModel.js
@@ -0,0 +1,289 @@
+import SlideCalcUtil from './slideCalcUtils';
+
+const MAX_ZOOM_PERCENT = 400;
+const HUNDRED_PERCENT = 100;
+const MYSTERY_NUM = 2;
+
+export default class SlideViewModel {
+  // private static const LOGGER:ILogger = getClassLogger(SlideViewModel);
+
+  constructor(vw, vh, sw, sh) {
+    this.viewportX = 0;
+    this.viewportY = 0;
+    this.viewportW = vw;
+    this.viewportH = vh;
+
+    this.loaderW = 0;
+    this.loaderH = 0;
+    this.loaderX = 0;
+    this.loaderY = 0;
+
+    this.viewedRegionX = 0;
+    this.viewedRegionY = 0;
+    this.viewedRegionW = HUNDRED_PERCENT;
+    this.viewedRegionH = HUNDRED_PERCENT;
+
+    this.pageOrigW = sw;
+    this.pageOrigH = sh;
+    this.calcPageW = 0;
+    this.calcPageH = 0;
+    this.calcPageX = 0;
+    this.calcPageY = 0;
+    this.parentW = vw;
+    this.parentH = vh;
+
+    this.fitToPage = true;
+
+    // After lots of trial and error on why synching doesn't work properly, I found I had to
+    // multiply the coordinates by 2. There's something I don't understand probably on the
+    // canvas coordinate system. (ralam feb 22, 2012)
+  }
+
+  isPortraitDoc() {
+    return this.pageOrigH > this.pageOrigW;
+  }
+
+  reset(pageWidth, pageHeight) {
+    this.pageOrigW = pageWidth;
+    this.pageOrigH = pageHeight;
+  }
+
+  resetForNewSlide(pageWidth, pageHeight) {
+    this.pageOrigW = pageWidth;
+    this.pageOrigH = pageHeight;
+  }
+  // Not used into class
+  // parentChange(parentW, parentH) {
+  //   this.viewportW = this.parentW = parentW;
+  //   this.viewportH = this.parentH = parentH;
+  // }
+
+  calculateViewportXY() {
+    this.viewportX = SlideCalcUtil.calculateViewportX(this.viewportW, this.parentW);
+    this.viewportY = SlideCalcUtil.calculateViewportY(this.viewportH, this.parentH);
+  }
+
+  calcViewedRegion() {
+    this.viewedRegionW = SlideCalcUtil.calcViewedRegionWidth(this.viewportW, this.calcPageW);
+    this.viewedRegionH = SlideCalcUtil.calcViewedRegionHeight(this.viewportH, this.calcPageH);
+    this.viewedRegionX = SlideCalcUtil.calcViewedRegionX(this.calcPageX, this.calcPageW);
+    this.viewedRegionY = SlideCalcUtil.calcViewedRegionY(this.calcPageY, this.calcPageH);
+  }
+
+  displayPresenterView() {
+    this.loaderX = Math.round(this.calcPageX);
+    this.loaderY = Math.round(this.calcPageY);
+    this.loaderW = Math.round(this.calcPageW);
+    this.loaderH = Math.round(this.calcPageH);
+  }
+
+  adjustSlideAfterParentResized() {
+    if (this.fitToPage) {
+      this.calculateViewportNeededForRegion(this.viewedRegionW, this.viewedRegionH);
+      this.displayViewerRegion(this.viewedRegionX, this.viewedRegionY, this.viewedRegionW, this.viewedRegionH);
+      this.calculateViewportXY();
+      this.displayPresenterView();
+      this.printViewedRegion();
+    } else {
+      this.calculateViewportSize();
+      this.calculateViewportXY();
+      this.calcPageW = (this.viewportW / this.viewedRegionW) * HUNDRED_PERCENT;
+      this.calcPageH = (this.pageOrigH / this.pageOrigW) * this.calcPageW;
+      this.calcViewedRegion();
+      this.doBoundsValidation();
+    }
+  }
+
+  switchToFitToPage(ftp) {
+    // LOGGER.debug("switchToFitToPage");
+
+    this.fitToPage = ftp;
+
+    this.saveViewedRegion(0, 0, 100, 100);
+
+    this.calculateViewportSize();
+    this.calculateViewportXY();
+  }
+
+  doWidthBoundsDetection() {
+    if (this.calcPageX >= 0) {
+      // Don't let the left edge move inside the view.
+      this.calcPageX = 0;
+    } else if ((this.calcPageW + this.calcPageX * MYSTERY_NUM) < this.viewportW) {
+      // Don't let the right edge move inside the view.
+      this.calcPageX = (this.viewportW - this.calcPageW) / MYSTERY_NUM;
+    } else {
+      // Let the move happen.
+    }
+  }
+
+  doHeightBoundsDetection() {
+    if (this.calcPageY >= 0) {
+      // Don't let the top edge move into the view.
+      this.calcPageY = 0;
+    } else if ((this.calcPageH + this.calcPageY * MYSTERY_NUM) < this.viewportH) {
+      // Don't let the bottome edge move into the view.
+      this.calcPageY = (this.viewportH - this.calcPageH) / MYSTERY_NUM;
+    } else {
+      // Let the move happen.
+    }
+  }
+
+  doBoundsValidation() {
+    this.doWidthBoundsDetection();
+    this.doHeightBoundsDetection();
+  }
+
+  /** Returns whether or not the page actually moved */
+  onMove(deltaX, deltaY) {
+    const oldX = this.calcPageX;
+    const oldY = this.calcPageY;
+
+    this.calcPageX += deltaX / MYSTERY_NUM;
+    this.calcPageY += deltaY / MYSTERY_NUM;
+
+    this.doBoundsValidation();
+
+    if (oldX != this.calcPageX || oldY != this.calcPageY) {
+      this.calcViewedRegion();
+      return true;
+    }
+    return false;
+  }
+
+  calculateViewportSize() {
+    this.viewportW = this.parentW;
+    this.viewportH = this.parentH;
+
+    /*
+    * For some reason when the viewport values are both whole numbers the clipping doesn't 
+    * function. When the second part of the width/height pair is rounded up and then 
+    * reduced by 0.5 the clipping always seems to happen. This was a long standing, bug 
+    * and if you try to remove the Math.ceil and "-0.5" you better know what you're doing.
+    *             - Chad (Aug 30, 2017)
+    */
+
+    if (this.fitToPage) {
+      // If the height is smaller than the width, we use the height as the base to determine the size of the slide.
+      if (this.parentH < this.parentW) {
+        this.viewportH = this.parentH;
+        this.viewportW = Math.ceil((this.pageOrigW * this.viewportH) / this.pageOrigH) - 0.5;
+        if (this.parentW < this.viewportW) {
+          this.viewportW = this.parentW;
+          this.viewportH = Math.ceil((this.pageOrigH * this.viewportW) / this.pageOrigW) - 0.5;
+        }
+      } else {
+        this.viewportW = this.parentW;
+        this.viewportH = Math.ceil((this.viewportW / this.pageOrigW) * this.pageOrigH) - 0.5;
+        if (this.parentH < this.viewportH) {
+          this.viewportH = this.parentH;
+          this.viewportW = Math.ceil((this.pageOrigW * this.viewportH) / this.pageOrigH) - 0.5;
+        }
+      }
+    } else {
+      this.viewportH = Math.ceil((this.viewportW / this.pageOrigW) * this.pageOrigH) - 0.5;
+      if (this.viewportH > this.parentH) {
+        this.viewportH = this.parentH;
+      }
+    }
+  }
+
+  printViewedRegion() {
+    			console.debug("Region [" + this.viewedRegionW + "," + this.viewedRegionH + "] [" + this.viewedRegionX + "," + this.viewedRegionY + "]");			
+    			console.debug("Region [" + ((this.viewedRegionW / HUNDRED_PERCENT)*this.calcPageW) + "," + ((this.viewedRegionH/HUNDRED_PERCENT)*this.calcPageH) + 
+    			"] [" + ((this.viewedRegionX/HUNDRED_PERCENT)*this.calcPageW) + "," + ((this.viewedRegionY/HUNDRED_PERCENT)*this.calcPageH) + "]");
+  }
+
+  onZoom(zoomValue, mouseX, mouseY) {
+
+    // Absolute x and y positions of the mouse over the (enlarged) slide:
+    let absXcoordInPage = Math.abs(this.calcPageX) * MYSTERY_NUM + mouseX;
+    let absYcoordInPage = Math.abs(this.calcPageY) * MYSTERY_NUM + mouseY;
+
+    // Relative position of mouse over the slide. For example, if your slide is 1000 pixels wide, 
+    // and your mouse has an absolute x-coordinate of 700, then relXcoordInPage will be 0.7 :
+    const relXcoordInPage = absXcoordInPage / this.calcPageW;
+    const relYcoordInPage = absYcoordInPage / this.calcPageH;
+
+    // Relative position of mouse in the view port (same as above, but with the view port):
+    const relXcoordInViewport = mouseX / this.viewportW;
+    const relYcoordInViewport = mouseY / this.viewportH;
+
+    if (this.isPortraitDoc()) {
+      if (this.fitToPage) {
+        this.calcPageH = this.viewportH * zoomValue / HUNDRED_PERCENT;
+        this.calcPageW = (this.pageOrigW / this.pageOrigH) * this.calcPageH;
+      } else {
+        this.calcPageW = this.viewportW * zoomValue / HUNDRED_PERCENT;
+        this.calcPageH = (this.calcPageW / this.pageOrigW) * this.pageOrigH;
+      }
+    } else if (this.fitToPage) {
+      this.calcPageW = this.viewportW * zoomValue / HUNDRED_PERCENT;
+      this.calcPageH = this.viewportH * zoomValue / HUNDRED_PERCENT;
+    } else {
+      this.calcPageW = this.viewportW * zoomValue / HUNDRED_PERCENT;
+      this.calcPageH = (this.calcPageW / this.pageOrigW) * this.pageOrigH;
+    }
+
+
+    absXcoordInPage = relXcoordInPage * this.calcPageW;
+    absYcoordInPage = relYcoordInPage * this.calcPageH;
+
+    this.calcPageX = -((absXcoordInPage - mouseX) / MYSTERY_NUM);
+    this.calcPageY = -((absYcoordInPage - mouseY) / MYSTERY_NUM);
+
+    this.doWidthBoundsDetection();
+    this.doHeightBoundsDetection();
+
+    this.calcViewedRegion();
+    this.printViewedRegion();
+  }
+
+  displayViewerRegion(x, y, regionW, regionH) {
+    // LogUtil.debug("** disp viewer 1 [" + regionW + "," + regionH + "][" + x + "," + y + "]");
+    this.calcPageW = this.viewportW / (regionW / HUNDRED_PERCENT);
+    this.calcPageH = this.viewportH / (regionH / HUNDRED_PERCENT);
+    this.calcPageX = (x / HUNDRED_PERCENT) * this.calcPageW;
+    this.calcPageY = (y / HUNDRED_PERCENT) * this.calcPageH;
+    // LogUtil.debug("** disp viewer 2 [" + viewportW + "," + viewportH + "]
+    // [" +_calcPageW + "," + _calcPageH + "][" + _calcPageX + "," + _calcPageY + "]");
+  }
+
+  saveViewedRegion(x, y, regionW, regionH) {
+    this.viewedRegionX = x;
+    this.viewedRegionY = y;
+    this.viewedRegionW = regionW;
+    this.viewedRegionH = regionH;
+  }
+
+  calculateViewportNeededForRegion(regionW, regionH) {
+    const vrwp = this.pageOrigW * (regionW / HUNDRED_PERCENT);
+    const vrhp = this.pageOrigH * (regionH / HUNDRED_PERCENT);
+
+    /*
+    * For some reason when the viewport values are both whole numbers the clipping doesn't 
+    * function. When the second part of the width/height pair is rounded up and then 
+    * reduced by 0.5 the clipping always seems to happen. This was a long standing, bug 
+    * and if you try to remove the Math.ceil and "-0.5" you better know what you're doing.
+    *             - Chad (Aug 30, 2017)
+    */
+
+    if (this.parentW < this.parentH) {
+      this.viewportW = this.parentW;
+      this.viewportH = Math.ceil((vrhp / vrwp) * this.parentW) - 0.5;
+      if (this.parentH < this.viewportH) {
+        this.viewportH = this.parentH;
+        this.viewportW = Math.ceil((vrwp * this.viewportH) / vrhp) - 0.5;
+      }
+    } else {
+      this.viewportH = this.parentH;
+      this.viewportW = Math.ceil((vrwp / vrhp) * this.parentH) - 0.5;
+      if (this.parentW < this.viewportW) {
+        this.viewportW = this.parentW;
+        this.viewportH = Math.ceil((vrhp * this.viewportW) / vrwp) - 0.5;
+      }
+    }
+  // LOGGER.debug("calc viewport ***** resizing [" + viewportW + "," + viewportH + "] 
+  // [" + parentW + "," + parentH + "," + fitToPage + "] [" + pageOrigW + "," + pageOrigH + "]");
+  }
+}