# "Paper" which is the Raphael term for the entire SVG object on the webpage. # This class deals with this SVG component only. class @WhiteboardPaperModel # Container must be a DOM element constructor: (@container) -> # a WhiteboardCursorModel @cursor = null # all slides in the presentation indexed by url @slides = {} @fitToPage = true @panX = null @panY = null @current = {} # the slide being shown @current.slide = null # a raphaeljs set with all the shapes in the current slide @current.shapes = null # a list of shapes as passed to this client when it receives `all_slides` # (se we are able to redraw the shapes whenever needed) @current.shapeDefinitions = [] @zoomLevel = 1 @shiftPressed = false @currentPathCount = 0 # $container = $('#whiteboard-paper') # @containerWidth = $container.innerWidth() # @containerHeight = $container.innerHeight() @_updateContainerDimensions() # $(window).on "resize.whiteboard_paper", _.bind(@_onWindowResize, @) # $(document).on "keydown.whiteboard_paper", _.bind(@_onKeyDown, @) # $(document).on "keyup.whiteboard_paper", _.bind(@_onKeyUp, @) # Bind to the event triggered when the client connects to the server # if globals.connection.isConnected() # @_registerEvents() # else # globals.events.on "connection:connected", => # @_registerEvents() @zoomObserver = null @adjustedWidth = 0 @adjustedHeight = 0 # Override the close() to unbind events. unbindEvents: -> $(window).off "resize.whiteboard_paper" $(document).off "keydown.whiteboard_paper" $(document).off "keyup.whiteboard_paper" # TODO: other events are being used in the code and should be off() here # Initializes the paper in the page. # Can't do these things in initialize() because by then some elements # are not yet created in the page. create: -> # paper is embedded within the div#slide of the page. # @raphaelObj ?= ScaleRaphael(@container, "900", "500") h = $("#"+@container).height() w = $("#"+@container).width() #console.log "h: #{h}" #console.log "w: #{w}" # @raphaelObj ?= ScaleRaphael(@container, "900", "500") @raphaelObj ?= ScaleRaphael(@container, w, h) # $container = $('#whiteboard-contents') @raphaelObj ?= ScaleRaphael(@container, $container.innerHeight(), $container.innerWidth()) @raphaelObj.canvas.setAttribute "preserveAspectRatio", "xMinYMin slice" @createCursor() #@cursor.on "cursor:mousewheel", _.bind(@_zoomSlide, @) if @slides @rebuild() else @slides = {} # if previously loaded unless navigator.userAgent.indexOf("Firefox") is -1 @raphaelObj.renderfix() # initializing border around slide to cover up areas which shouldnt show # @borders = {} # for border in ['left', 'right', 'top', 'bottom'] # @borders[border] = @raphaelObj.rect(0, 0, 0, 0) # @borders[border].attr("fill", "#ababab") # @borders[border].attr( {stroke:"#ababab"} ) @raphaelObj # Re-add the images to the paper that are found # in the slides array (an object of urls and dimensions). rebuild: -> @current.slide = null for url of @slides if @slides.hasOwnProperty(url) @addImageToPaper url, @slides[url].getWidth(), @slides[url].getHeight() # A wrapper around ScaleRaphael's `changeSize()` method, more details at: # http://www.shapevent.com/scaleraphael/ # Also makes sure that the images are redraw in the canvas so they are actually resized. changeSize: (windowWidth, windowHeight, center=true, clipping=false) -> if @raphaelObj? @raphaelObj.changeSize(windowWidth, windowHeight, center, clipping) # TODO: we can scale the slides and drawings instead of re-adding them, but the logic # will change quite a bit # slides slidesTmp = _.clone(@slides) urlTmp = @current.slide @removeAllImagesFromPaper() @slides = slidesTmp @rebuild() @showImageFromPaper(urlTmp?.url) # drawings tmp = _.clone(@current.shapeDefinitions) @clearShapes() @drawListOfShapes(tmp) scale: (width, height) -> @raphaelObj?.changeSize(width, height) # Add an image to the paper. # @param {string} url the URL of the image to add to the paper # @param {number} width the width of the image (in pixels) # @param {number} height the height of the image (in pixels) # @return {Raphael.image} the image object added to the whiteboard addImageToPaper: (url, width, height) -> @_updateContainerDimensions() if @fitToPage # solve for the ratio of what length is going to fit more than the other max = Math.max(width / @containerWidth, height / @containerHeight) # fit it all in appropriately # TODO: temporary solution url = @_slideUrl(url) sw = width / max sh = height / max cx = (@containerWidth / 2) - (width / 2) cy = (@containerHeight / 2) - (height / 2) img = @raphaelObj.image(url, cx, cy, width, height) originalWidth = width originalHeight = height else # fit to width alert "no fit" # assume it will fit width ways sw = width / wr sh = height / wr wr = width / @containerWidth originalWidth = sw originalHeight = sh sw = width / wr sh = height / wr img = @raphaelObj.image(url, cx = 0, cy = 0, sw, sh) # sw slide width as percentage of original width of paper # sh slide height as a percentage of original height of paper # x-offset from top left corner as percentage of original width of paper # y-offset from top left corner as percentage of original height of paper @slides[url] = new WhiteboardSlideModel(img.id, url, img, originalWidth, originalHeight, sw, sh, cx, cy) unless @current.slide? img.toBack() @current.slide = @slides[url] else if @current.slide.url is url img.toBack() else img.hide() $(@container).on "mousemove", _.bind(@_onMouseMove, @) $(@container).on "mousewheel", _.bind(@_zoomSlide, @) # TODO $(img.node).bind "mousewheel", zoomSlide #@trigger('paper:image:added', img) # TODO: other places might also required an update in these dimensions @_updateContainerDimensions() img # Removes all the images from the Raphael paper. removeAllImagesFromPaper: -> for url of @slides if @slides.hasOwnProperty(url) @raphaelObj.getById(@slides[url]?.getId())?.remove() @trigger('paper:image:removed', @slides[url].getId()) # Removes the previous image preventing images from being redrawn over each other repeatedly @slides = {} @current.slide = null # Shows an image from the paper. # The url must be in the slides array. # @param {string} url the url of the image (must be in slides array) showImageFromPaper: (url) -> # TODO: temporary solution url = @_slideUrl(url) if not @current.slide? or (@slides[url]? and @current.slide.url isnt url) @_hideImageFromPaper(@current.slide.url) if @current.slide? next = @_getImageFromPaper(url) if next next.show() next.toFront() @current.shapes.forEach (element) -> element.toFront() @cursor.toFront() @current.slide = @slides[url] # Updates the paper from the server values. # @param {number} cx_ the x-offset value as a percentage of the original width # @param {number} cy_ the y-offset value as a percentage of the original height # @param {number} sw_ the slide width value as a percentage of the original width # @param {number} sh_ the slide height value as a percentage of the original height # TODO: not working as it should updatePaperFromServer: (cx_, cy_, sw_, sh_) -> # # if updating the slide size (zooming!) # [slideWidth, slideHeight] = @_currentSlideOriginalDimensions() # if sw_ and sh_ # @raphaelObj.setViewBox cx_ * slideWidth, cy_ * slideHeight, sw_ * slideWidth, sh_ * slideHeight, # sw = slideWidth / sw_ # sh = slideHeight / sh_ # # just panning, so use old slide size values # else # [sw, sh] = @_currentSlideDimensions() # @raphaelObj.setViewBox cx_ * slideWidth, cy_ * slideHeight, @raphaelObj._viewBox[2], @raphaelObj._viewBox[3] # # update corners # cx = cx_ * sw # cy = cy_ * sh # # update position of svg object in the window # sx = (@containerWidth - slideWidth) / 2 # sy = (@containerHeight - slideHeight) / 2 # sy = 0 if sy < 0 # @raphaelObj.canvas.style.left = sx + "px" # @raphaelObj.canvas.style.top = sy + "px" # @raphaelObj.setSize slideWidth - 2, slideHeight - 2 # # update zoom level and cursor position # z = @raphaelObj._viewBox[2] / slideWidth # @zoomLevel = z # dcr = 1 # @cursor.setRadius(dcr * z) # # force the slice attribute despite Raphael changing it # @raphaelObj.canvas.setAttribute "preserveAspectRatio", "xMinYMin slice" # Switches the tool and thus the functions that get # called when certain events are fired from Raphael. # @param {string} tool the tool to turn on # @return {undefined} setCurrentTool: (tool) -> @currentTool = tool console.log "setting current tool to", tool switch tool when "line" @cursor.undrag() @current.line = @_createTool(tool) @cursor.drag(@current.line.dragOnMove, @current.line.dragOnStart, @current.line.dragOnEnd) when "rectangle" @cursor.undrag() @current.rectangle = @_createTool(tool) @cursor.drag(@current.rectangle.dragOnMove, @current.rectangle.dragOnStart, @current.rectangle.dragOnEnd) # TODO: the shapes below are still in the old format # when "panzoom" # @cursor.undrag() # @cursor.drag _.bind(@_panDragging, @), # _.bind(@_panGo, @), _.bind(@_panStop, @) # when "ellipse" # @cursor.undrag() # @cursor.drag _.bind(@_ellipseDragging, @), # _.bind(@_ellipseDragStart, @), _.bind(@_ellipseDragStop, @) # when "text" # @cursor.undrag() # @cursor.drag _.bind(@_rectDragging, @), # _.bind(@_textStart, @), _.bind(@_textStop, @) else console.log "ERROR: Cannot set invalid tool:", tool # Sets the fit to page. # @param {boolean} value If true fit to page. If false fit to width. # TODO: not really working as it should be setFitToPage: (value) -> @fitToPage = value # TODO: we can scale the slides and drawings instead of re-adding them, but the logic # will change quite a bit temp = @slides @removeAllImagesFromPaper() @slides = temp # re-add all the images as they should fit differently @rebuild() # set to default zoom level #globals.connection.emitPaperUpdate 0, 0, 1, 1 # get the shapes to reprocess #globals.connection.emitAllShapes() # Socket response - Update zoom variables and viewbox # @param {number} d the delta value from the scroll event # @return {undefined} setZoom: (d) -> step = 0.05 # step size if d < 0 @zoomLevel += step # zooming out else @zoomLevel -= step # zooming in [sw, sh] = @_currentSlideDimensions() [cx, cy] = @_currentSlideOffsets() x = cx / sw y = cy / sh # cannot zoom out further than 100% z = (if @zoomLevel > 1 then 1 else @zoomLevel) # cannot zoom in further than 400% (1/4) z = (if z < 0.25 then 0.25 else z) # cannot zoom to make corner less than (x,y) = (0,0) x = (if x < 0 then 0 else x) y = (if y < 0 then 0 else y) # cannot view more than the bottom corners zz = 1 - z x = (if x > zz then zz else x) y = (if y > zz then zz else y) #globals.connection.emitPaperUpdate x, y, z, z # send update to all clients stopPanning: -> # nothing to do # Draws an array of shapes to the paper. # @param {array} shapes the array of shapes to draw drawListOfShapes: (shapes) -> @current.shapeDefinitions = shapes @current.shapes = @raphaelObj.set() for shape in shapes shapeType = shape?.shape?.shape_type dataBlock = shape?.shape?.shape data = if _.isString(dataBlock) then JSON.parse(dataBlock) else dataBlock tool = @_createTool(shapeType) if tool? @current.shapes.push tool.draw.apply(tool, data) else console.log "shape not recognized at drawListOfShapes", shape # make sure the cursor is still on top @cursor.toFront() #Changes the currently displayed presentation (if any) with this one #@param {object} containing the "presentation" object -id,name,pages[] sharePresentation: (data) -> #globals.events.trigger("connection:all_slides", data.payload) # Clear all shapes from this paper. clearShapes: -> if @current.shapes? @current.shapes.forEach (element) -> element.remove() @currentShapes = [] @currentShapesDefinitions = [] @clearCursor() clearCursor: -> @cursor?.remove() createCursor: -> @cursor = new WhiteboardCursorModel(@raphaelObj) @cursor.draw() # Updated a shape `shape` with the data in `data`. # TODO: check if the objects exist before calling update, if they don't they should be created updateShape: (shape, data) -> @current[shape].update(data) # Make a shape `shape` with the data in `data`. makeShape: (shape, data) -> tool = null @current[shape] = @_createTool(shape) toolModel = @current[shape] tool = @current[shape].make(data) if tool? @current.shapes ?= @raphaelObj.set() @current.shapes.push(tool) @current.shapeDefinitions.push(toolModel.getDefinition()) # Update the cursor position on screen # @param {number} x the x value of the cursor as a percentage of the width # @param {number} y the y value of the cursor as a percentage of the height moveCursor: (x, y) -> [cx, cy] = @_currentSlideOffsets() [slideWidth, slideHeight] = @_currentSlideOriginalDimensions() @cursor.setPosition(x * slideWidth + cx, y * slideHeight + cy) #if the slide is zoomed in then move the cursor based on where the viewBox is looking if @viewBoxXpos? && @viewBoxYPos? && @viewBoxWidth? && @viewBoxHeight? @cursor.setPosition( @viewBoxXpos + x * @viewBoxWidth, @viewBoxYPos + y * @viewBoxHeight ) # Update the slide to move and zoom # @param {number} xOffset the x value of offset # @param {number} yOffset the y value of offset # @param {number} widthRatio the ratio of the previous width # @param {number} heightRatio the ratio of the previous height moveAndZoom: (xOffset, yOffset, widthRatio, heightRatio) -> @globalxOffset = xOffset @globalyOffset = yOffset @globalwidthRatio = widthRatio @globalheightRatio = heightRatio [slideWidth, slideHeight] = @_currentSlideOriginalDimensions() #console.log("xOffset: " + xOffset + ", yOffset: " + yOffset); #console.log("@containerWidth: " + @containerWidth + " @containerHeight: " + @containerHeight); #console.log("slideWidth: " + slideWidth + " slideHeight: " + slideHeight); baseWidth = (@containerWidth - slideWidth) / 2 baseHeight = (@containerHeight - slideHeight) / 2 #get the actual size of the slide, depending on the limiting factor (container width or container height) actualWidth = @current.slide.displayWidth actualHeight = @current.slide.displayHeight #console.log("actualWidth:" + actualWidth + " actualHeight: " + actualHeight) #calculate parameters to pass newXPos = baseWidth - 2* xOffset * actualWidth / 100 newyPos = baseHeight - 2* yOffset * actualHeight / 100 newWidth = actualWidth / 100 * widthRatio newHeight = actualHeight / 100 * heightRatio @viewBoxXpos = newXPos @viewBoxYPos = newyPos @viewBoxWidth = newWidth @viewBoxHeight = newHeight #console.log("newXPos: " + newXPos + " newyPos: " + newyPos + " newWidth: " + newWidth + " newHeight: " + newHeight) #set parameters to raphael viewbox @raphaelObj.setViewBox(newXPos , newyPos, newWidth , newHeight , true) # update the rectangle elements which create the border when page is zoomed @borders.left.attr( {width:newXPos, height: @containerHeight} ) @borders.right.attr( x: newXPos + newWidth y: 0 width:newXPos height:@containerHeight ) @borders.top.attr( width: @containerWidth height: newyPos ) @borders.bottom.attr( y: newyPos + newHeight width: @containerWidth height: @containerHeight ) # borders should appear infront of every other element (i.e. shapes) for _, border of @borders border.toFront() #update cursor to appear the same size even when page is zoomed in @cursor.setRadius( 3 * widthRatio / 100 ) zoomAndPan: (widthRatio, heightRatio, xOffset, yOffset) -> newX = - xOffset * 2 * @adjustedWidth / 100 newY = - yOffset * 2 * @adjustedHeight / 100 newWidth = @adjustedWidth * widthRatio / 100 newHeight = @adjustedHeight * heightRatio / 100 @raphaelObj.setViewBox(newX, newY, newWidth, newHeight) # zooms and pans # Registers listeners for events in the gloval event bus _registerEvents: -> # globals.events.on "connection:whiteboardDrawPen", (startingData) => # type = startingData.payload.shape_type # color = startingData.payload.data.line.color # thickness = startingData.payload.data.line.weight # points = startingData.shape.points # if type is "line" # for i in [0..points.length - 1] # if i is 0 # #make these compatible with a line # console.log "points[i]: " + points[i] # lineObject = { # shape: { # type: "line", # coordinate: { # firstX : points[i].x/100, # firstY : points[i].y/100 # }, # color: startingData.payload.data.line.color, # thickness : startingData.payload.data.line.weight # } # adding : false #tell the line object that we are NOT adding points but creating a new line # } # console.log "lineObject: " + lineObject # @makeShape type, lineObject # else # console.log "points[i]: "+ points[i] # lineObject = { # shape: { # type: "line", # coordinate: { # firstX : points[i].x/100, # firstY : points[i].y/100 # }, # color: startingData.payload.data.line.color, # thickness : startingData.payload.data.line.weight # } # adding : true #tell the line object that we ARE adding points and NOT creating a new line # } # console.log "lineObject: " + lineObject # @updateShape type, lineObject # globals.events.on "connection:move_and_zoom", (xOffset, yOffset, widthRatio, heightRatio) => # @moveAndZoom(xOffset, yOffset, widthRatio, heightRatio) # globals.events.on "connection:changeslide", (url) => # @showImageFromPaper(url) # globals.events.on "connection:viewBox", (xperc, yperc, wperc, hperc) => # xperc = parseFloat(xperc, 10) # yperc = parseFloat(yperc, 10) # wperc = parseFloat(wperc, 10) # hperc = parseFloat(hperc, 10) # @updatePaperFromServer(xperc, yperc, wperc, hperc) # globals.events.on "connection:fitToPage", (value) => # @setFitToPage(value) # globals.events.on "connection:zoom", (delta) => # @setZoom(delta) # globals.events.on "connection:paper", (cx, cy, sw, sh) => # @updatePaperFromServer(cx, cy, sw, sh) # globals.events.on "connection:panStop", => # @stopPanning() # globals.events.on "connection:toolChanged", (tool) => # @setCurrentTool(tool) # globals.events.on "connection:textDone", => # @textDone() # globals.events.on "connection:uploadStatus", (message, fade) => # globals.events.trigger("whiteboard:paper:uploadStatus", message, fade) # Update the dimensions of the container. _updateContainerDimensions: -> #console.log "update Container Dimensions" $container = $('#whiteboard-paper') @containerWidth = $container.innerWidth() @containerHeight = $container.innerHeight() @containerOffsetLeft = $container.offset()?.left @containerOffsetTop = $container.offset()?.top # Retrieves an image element from the paper. # The url must be in the slides array. # @param {string} url the url of the image (must be in slides array) # @return {Raphael.image} return the image or null if not found _getImageFromPaper: (url) -> if @slides[url] id = @slides[url].getId() return @raphaelObj.getById(id) if id? null # Hides an image from the paper given the URL. # The url must be in the slides array. # @param {string} url the url of the image (must be in slides array) _hideImageFromPaper: (url) -> img = @_getImageFromPaper(url) img.hide() if img? # Update zoom variables on all clients # @param {Event} e the event that occurs when scrolling # @param {number} delta the speed/direction at which the scroll occurred _zoomSlide: (e, delta) -> #globals.connection.emitZoom delta # Called when the cursor is moved over the presentation. # Sends cursor moving event to server. # @param {Event} e the mouse event # @param {number} x the x value of cursor at the time in relation to the left side of the browser # @param {number} y the y value of cursor at the time in relation to the top of the browser # TODO: this should only be done if the user is the presenter _onMouseMove: (e, x, y) -> [sw, sh] = @_currentSlideDimensions() xLocal = (e.pageX - @containerOffsetLeft) / sw yLocal = (e.pageY - @containerOffsetTop) / sh #globals.connection.emitMoveCursor xLocal, yLocal # When the user is dragging the cursor (click + move) # @param {number} dx the difference between the x value from panGo and now # @param {number} dy the difference between the y value from panGo and now _panDragging: (dx, dy) -> [slideWidth, slideHeight] = @_currentSlideOriginalDimensions() sx = (@containerWidth - slideWidth) / 2 sy = (@containerHeight - slideHeight) / 2 [sw, sh] = @_currentSlideDimensions() # ensuring that we cannot pan outside of the boundaries x = (@panX - dx) # cannot pan past the left edge of the page x = (if x < 0 then 0 else x) y = (@panY - dy) # cannot pan past the top of the page y = (if y < 0 then 0 else y) if @fitToPage x2 = slideWidth + x else x2 = @containerWidth + x # cannot pan past the width x = (if x2 > sw then sw - (@containerWidth - sx * 2) else x) if @fitToPage y2 = slideHeight + y else # height of image could be greater (or less) than the box it fits in y2 = @containerHeight + y # cannot pan below the height y = (if y2 > sh then sh - (@containerHeight - sy * 2) else y) #globals.connection.emitPaperUpdate x / sw, y / sh, null, null # When panning starts # @param {number} x the x value of the cursor # @param {number} y the y value of the cursor _panGo: (x, y) -> [cx, cy] = @_currentSlideOffsets() @panX = cx @panY = cy # When panning finishes # @param {Event} e the mouse event _panStop: (e) -> @stopPanning() # Called when the application window is resized. _onWindowResize: -> @_updateContainerDimensions() console.log "_onWindowResize" #TODO: temporary hacked away fix so that the buttons resize correctly when the window resizes $("#users-btn").click(); $("#users-btn").click(); #TODO: maybe find solution besides these global values..no conflicts however [slideWidth, slideHeight] = @_currentSlideOriginalDimensions() #console.log("xOffset: " + xOffset + ", yOffset: " + yOffset); #console.log("@containerWidth: " + @containerWidth + " @containerHeight: " + @containerHeight); #console.log("slideWidth: " + slideWidth + " slideHeight: " + slideHeight); baseWidth = (@containerWidth - slideWidth) / 2 baseHeight = (@containerHeight - slideHeight) / 2 #get the actual size of the slide, depending on the limiting factor (container width or container height) if(@containerWidth - slideWidth < @containerHeight - slideHeight) actualHeight = @containerWidth * slideHeight / slideWidth actualWidth = @containerWidth else actualWidth = @containerHeight * slideWidth / slideHeight actualHeight = @containerHeight #console.log("actualWidth:" + actualWidth + " actualHeight: " + actualHeight) #calculate parameters to pass newXPos = baseWidth newyPos = baseHeight newWidth = actualWidth newHeight = actualHeight #now the zooming will still be correct when the window is resized #and hopefully when rotated on a mobile device if @globalxOffset? && @globalyOffset? && @globalwidthRatio? && @globalheightRatio? console.log "has zoomed in" @moveAndZoom(@globalxOffset, @globalyOffset, @globalwidthRatio, @globalheightRatio) else obj = globalxOffset : @globalxOffset globalyOffset : @globalyOffset globalwidthRatio : @globalwidthRatio globalheightRatio : @globalheightRatio console.log obj console.log "not zoomed" @raphaelObj.setViewBox(newXPos, newyPos, newWidth, newHeight,true) # when pressing down on a key at anytime _onKeyDown: (event) -> unless event keyCode = window.event.keyCode else keyCode = event.keyCode switch keyCode when 16 # shift key @shiftPressed = true # when releasing any key at any time _onKeyUp: -> unless event keyCode = window.event.keyCode else keyCode = event.keyCode switch keyCode when 16 # shift key @shiftPressed = false _currentSlideDimensions: -> if @current.slide? then @current.slide.getDimensions() else [0, 0] _currentSlideOriginalDimensions: -> if @current.slide? then @current.slide.getOriginalDimensions() else [0, 0] _currentSlideOffsets: -> if @current.slide? then @current.slide.getOffsets() else [0, 0] # Wrapper method to create a tool for the whiteboard _createTool: (type) -> switch type when "pencil" model = WhiteboardLineModel when "path", "line" model = WhiteboardLineModel when "rectangle" model = WhiteboardRectModel when "ellipse" model = WhiteboardEllipseModel when "triangle" model = WhiteboardTriangleModel when "text" model = WhiteboardTextModel if model? [slideWidth, slideHeight] = @_currentSlideOriginalDimensions() [xOffset, yOffset] = @_currentSlideOffsets() [width, height] = @_currentSlideDimensions() tool = new model(@raphaelObj) # TODO: why are the parameters inverted and it works? tool.setPaperSize(slideHeight, slideWidth) tool.setOffsets(xOffset, yOffset) tool.setPaperDimensions(width,height) tool else null # Adds the base url (the protocol+server part) to `url` if needed. _slideUrl: (url) -> if url?.match(/http[s]?:/) url else console.log "The url '#{url}'' did not match the expected format of: http/s" #globals.presentationServer + url #Changes the currently displayed page/slide (if any) with this one #@param {data} message object containing the "presentation" object _displayPage: (data, originalWidth, originalHeight) -> @removeAllImagesFromPaper() # get dimensions for available whiteboard space # get where to start from the left -> either the end of the user's list or the left edge of the screen # if getInSession "display_usersList" then xBegin = $("#userListContainer").width() # else xBegin = 0 # # get where to start from the right -> either the beginning of the chat bar or the right edge of the screen # if getInSession "display_chatbar" then xEnd = $("#chat").position().left # else xEnd = $( document ).width(); # # find the height to start the top of the image at # if getInSession "display_navbar" then yBegin = $("#navbar").height() # else yBegin = 0 # yEnd = $( document ).height(); # # TODO: add some form of padding to the left, right, top, and bottom boundaries # # # boardWidth = xEnd - xBegin # boardHeight = yEnd - yBegin boardWidth = @containerWidth boardHeight = @containerHeight currentSlide = getCurrentSlideDoc() # TODO currentSlide undefined in some cases - will check later why imageWidth = boardWidth * (currentSlide?.slide.width_ratio/100) or boardWidth imageHeight = boardHeight * (currentSlide?.slide.height_ratio/100) or boardHeight #alert("_displayPage") # console.log "xBegin: #{xBegin}" # console.log "xEnd: #{xEnd}" # console.log "yBegin: #{yBegin}" # console.log "yEnd: #{yEnd}" # console.log "boardWidth: #{boardWidth}" # console.log "boardHeight: #{boardHeight}" console.log "imageWidth: #{imageWidth}" console.log "imageHeight: #{imageHeight}" currentPresentation = Meteor.Presentations.findOne({"presentation.current": true}) presentationId = currentPresentation?.presentation?.id currentSlideCursor = Meteor.Slides.find({"presentationId": presentationId, "slide.current": true}) if @zoomObserver isnt null @zoomObserver.stop() _this = this @zoomObserver = currentSlideCursor.observe # watching the current slide changes changed: (newDoc, oldDoc) -> if originalWidth <= originalHeight @adjustedWidth = boardHeight * originalWidth / originalHeight @adjustedHeight = boardHeight else @adjustedHeight = boardWidth * originalHeight / originalWidth @adjustedWidth = boardWidth _this.zoomAndPan(newDoc.slide.width_ratio, newDoc.slide.height_ratio, newDoc.slide.x_offset, newDoc.slide.y_offset) oldRatio = (oldDoc.slide.width_ratio + oldDoc.slide.height_ratio) / 2 newRatio = (newDoc.slide.width_ratio + newDoc.slide.height_ratio) / 2 _this?.currentShapes?.forEach (shape) -> shape.attr "stroke-width", shape.attr('stroke-width') * oldRatio / newRatio if originalWidth <= originalHeight # square => boardHeight is the shortest side @adjustedWidth = boardHeight * originalWidth / originalHeight $('#whiteboard-paper').width(@adjustedWidth) @addImageToPaper(data, @adjustedWidth, boardHeight) @adjustedHeight = boardHeight else @adjustedHeight = boardWidth * originalHeight / originalWidth $('#whiteboard-paper').height(@adjustedHeight) @addImageToPaper(data, boardWidth, @adjustedHeight) @adjustedWidth = boardWidth @zoomAndPan(currentSlide.slide.width_ratio, currentSlide.slide.height_ratio, currentSlide.slide.x_offset, currentSlide.slide.y_offset)