format: png dpi: 96 layout-disposition: bg-el-norepeat layout-position-anchor: tl Hello World flow text which wraps UPPER Multi linetextFOO Grouped text // Copyright 2008, 2009 Hannes Hochreiner // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see http://www.gnu.org/licenses/. // Add event listener for initialisation. document.addEventListener("DOMContentLoaded", jessyInk_core_mouseHandler_zoomControl_init, false); /** Initialisation function. * * This function looks for the objects of the appropriate sub-type and hands them to another function that will add the required methods. */ function jessyInk_core_mouseHandler_zoomControl_init() { var elems = document.getElementsByTagNameNS("https://launchpad.net/jessyink", "mousehandler"); for (var counter = 0; counter < elems.length; counter++) { if (elems[counter].getAttributeNS("https://launchpad.net/jessyink", "subtype") == "jessyInk_core_mouseHandler_zoomControl") jessyInk_core_mouseHandler_zoomControl(elems[counter]); } } /** Function to initialise an object. * * @param obj Object to be initialised. */ function jessyInk_core_mouseHandler_zoomControl(obj) { // Last dragging position. obj.dragging_last; // Flag to indicate whether dragging is active currently. obj.dragging_active = false; // Flag to indicate whether dragging is working currently. obj.dragging_working = false; // Flag to indicate whether the user clicked. obj.click = false; /** Function supplying a custom mouse handler. * * @returns A dictionary containing the new mouse handler functions. */ obj.getMouseHandler = function () { var handlerDictio = new Object(); handlerDictio[SLIDE_MODE] = new Object(); handlerDictio[SLIDE_MODE][MOUSE_DOWN] = obj.mousedown; handlerDictio[SLIDE_MODE][MOUSE_MOVE] = obj.mousemove; handlerDictio[SLIDE_MODE][MOUSE_UP] = obj.mouseup; handlerDictio[SLIDE_MODE][MOUSE_WHEEL] = obj.mousewheel; return handlerDictio; } /** Event handler for mouse clicks. * * @param e Event object. */ obj.mouseclick = function (e) { var elem = obj.getAdHocViewBbox(slides[activeSlide]["viewGroup"], obj.getCoords(e)); processingEffect = true; effectArray = new Array(); effectArray[0] = new Object(); effectArray[0]["effect"] = "view"; effectArray[0]["dir"] = 1; effectArray[0]["element"] = slides[activeSlide]["viewGroup"]; effectArray[0]["options"] = new Object(); effectArray[0]["options"]["length"] = 200; if (elem == null) effectArray[0]["options"]["matrixNew"] = (new matrixSVG()).fromSVGElements(1, 0, 0, 1, 0, 0); else effectArray[0]["options"]["matrixNew"] = obj.pointMatrixToTransformation(obj.rectToMatrix(elem)).mult((new matrixSVG()).fromSVGMatrix(slides[activeSlide].viewGroup.getScreenCTM()).inv().mult((new matrixSVG()).fromSVGMatrix(elem.parentNode.getScreenCTM())).inv()); transCounter = 0; startTime = (new Date()).getTime(); lastFrameTime = null; effect(1); return false; } /** Function to search for the element the user clicked on. * * This function searches for the element with the highest z-order, which encloses the point the user clicked on * and which view box fits entierly into the currently visible part of the slide. * * @param elem Element to start the search from. * @param pnt Point where the user clicked. * @returns The element the user clicked on or null, if no element could be found. */ obj.getAdHocViewBbox = function (elem, pnt) { var children = elem.childNodes; for (var counter = 0; counter < children.length; counter++) { if (children[counter].getBBox) { var childPointList = obj.projectRect(children[counter].getBBox(), children[counter].getScreenCTM()); var viewBbox = document.documentElement.createSVGRect(); viewBbox.x = 0.0; viewBbox.y = 0.0; viewBbox.width = WIDTH; viewBbox.height = HEIGHT; var screenPointList = obj.projectRect(viewBbox, slides[activeSlide]["element"].getScreenCTM()); if (obj.pointsWithinRect([pnt], childPointList) && obj.pointsWithinRect(childPointList, screenPointList)) return children[counter]; child = obj.getAdHocViewBbox(children[counter], pnt); if (child != null) return child; } } return null; } /** Function to project a rectangle using the projection matrix supplied. * * @param rect The rectangle to project. * @param projectionMatrix The projection matrix. * @returns A list of the four corners of the projected rectangle starting from the upper left corner and going counter-clockwise. */ obj.projectRect = function (rect, projectionMatrix) { var pntUL = document.documentElement.createSVGPoint(); pntUL.x = rect.x; pntUL.y = rect.y; pntUL = pntUL.matrixTransform(projectionMatrix); var pntLL = document.documentElement.createSVGPoint(); pntLL.x = rect.x; pntLL.y = rect.y + rect.height; pntLL = pntLL.matrixTransform(projectionMatrix); var pntUR = document.documentElement.createSVGPoint(); pntUR.x = rect.x + rect.width; pntUR.y = rect.y; pntUR = pntUR.matrixTransform(projectionMatrix); var pntLR = document.documentElement.createSVGPoint(); pntLR.x = rect.x + rect.width; pntLR.y = rect.y + rect.height; pntLR = pntLR.matrixTransform(projectionMatrix); return [pntUL, pntLL, pntUR, pntLR]; } /** Function to determine whether all the points supplied in a list are within a rectangle. * * @param pnts List of points to check. * @param pointList List of points representing the four corners of the rectangle. * @return True, if all points are within the rectangle; false, otherwise. */ obj.pointsWithinRect = function (pnts, pointList) { var pntUL = pointList[0]; var pntLL = pointList[1]; var pntUR = pointList[2]; var matrixOrig = (new matrixSVG()).fromElements(pntUL.x, pntLL.x, pntUR.x, pntUL.y, pntLL.y, pntUR.y, 1, 1, 1); var matrixProj = (new matrixSVG()).fromElements(0, 0, 1, 0, 1, 0, 1, 1, 1); var matrixProjection = matrixProj.mult(matrixOrig.inv()); for (var blockCounter = 0; blockCounter < Math.ceil(pnts.length / 3.0); blockCounter++) { var subPnts = new Array(); for (var pntCounter = 0; pntCounter < 3.0; pntCounter++) { if (blockCounter * 3.0 + pntCounter < pnts.length) subPnts[pntCounter] = pnts[blockCounter * 3.0 + pntCounter]; else { var tmpPnt = document.documentElement.createSVGPoint(); tmpPnt.x = 0.0; tmpPnt.y = 0.0; subPnts[pntCounter] = tmpPnt; } } var matrixPnt = (new matrixSVG).fromElements(subPnts[0].x, subPnts[1].x, subPnts[2].x, subPnts[0].y, subPnts[1].y, subPnts[2].y, 1, 1, 1); var matrixTrans = matrixProjection.mult(matrixPnt); for (var pntCounter = 0; pntCounter < 3.0; pntCounter++) { if (blockCounter * 3.0 + pntCounter < pnts.length) { if ((pntCounter == 0) && !((matrixTrans.e11 > 0.01) && (matrixTrans.e11 < 0.99) && (matrixTrans.e21 > 0.01) && (matrixTrans.e21 < 0.99))) return false; else if ((pntCounter == 1) && !((matrixTrans.e12 > 0.01) && (matrixTrans.e12 < 0.99) && (matrixTrans.e22 > 0.01) && (matrixTrans.e22 < 0.99))) return false; else if ((pntCounter == 2) && !((matrixTrans.e13 > 0.01) && (matrixTrans.e13 < 0.99) && (matrixTrans.e23 > 0.01) && (matrixTrans.e23 < 0.99))) return false; } } } return true; } /** Event handler for mouse movements. * * @param e Event object. */ obj.mousemove = function (e) { obj.click = false; if (!obj.dragging_active || obj.dragging_working) return false; obj.dragging_working = true; var p = obj.getCoords(e); if (slides[activeSlide].viewGroup.transform.baseVal.numberOfItems < 1) { var matrix = (new matrixSVG()).fromElements(1, 0, 0, 0, 1, 0, 0, 0, 1); } else { var matrix = (new matrixSVG()).fromSVGMatrix(slides[activeSlide].viewGroup.transform.baseVal.consolidate().matrix); } matrix.e13 += p.x - obj.dragging_last.x; matrix.e23 += p.y - obj.dragging_last.y; slides[activeSlide]["viewGroup"].setAttribute("transform", matrix.toAttribute()); obj.dragging_last = p; obj.dragging_working = false; return false; } /** Event handler for mouse down. * * @param e Event object. */ obj.mousedown = function (e) { if (obj.dragging_active) return false; var value = 0; if (e.button) value = e.button; else if (e.which) value = e.which; if (value == 1) { obj.dragging_last = obj.getCoords(e); obj.dragging_active = true; obj.click = true; } return false; } /** Event handler for mouse up. * * @param e Event object. */ obj.mouseup = function (e) { obj.dragging_active = false; if (obj.click) return obj.mouseclick(e); else return false; } /** Function to get the coordinates of a point corrected for the offset of the viewport. * * @param e Point. * @returns Coordinates of the point corrected for the offset of the viewport. */ obj.getCoords = function (e) { var svgPoint = document.documentElement.createSVGPoint(); svgPoint.x = e.clientX + window.pageXOffset; svgPoint.y = e.clientY + window.pageYOffset; return svgPoint; } /** Event handler for scrolling. * * @param e Event object. */ obj.mousewheel = function(e) { var p = obj.projectCoords(obj.getCoords(e)); if (slides[activeSlide].viewGroup.transform.baseVal.numberOfItems < 1) { var matrix = (new matrixSVG()).fromElements(1, 0, 0, 0, 1, 0, 0, 0, 1); } else { var matrix = (new matrixSVG()).fromSVGMatrix(slides[activeSlide].viewGroup.transform.baseVal.consolidate().matrix); } if (e.wheelDelta) { // IE Opera delta = e.wheelDelta/120; } else if (e.detail) { // MOZ delta = -e.detail/3; } var widthOld = p.x * matrix.e11 + p.y * matrix.e12; var heightOld = p.x * matrix.e21 + p.y * matrix.e22; matrix.e11 *= (1.0 - delta / 20.0); matrix.e12 *= (1.0 - delta / 20.0); matrix.e21 *= (1.0 - delta / 20.0); matrix.e22 *= (1.0 - delta / 20.0); var widthNew = p.x * matrix.e11 + p.y * matrix.e12; var heightNew = p.x * matrix.e21 + p.y * matrix.e22; matrix.e13 += (widthOld - widthNew); matrix.e23 += (heightOld - heightNew); slides[activeSlide]["viewGroup"].setAttribute("transform", matrix.toAttribute()); return false; } /** Function to project a point to screen coordinates. * * @param Point. * @returns The point projected to screen coordinates. */ obj.projectCoords = function(pnt) { var matrix = slides[activeSlide]["element"].getScreenCTM(); if (slides[activeSlide]["viewGroup"]) matrix = slides[activeSlide]["viewGroup"].getScreenCTM(); pnt = pnt.matrixTransform(matrix.inverse()); return pnt; } /** Function to convert a rectangle into a point matrix. * * The function figures out a rectangle that encloses the rectangle given and has the same width/height ratio as the viewport of the presentation. * * @param rect Rectangle. * @return The upper left, upper right and lower right corner of the rectangle in a point matrix. */ obj.rectToMatrix = function(rect) { rectWidth = rect.getBBox().width; rectHeight = rect.getBBox().height; rectX = rect.getBBox().x; rectY = rect.getBBox().y; rectXcorr = 0; rectYcorr = 0; scaleX = WIDTH / rectWidth; scaleY = HEIGHT / rectHeight; if (scaleX > scaleY) { scaleX = scaleY; rectXcorr -= (WIDTH / scaleX - rectWidth) / 2; rectWidth = WIDTH / scaleX; } else { scaleY = scaleX; rectYcorr -= (HEIGHT / scaleY - rectHeight) / 2; rectHeight = HEIGHT / scaleY; } if (rect.transform.baseVal.numberOfItems < 1) { mRectTrans = (new matrixSVG()).fromElements(1, 0, 0, 0, 1, 0, 0, 0, 1); } else { mRectTrans = (new matrixSVG()).fromSVGMatrix(rect.transform.baseVal.consolidate().matrix); } newBasePoints = (new matrixSVG()).fromElements(rectX, rectX, rectX, rectY, rectY, rectY, 1, 1, 1); newVectors = (new matrixSVG()).fromElements(rectXcorr, rectXcorr + rectWidth, rectXcorr + rectWidth, rectYcorr, rectYcorr, rectYcorr + rectHeight, 0, 0, 0); return mRectTrans.mult(newBasePoints.add(newVectors)); } /** Function to return a transformation matrix from a point matrix. * * @param mPoints The point matrix. * @returns The transformation matrix. */ obj.pointMatrixToTransformation = function(mPoints) { mPointsOld = (new matrixSVG()).fromElements(0, WIDTH, WIDTH, 0, 0, HEIGHT, 1, 1, 1); return mPointsOld.mult(mPoints.inv()); } }