1<!-- Created with Inkscape (http://www.inkscape.org/) --><svg xmlns:ns1="https://launchpad.net/jessyink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="1000" height="1000" viewBox="0 0 1000 1000" version="1.1" id="svg8" inkscape:version="0.92.4 5da689c313, 2019-01-14" sodipodi:docname="test.svg"> 2 <defs id="defs33"> 3 <marker inkscape:stockid="Arrow2Lstart" orient="auto" refY="0.0" refX="0.0" id="Arrow2Lstart" style="overflow:visible" inkscape:isstock="true"> 4 <path id="path859" style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " transform="scale(1.1) translate(1,0)"/> 5 </marker> 6 </defs> 7 <sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1920" inkscape:window-height="1017" id="base" showgrid="true" inkscape:snap-text-baseline="true" inkscape:zoom="0.6675088" inkscape:cx="202.7349" inkscape:cy="481.16986" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="webslicer-layer"> 8 <inkscape:grid type="xygrid" id="grid27" spacingx="10" spacingy="10" empspacing="10" color="#8080ff" opacity="0.25098039" empcolor="#0000ff" empopacity="0.25098039"/> 9 </sodipodi:namedview> 10 <g inkscape:groupmode="layer" id="webslicer-layer" inkscape:label="Slide3" style="display:inline"> 11 <rect height="201.49811" width="248.69112" y="353.92661" x="651.3089" id="slicerect1" style="opacity:0.5;fill:#ff0000;stroke-width:1.11927199"> 12 <desc id="desc51">format: png 13dpi: 96 14layout-disposition: bg-el-norepeat 15layout-position-anchor: tl</desc> 16 </rect> 17 </g> 18 <g inkscape:groupmode="layer" id="layer2" inkscape:label="Slide2" style="display:inline"> 19 <circle style="display:inline;fill:#000080;stroke:none" id="c1" cx="150" cy="450" r="50" inkscape:label="#path3736"/> 20 <ellipse style="display:inline;fill:none;stroke:#ff0000;stroke-width:16" id="c2" cx="400" cy="450" rx="100" ry="50" inkscape:label="#path3738"/> 21 <path style="display:inline;fill:#ffff00;stroke:#008000;stroke-width:16" id="c3" sodipodi:type="arc" sodipodi:cx="700" sodipodi:cy="450" sodipodi:rx="100" sodipodi:ry="50" sodipodi:start="0.59013865" sodipodi:end="5.6484511" d="m 783.08635,477.82381 a 100,50 0 0 1 -111.09848,20.17442 100,50 0 0 1 -71.96301,-46.88343 100,50 0 0 1 67.71127,-48.44091 100,50 0 0 1 112.7868,17.67793 L 700,450 Z" inkscape:label="#path3740"/> 22 <path style="display:inline;fill:none;stroke:#000000;stroke-width:10;marker-start:url(#Arrow2Lstart)" d="M 100,600 200,700 300,600 400,700" id="p1" inkscape:connector-curvature="0" inkscape:label="#path3746"/> 23 <path style="display:inline;fill:none;stroke:#000000;stroke-width:10" d="m 500,600 c 0,0 0,100 100,100 100,0 0,-100 100,-100 100,0 100,100 100,100" id="p2" inkscape:connector-curvature="0" inkscape:label="#path3748"/> 24 <path sodipodi:type="star" style="display:inline;fill:#ffff00;stroke:#008000;stroke-width:10" id="s1" sodipodi:sides="5" sodipodi:cx="189.03001" sodipodi:cy="847.93945" sodipodi:r1="69.364868" sodipodi:r2="34.682434" sodipodi:arg1="0.63598373" sodipodi:arg2="1.2643023" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="m 244.8332,889.14005 -45.33887,-8.13446 -32.40428,32.73753 -6.27415,-45.63352 -41.14872,-20.70184 41.46124,-20.06861 6.97297,-45.53197 31.89861,33.23044 45.45824,-7.43847 -21.74681,40.60615 z" inkscape:transform-center-x="6.4673011" inkscape:transform-center-y="-0.16430137"/> 25 <use style="display:inline" x="0" y="0" xlink:href="#s1" inkscape:transform-center-x="6.4673011" inkscape:transform-center-y="-0.16430137" id="u1" transform="translate(200,2.9962152)" width="100%" height="100%" inkscape:label="#use3808"/> 26 </g> 27 <g inkscape:label="Slide1" inkscape:groupmode="layer" id="layer1" style="display:inline"> 28 <text xml:space="preserve" style="font-size:14.66666698px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke:none" x="100" y="100" id="t1" inkscape:label="#text12"><tspan sodipodi:role="line" id="tspan10" x="100" y="100">Hello World</tspan></text> 29 <flowRoot xml:space="preserve" id="t4" style="font-size:40px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke:none" transform="matrix(0.26458333,0,0,0.26458333,372.02961,28.904505)" inkscape:label="#flowRoot14"><flowRegion id="flowRegion16"><rect id="rect18" width="264.5675" height="262.16187" x="105.71429" y="219.66254"/></flowRegion><flowPara id="flowPara20" style="font-size:55.43307114px">flow text which wraps</flowPara></flowRoot> <text xml:space="preserve" style="font-size:14.66666698px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke:none" x="200" y="100" id="t2" inkscape:label="#text3727"><tspan sodipodi:role="line" id="tspan3725" x="200" y="100" style="font-size:14.66666698px">UPPER</tspan></text> 30 <text xml:space="preserve" style="font-size:10.58333302px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke:none" x="300" y="100" id="t3" inkscape:label="#text3735"><tspan sodipodi:role="line" id="tspan3733" x="300" y="100" style="font-size:14.66666698px">Multi line</tspan><tspan sodipodi:role="line" x="300" y="118.33334" id="tspan3737" style="font-size:14.66666698px">text</tspan><tspan sodipodi:role="line" x="300" y="136.66667" id="tspan3739" style="font-size:14.66666698px">FOO</tspan></text> 31 <g id="t5" transform="translate(445.71038,-129.64807)" inkscape:label="#g3772"> 32 <text id="text3762" y="229.64807" x="54.289616" style="font-size:10.58333302px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke:none" xml:space="preserve"><tspan y="229.64807" x="54.289616" id="tspan3760" sodipodi:role="line" style="font-size:14.66666698px">Grouped</tspan></text> 33 <text id="text3766" y="259.64807" x="54.289619" style="font-size:14.66666698px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke:none" xml:space="preserve"><tspan y="259.64807" x="54.289619" id="tspan3764" sodipodi:role="line" style="font-size:14.66666698px">text</tspan></text> 34 </g> 35 <rect style="fill:#000080;stroke:none" id="r1" width="100" height="100" x="100" y="200" inkscape:label="#rect3732"/> 36 <rect style="fill:none;stroke:#ff0000;stroke-width:16" id="r2" width="200" height="100" x="300" y="200" inkscape:label="#rect3734"/> 37 <rect style="fill:#ffff00;stroke:#008000;stroke-width:16" id="r3" width="200" height="100" x="600" y="200" ry="38.950798" rx="44.943226" inkscape:label="#rect3744"/> 38 </g> 39 <svg:script id="JessyInk" ns1:version="1.5.5">// Copyright 2008, 2009 Hannes Hochreiner 40// This program is free software: you can redistribute it and/or modify 41// it under the terms of the GNU General Public License as published by 42// the Free Software Foundation, either version 3 of the License, or 43// (at your option) any later version. 44// 45// This program is distributed in the hope that it will be useful, 46// but WITHOUT ANY WARRANTY; without even the implied warranty of 47// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 48// GNU General Public License for more details. 49// 50// You should have received a copy of the GNU General Public License 51// along with this program. If not, see http://www.gnu.org/licenses/. 52 53// Set onload event handler. 54window.onload = jessyInkInit; 55 56// Creating a namespace dictionary. The standard Inkscape namespaces are taken from inkex.py. 57var NSS = new Object(); 58NSS['sodipodi']='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd'; 59NSS['cc']='http://web.resource.org/cc/'; 60NSS['svg']='http://www.w3.org/2000/svg'; 61NSS['dc']='http://purl.org/dc/elements/1.1/'; 62NSS['rdf']='http://www.w3.org/1999/02/22-rdf-syntax-ns#'; 63NSS['inkscape']='http://www.inkscape.org/namespaces/inkscape'; 64NSS['xlink']='http://www.w3.org/1999/xlink'; 65NSS['xml']='http://www.w3.org/XML/1998/namespace'; 66NSS['jessyink']='https://launchpad.net/jessyink'; 67 68// Keycodes. 69var LEFT_KEY = 37; // cursor left keycode 70var UP_KEY = 38; // cursor up keycode 71var RIGHT_KEY = 39; // cursor right keycode 72var DOWN_KEY = 40; // cursor down keycode 73var PAGE_UP_KEY = 33; // page up keycode 74var PAGE_DOWN_KEY = 34; // page down keycode 75var HOME_KEY = 36; // home keycode 76var END_KEY = 35; // end keycode 77var ENTER_KEY = 13; // next slide 78var SPACE_KEY = 32; 79var ESCAPE_KEY = 27; 80 81// Presentation modes. 82var SLIDE_MODE = 1; 83var INDEX_MODE = 2; 84var DRAWING_MODE = 3; 85 86// Mouse handler actions. 87var MOUSE_UP = 1; 88var MOUSE_DOWN = 2; 89var MOUSE_MOVE = 3; 90var MOUSE_WHEEL = 4; 91 92// Parameters. 93var ROOT_NODE = document.getElementsByTagNameNS(NSS["svg"], "svg")[0]; 94var HEIGHT = 0; 95var WIDTH = 0; 96var INDEX_COLUMNS_DEFAULT = 4; 97var INDEX_COLUMNS = INDEX_COLUMNS_DEFAULT; 98var INDEX_OFFSET = 0; 99var STATE_START = -1; 100var STATE_END = -2; 101var BACKGROUND_COLOR = null; 102var slides = new Array(); 103 104// Initialisation. 105var currentMode = SLIDE_MODE; 106var masterSlide = null; 107var activeSlide = 0; 108var activeEffect = 0; 109var timeStep = 30; // 40 ms equal 25 frames per second. 110var lastFrameTime = null; 111var processingEffect = false; 112var transCounter = 0; 113var effectArray = 0; 114var defaultTransitionInDict = new Object(); 115defaultTransitionInDict["name"] = "appear"; 116var defaultTransitionOutDict = new Object(); 117defaultTransitionOutDict["name"] = "appear"; 118var jessyInkInitialised = false; 119 120// Initialise char and key code dictionaries. 121var charCodeDictionary = getDefaultCharCodeDictionary(); 122var keyCodeDictionary = getDefaultKeyCodeDictionary(); 123 124// Initialise mouse handler dictionary. 125var mouseHandlerDictionary = getDefaultMouseHandlerDictionary(); 126 127var progress_bar_visible = false; 128var timer_elapsed = 0; 129var timer_start = timer_elapsed; 130var timer_duration = 15; // 15 minutes 131 132var history_counter = 0; 133var history_original_elements = new Array(); 134var history_presentation_elements = new Array(); 135 136var mouse_original_path = null; 137var mouse_presentation_path = null; 138var mouse_last_x = -1; 139var mouse_last_y = -1; 140var mouse_min_dist_sqr = 3 * 3; 141var path_colour = "red"; 142var path_width_default = 3; 143var path_width = path_width_default; 144var path_paint_width = path_width; 145 146var number_of_added_slides = 0; 147 148/** Initialisation function. 149 * The whole presentation is set-up in this function. 150 */ 151function jessyInkInit() 152{ 153 // Make sure we only execute this code once. Double execution can occur if the onload event handler is set 154 // in the main svg tag as well (as was recommended in earlier versions). Executing this function twice does 155 // not lead to any problems, but it takes more time. 156 if (jessyInkInitialised) 157 return; 158 159 // Making the presentation scalable. 160 var VIEWBOX = ROOT_NODE.getAttribute("viewBox"); 161 162 if (VIEWBOX) 163 { 164 WIDTH = ROOT_NODE.viewBox.animVal.width; 165 HEIGHT = ROOT_NODE.viewBox.animVal.height; 166 } 167 else 168 { 169 HEIGHT = parseFloat(ROOT_NODE.getAttribute("height")); 170 WIDTH = parseFloat(ROOT_NODE.getAttribute("width")); 171 ROOT_NODE.setAttribute("viewBox", "0 0 " + WIDTH + " " + HEIGHT); 172 } 173 174 ROOT_NODE.setAttribute("width", "100%"); 175 ROOT_NODE.setAttribute("height", "100%"); 176 177 // Setting the background color. 178 var namedViews = document.getElementsByTagNameNS(NSS["sodipodi"], "namedview"); 179 180 for (var counter = 0; counter < namedViews.length; counter++) 181 { 182 if (namedViews[counter].hasAttribute("id") && namedViews[counter].hasAttribute("pagecolor")) 183 { 184 if (namedViews[counter].getAttribute("id") == "base") 185 { 186 BACKGROUND_COLOR = namedViews[counter].getAttribute("pagecolor"); 187 var newAttribute = "background-color:" + BACKGROUND_COLOR + ";"; 188 189 if (ROOT_NODE.hasAttribute("style")) 190 newAttribute += ROOT_NODE.getAttribute("style"); 191 192 ROOT_NODE.setAttribute("style", newAttribute); 193 } 194 } 195 } 196 197 // Defining clip-path. 198 var defsNodes = document.getElementsByTagNameNS(NSS["svg"], "defs"); 199 200 if (defsNodes.length > 0) 201 { 202 var existingClipPath = document.getElementById("jessyInkSlideClipPath"); 203 204 if (!existingClipPath) 205 { 206 var rectNode = document.createElementNS(NSS["svg"], "rect"); 207 var clipPath = document.createElementNS(NSS["svg"], "clipPath"); 208 209 rectNode.setAttribute("x", 0); 210 rectNode.setAttribute("y", 0); 211 rectNode.setAttribute("width", WIDTH); 212 rectNode.setAttribute("height", HEIGHT); 213 214 clipPath.setAttribute("id", "jessyInkSlideClipPath"); 215 clipPath.setAttribute("clipPathUnits", "userSpaceOnUse"); 216 217 clipPath.appendChild(rectNode); 218 defsNodes[0].appendChild(clipPath); 219 } 220 } 221 222 // Making a list of the slide and finding the master slide. 223 var nodes = document.getElementsByTagNameNS(NSS["svg"], "g"); 224 var tempSlides = new Array(); 225 var existingJessyInkPresentationLayer = null; 226 227 for (var counter = 0; counter < nodes.length; counter++) 228 { 229 if (nodes[counter].getAttributeNS(NSS["inkscape"], "groupmode") && (nodes[counter].getAttributeNS(NSS["inkscape"], "groupmode") == "layer")) 230 { 231 if (nodes[counter].getAttributeNS(NSS["inkscape"], "label") && nodes[counter].getAttributeNS(NSS["jessyink"], "masterSlide") == "masterSlide") 232 masterSlide = nodes[counter]; 233 else if (nodes[counter].getAttributeNS(NSS["inkscape"], "label") && nodes[counter].getAttributeNS(NSS["jessyink"], "presentationLayer") == "presentationLayer") 234 existingJessyInkPresentationLayer = nodes[counter]; 235 else 236 tempSlides.push(nodes[counter].getAttribute("id")); 237 } 238 else if (nodes[counter].getAttributeNS(NSS['jessyink'], 'element')) 239 { 240 handleElement(nodes[counter]); 241 } 242 } 243 244 // Hide master slide set default transitions. 245 if (masterSlide) 246 { 247 masterSlide.style.display = "none"; 248 249 if (masterSlide.hasAttributeNS(NSS["jessyink"], "transitionIn")) 250 defaultTransitionInDict = propStrToDict(masterSlide.getAttributeNS(NSS["jessyink"], "transitionIn")); 251 252 if (masterSlide.hasAttributeNS(NSS["jessyink"], "transitionOut")) 253 defaultTransitionOutDict = propStrToDict(masterSlide.getAttributeNS(NSS["jessyink"], "transitionOut")); 254 } 255 256 if (existingJessyInkPresentationLayer != null) 257 { 258 existingJessyInkPresentationLayer.parentNode.removeChild(existingJessyInkPresentationLayer); 259 } 260 261 // Set start slide. 262 var hashObj = new LocationHash(window.location.hash); 263 264 activeSlide = hashObj.slideNumber; 265 activeEffect = hashObj.effectNumber; 266 267 if (activeSlide < 0) 268 activeSlide = 0; 269 else if (activeSlide >= tempSlides.length) 270 activeSlide = tempSlides.length - 1; 271 272 var originalNode = document.getElementById(tempSlides[counter]); 273 274 var JessyInkPresentationLayer = document.createElementNS(NSS["svg"], "g"); 275 JessyInkPresentationLayer.setAttributeNS(NSS["inkscape"], "groupmode", "layer"); 276 JessyInkPresentationLayer.setAttributeNS(NSS["inkscape"], "label", "JessyInk Presentation Layer"); 277 JessyInkPresentationLayer.setAttributeNS(NSS["jessyink"], "presentationLayer", "presentationLayer"); 278 JessyInkPresentationLayer.setAttribute("id", "jessyink_presentation_layer"); 279 JessyInkPresentationLayer.style.display = "inherit"; 280 ROOT_NODE.appendChild(JessyInkPresentationLayer); 281 282 // Gathering all the information about the transitions and effects of the slides, set the background 283 // from the master slide and substitute the auto-texts. 284 for (var counter = 0; counter < tempSlides.length; counter++) 285 { 286 var originalNode = document.getElementById(tempSlides[counter]); 287 originalNode.style.display = "none"; 288 var node = suffixNodeIds(originalNode.cloneNode(true), "_" + counter); 289 JessyInkPresentationLayer.appendChild(node); 290 slides[counter] = new Object(); 291 slides[counter]["original_element"] = originalNode; 292 slides[counter]["element"] = node; 293 294 // Set build in transition. 295 slides[counter]["transitionIn"] = new Object(); 296 297 var dict; 298 299 if (node.hasAttributeNS(NSS["jessyink"], "transitionIn")) 300 dict = propStrToDict(node.getAttributeNS(NSS["jessyink"], "transitionIn")); 301 else 302 dict = defaultTransitionInDict; 303 304 slides[counter]["transitionIn"]["name"] = dict["name"]; 305 slides[counter]["transitionIn"]["options"] = new Object(); 306 307 for (key in dict) 308 if (key != "name") 309 slides[counter]["transitionIn"]["options"][key] = dict[key]; 310 311 // Set build out transition. 312 slides[counter]["transitionOut"] = new Object(); 313 314 if (node.hasAttributeNS(NSS["jessyink"], "transitionOut")) 315 dict = propStrToDict(node.getAttributeNS(NSS["jessyink"], "transitionOut")); 316 else 317 dict = defaultTransitionOutDict; 318 319 slides[counter]["transitionOut"]["name"] = dict["name"]; 320 slides[counter]["transitionOut"]["options"] = new Object(); 321 322 for (key in dict) 323 if (key != "name") 324 slides[counter]["transitionOut"]["options"][key] = dict[key]; 325 326 // Copy master slide content. 327 if (masterSlide) 328 { 329 var clonedNode = suffixNodeIds(masterSlide.cloneNode(true), "_" + counter); 330 clonedNode.removeAttributeNS(NSS["inkscape"], "groupmode"); 331 clonedNode.removeAttributeNS(NSS["inkscape"], "label"); 332 clonedNode.style.display = "inherit"; 333 334 node.insertBefore(clonedNode, node.firstChild); 335 } 336 337 // Setting clip path. 338 node.setAttribute("clip-path", "url(#jessyInkSlideClipPath)"); 339 340 // Substitute auto texts. 341 substituteAutoTexts(node, node.getAttributeNS(NSS["inkscape"], "label"), counter + 1, tempSlides.length); 342 343 node.removeAttributeNS(NSS["inkscape"], "groupmode"); 344 node.removeAttributeNS(NSS["inkscape"], "label"); 345 346 // Set effects. 347 var tempEffects = new Array(); 348 var groups = new Object(); 349 350 for (var IOCounter = 0; IOCounter <= 1; IOCounter++) 351 { 352 var propName = ""; 353 var dir = 0; 354 355 if (IOCounter == 0) 356 { 357 propName = "effectIn"; 358 dir = 1; 359 } 360 else if (IOCounter == 1) 361 { 362 propName = "effectOut"; 363 dir = -1; 364 } 365 366 var effects = getElementsByPropertyNS(node, NSS["jessyink"], propName); 367 368 for (var effectCounter = 0; effectCounter < effects.length; effectCounter++) 369 { 370 var element = document.getElementById(effects[effectCounter]); 371 var dict = propStrToDict(element.getAttributeNS(NSS["jessyink"], propName)); 372 373 // Put every element that has an effect associated with it, into its own group. 374 // Unless of course, we already put it into its own group. 375 if (!(groups[element.id])) 376 { 377 var newGroup = document.createElementNS(NSS["svg"], "g"); 378 379 element.parentNode.insertBefore(newGroup, element); 380 newGroup.appendChild(element.parentNode.removeChild(element)); 381 groups[element.id] = newGroup; 382 } 383 384 var effectDict = new Object(); 385 386 effectDict["effect"] = dict["name"]; 387 effectDict["dir"] = dir; 388 effectDict["element"] = groups[element.id]; 389 390 for (var option in dict) 391 { 392 if ((option != "name") && (option != "order")) 393 { 394 if (!effectDict["options"]) 395 effectDict["options"] = new Object(); 396 397 effectDict["options"][option] = dict[option]; 398 } 399 } 400 401 if (!tempEffects[dict["order"]]) 402 tempEffects[dict["order"]] = new Array(); 403 404 tempEffects[dict["order"]][tempEffects[dict["order"]].length] = effectDict; 405 } 406 } 407 408 // Make invisible, but keep in rendering tree to ensure that bounding box can be calculated. 409 node.setAttribute("opacity",0); 410 node.style.display = "inherit"; 411 412 // Create a transform group. 413 var transformGroup = document.createElementNS(NSS["svg"], "g"); 414 415 // Add content to transform group. 416 while (node.firstChild) 417 transformGroup.appendChild(node.firstChild); 418 419 // Transfer the transform attribute from the node to the transform group. 420 if (node.getAttribute("transform")) 421 { 422 transformGroup.setAttribute("transform", node.getAttribute("transform")); 423 node.removeAttribute("transform"); 424 } 425 426 // Create a view group. 427 var viewGroup = document.createElementNS(NSS["svg"], "g"); 428 429 viewGroup.appendChild(transformGroup); 430 slides[counter]["viewGroup"] = node.appendChild(viewGroup); 431 432 // Insert background. 433 if (BACKGROUND_COLOR != null) 434 { 435 var rectNode = document.createElementNS(NSS["svg"], "rect"); 436 437 rectNode.setAttribute("x", 0); 438 rectNode.setAttribute("y", 0); 439 rectNode.setAttribute("width", WIDTH); 440 rectNode.setAttribute("height", HEIGHT); 441 rectNode.setAttribute("id", "jessyInkBackground" + counter); 442 rectNode.setAttribute("fill", BACKGROUND_COLOR); 443 444 slides[counter]["viewGroup"].insertBefore(rectNode, slides[counter]["viewGroup"].firstChild); 445 } 446 447 // Set views. 448 var tempViews = new Array(); 449 var views = getElementsByPropertyNS(node, NSS["jessyink"], "view"); 450 var matrixOld = (new matrixSVG()).fromElements(1, 0, 0, 0, 1, 0, 0, 0, 1); 451 452 // Set initial view even if there are no other views. 453 slides[counter]["viewGroup"].setAttribute("transform", matrixOld.toAttribute()); 454 slides[counter].initialView = matrixOld.toAttribute(); 455 456 for (var viewCounter = 0; viewCounter < views.length; viewCounter++) 457 { 458 var element = document.getElementById(views[viewCounter]); 459 var dict = propStrToDict(element.getAttributeNS(NSS["jessyink"], "view")); 460 461 if (dict["order"] == 0) 462 { 463 matrixOld = pointMatrixToTransformation(rectToMatrix(element)).mult((new matrixSVG()).fromSVGMatrix(slides[counter].viewGroup.getScreenCTM()).inv().mult((new matrixSVG()).fromSVGMatrix(element.parentNode.getScreenCTM())).inv()); 464 slides[counter].initialView = matrixOld.toAttribute(); 465 } 466 else 467 { 468 var effectDict = new Object(); 469 470 effectDict["effect"] = dict["name"]; 471 effectDict["dir"] = 1; 472 effectDict["element"] = slides[counter]["viewGroup"]; 473 effectDict["order"] = dict["order"]; 474 475 for (var option in dict) 476 { 477 if ((option != "name") && (option != "order")) 478 { 479 if (!effectDict["options"]) 480 effectDict["options"] = new Object(); 481 482 effectDict["options"][option] = dict[option]; 483 } 484 } 485 486 effectDict["options"]["matrixNew"] = pointMatrixToTransformation(rectToMatrix(element)).mult((new matrixSVG()).fromSVGMatrix(slides[counter].viewGroup.getScreenCTM()).inv().mult((new matrixSVG()).fromSVGMatrix(element.parentNode.getScreenCTM())).inv()); 487 488 tempViews[dict["order"]] = effectDict; 489 } 490 491 // Remove element. 492 element.parentNode.removeChild(element); 493 } 494 495 // Consolidate view array and append it to the effect array. 496 if (tempViews.length > 0) 497 { 498 for (var viewCounter = 0; viewCounter < tempViews.length; viewCounter++) 499 { 500 if (tempViews[viewCounter]) 501 { 502 tempViews[viewCounter]["options"]["matrixOld"] = matrixOld; 503 matrixOld = tempViews[viewCounter]["options"]["matrixNew"]; 504 505 if (!tempEffects[tempViews[viewCounter]["order"]]) 506 tempEffects[tempViews[viewCounter]["order"]] = new Array(); 507 508 tempEffects[tempViews[viewCounter]["order"]][tempEffects[tempViews[viewCounter]["order"]].length] = tempViews[viewCounter]; 509 } 510 } 511 } 512 513 // Set consolidated effect array. 514 if (tempEffects.length > 0) 515 { 516 slides[counter]["effects"] = new Array(); 517 518 for (var effectCounter = 0; effectCounter < tempEffects.length; effectCounter++) 519 { 520 if (tempEffects[effectCounter]) 521 slides[counter]["effects"][slides[counter]["effects"].length] = tempEffects[effectCounter]; 522 } 523 } 524 525 node.setAttribute("onmouseover", "if ((currentMode == INDEX_MODE) && ( activeSlide != " + counter + ")) { indexSetActiveSlide(" + counter + "); };"); 526 527 // Set visibility for initial state. 528 if (counter == activeSlide) 529 { 530 node.style.display = "inherit"; 531 node.setAttribute("opacity",1); 532 } 533 else 534 { 535 node.style.display = "none"; 536 node.setAttribute("opacity",0); 537 } 538 } 539 540 // Set key handler. 541 var jessyInkObjects = document.getElementsByTagNameNS(NSS["svg"], "g"); 542 543 for (var counter = 0; counter < jessyInkObjects.length; counter++) 544 { 545 var elem = jessyInkObjects[counter]; 546 547 if (elem.getAttributeNS(NSS["jessyink"], "customKeyBindings")) 548 { 549 if (elem.getCustomKeyBindings != undefined) 550 keyCodeDictionary = elem.getCustomKeyBindings(); 551 552 if (elem.getCustomCharBindings != undefined) 553 charCodeDictionary = elem.getCustomCharBindings(); 554 } 555 } 556 557 // Set mouse handler. 558 var jessyInkMouseHandler = document.getElementsByTagNameNS(NSS["jessyink"], "mousehandler"); 559 560 for (var counter = 0; counter < jessyInkMouseHandler.length; counter++) 561 { 562 var elem = jessyInkMouseHandler[counter]; 563 564 if (elem.getMouseHandler != undefined) 565 { 566 var tempDict = elem.getMouseHandler(); 567 568 for (mode in tempDict) 569 { 570 if (!mouseHandlerDictionary[mode]) 571 mouseHandlerDictionary[mode] = new Object(); 572 573 for (handler in tempDict[mode]) 574 mouseHandlerDictionary[mode][handler] = tempDict[mode][handler]; 575 } 576 } 577 } 578 579 // Check effect number. 580 if ((activeEffect < 0) || (!slides[activeSlide].effects)) 581 { 582 activeEffect = 0; 583 } 584 else if (activeEffect > slides[activeSlide].effects.length) 585 { 586 activeEffect = slides[activeSlide].effects.length; 587 } 588 589 createProgressBar(JessyInkPresentationLayer); 590 hideProgressBar(); 591 setProgressBarValue(activeSlide); 592 setTimeIndicatorValue(0); 593 setInterval("updateTimer()", 1000); 594 setSlideToState(activeSlide, activeEffect); 595 jessyInkInitialised = true; 596} 597 598/** Function to substitute the auto-texts. 599 * 600 * @param node the node 601 * @param slideName name of the slide the node is on 602 * @param slideNumber number of the slide the node is on 603 * @param numberOfSlides number of slides in the presentation 604 */ 605function substituteAutoTexts(node, slideName, slideNumber, numberOfSlides) 606{ 607 var texts = node.getElementsByTagNameNS(NSS["svg"], "tspan"); 608 609 for (var textCounter = 0; textCounter < texts.length; textCounter++) 610 { 611 if (texts[textCounter].getAttributeNS(NSS["jessyink"], "autoText") == "slideNumber") 612 texts[textCounter].firstChild.nodeValue = slideNumber; 613 else if (texts[textCounter].getAttributeNS(NSS["jessyink"], "autoText") == "numberOfSlides") 614 texts[textCounter].firstChild.nodeValue = numberOfSlides; 615 else if (texts[textCounter].getAttributeNS(NSS["jessyink"], "autoText") == "slideTitle") 616 texts[textCounter].firstChild.nodeValue = slideName; 617 } 618} 619 620/** Convenience function to get an element depending on whether it has a property with a particular name. 621 * This function emulates some dearly missed XPath functionality. 622 * 623 * @param node the node 624 * @param namespace namespace of the attribute 625 * @param name attribute name 626 */ 627function getElementsByPropertyNS(node, namespace, name) 628{ 629 var elems = new Array(); 630 631 if (node.getAttributeNS(namespace, name)) 632 elems.push(node.getAttribute("id")); 633 634 for (var counter = 0; counter < node.childNodes.length; counter++) 635 { 636 if (node.childNodes[counter].nodeType == 1) 637 elems = elems.concat(getElementsByPropertyNS(node.childNodes[counter], namespace, name)); 638 } 639 640 return elems; 641} 642 643/** Function to dispatch the next effect, if there is none left, change the slide. 644 * 645 * @param dir direction of the change (1 = forwards, -1 = backwards) 646 */ 647function dispatchEffects(dir) 648{ 649 if (slides[activeSlide]["effects"] && (((dir == 1) && (activeEffect < slides[activeSlide]["effects"].length)) || ((dir == -1) && (activeEffect > 0)))) 650 { 651 processingEffect = true; 652 653 if (dir == 1) 654 { 655 effectArray = slides[activeSlide]["effects"][activeEffect]; 656 activeEffect += dir; 657 } 658 else if (dir == -1) 659 { 660 activeEffect += dir; 661 effectArray = slides[activeSlide]["effects"][activeEffect]; 662 } 663 664 transCounter = 0; 665 startTime = (new Date()).getTime(); 666 lastFrameTime = null; 667 effect(dir); 668 } 669 else if (((dir == 1) && (activeSlide < (slides.length - 1))) || (((dir == -1) && (activeSlide > 0)))) 670 { 671 changeSlide(dir); 672 } 673} 674 675/** Function to skip effects and directly either put the slide into start or end state or change slides. 676 * 677 * @param dir direction of the change (1 = forwards, -1 = backwards) 678 */ 679function skipEffects(dir) 680{ 681 if (slides[activeSlide]["effects"] && (((dir == 1) && (activeEffect < slides[activeSlide]["effects"].length)) || ((dir == -1) && (activeEffect > 0)))) 682 { 683 processingEffect = true; 684 685 if (slides[activeSlide]["effects"] && (dir == 1)) 686 activeEffect = slides[activeSlide]["effects"].length; 687 else 688 activeEffect = 0; 689 690 if (dir == 1) 691 setSlideToState(activeSlide, STATE_END); 692 else 693 setSlideToState(activeSlide, STATE_START); 694 695 processingEffect = false; 696 } 697 else if (((dir == 1) && (activeSlide < (slides.length - 1))) || (((dir == -1) && (activeSlide > 0)))) 698 { 699 changeSlide(dir); 700 } 701} 702 703/** Function to change between slides. 704 * 705 * @param dir direction (1 = forwards, -1 = backwards) 706 */ 707function changeSlide(dir) 708{ 709 processingEffect = true; 710 effectArray = new Array(); 711 712 effectArray[0] = new Object(); 713 if (dir == 1) 714 { 715 effectArray[0]["effect"] = slides[activeSlide]["transitionOut"]["name"]; 716 effectArray[0]["options"] = slides[activeSlide]["transitionOut"]["options"]; 717 effectArray[0]["dir"] = -1; 718 } 719 else if (dir == -1) 720 { 721 effectArray[0]["effect"] = slides[activeSlide]["transitionIn"]["name"]; 722 effectArray[0]["options"] = slides[activeSlide]["transitionIn"]["options"]; 723 effectArray[0]["dir"] = 1; 724 } 725 effectArray[0]["element"] = slides[activeSlide]["element"]; 726 727 activeSlide += dir; 728 setProgressBarValue(activeSlide); 729 730 effectArray[1] = new Object(); 731 732 if (dir == 1) 733 { 734 effectArray[1]["effect"] = slides[activeSlide]["transitionIn"]["name"]; 735 effectArray[1]["options"] = slides[activeSlide]["transitionIn"]["options"]; 736 effectArray[1]["dir"] = 1; 737 } 738 else if (dir == -1) 739 { 740 effectArray[1]["effect"] = slides[activeSlide]["transitionOut"]["name"]; 741 effectArray[1]["options"] = slides[activeSlide]["transitionOut"]["options"]; 742 effectArray[1]["dir"] = -1; 743 } 744 745 effectArray[1]["element"] = slides[activeSlide]["element"]; 746 747 if (slides[activeSlide]["effects"] && (dir == -1)) 748 activeEffect = slides[activeSlide]["effects"].length; 749 else 750 activeEffect = 0; 751 752 if (dir == -1) 753 setSlideToState(activeSlide, STATE_END); 754 else 755 setSlideToState(activeSlide, STATE_START); 756 757 transCounter = 0; 758 startTime = (new Date()).getTime(); 759 lastFrameTime = null; 760 effect(dir); 761} 762 763/** Function to toggle between index and slide mode. 764*/ 765function toggleSlideIndex() 766{ 767 var suspendHandle = ROOT_NODE.suspendRedraw(500); 768 769 if (currentMode == SLIDE_MODE) 770 { 771 hideProgressBar(); 772 INDEX_OFFSET = -1; 773 indexSetPageSlide(activeSlide); 774 currentMode = INDEX_MODE; 775 } 776 else if (currentMode == INDEX_MODE) 777 { 778 for (var counter = 0; counter < slides.length; counter++) 779 { 780 slides[counter]["element"].setAttribute("transform","scale(1)"); 781 782 if (counter == activeSlide) 783 { 784 slides[counter]["element"].style.display = "inherit"; 785 slides[counter]["element"].setAttribute("opacity",1); 786 activeEffect = 0; 787 } 788 else 789 { 790 slides[counter]["element"].setAttribute("opacity",0); 791 slides[counter]["element"].style.display = "none"; 792 } 793 } 794 currentMode = SLIDE_MODE; 795 setSlideToState(activeSlide, STATE_START); 796 setProgressBarValue(activeSlide); 797 798 if (progress_bar_visible) 799 { 800 showProgressBar(); 801 } 802 } 803 804 ROOT_NODE.unsuspendRedraw(suspendHandle); 805 ROOT_NODE.forceRedraw(); 806} 807 808/** Function to run an effect. 809 * 810 * @param dir direction in which to play the effect (1 = forwards, -1 = backwards) 811 */ 812function effect(dir) 813{ 814 var done = true; 815 816 var suspendHandle = ROOT_NODE.suspendRedraw(200); 817 818 for (var counter = 0; counter < effectArray.length; counter++) 819 { 820 if (effectArray[counter]["effect"] == "fade") 821 done &= fade(parseInt(effectArray[counter]["dir"]) * dir, effectArray[counter]["element"], transCounter, effectArray[counter]["options"]); 822 else if (effectArray[counter]["effect"] == "appear") 823 done &= appear(parseInt(effectArray[counter]["dir"]) * dir, effectArray[counter]["element"], transCounter, effectArray[counter]["options"]); 824 else if (effectArray[counter]["effect"] == "pop") 825 done &= pop(parseInt(effectArray[counter]["dir"]) * dir, effectArray[counter]["element"], transCounter, effectArray[counter]["options"]); 826 else if (effectArray[counter]["effect"] == "view") 827 done &= view(parseInt(effectArray[counter]["dir"]) * dir, effectArray[counter]["element"], transCounter, effectArray[counter]["options"]); 828 } 829 830 ROOT_NODE.unsuspendRedraw(suspendHandle); 831 ROOT_NODE.forceRedraw(); 832 833 if (!done) 834 { 835 var currentTime = (new Date()).getTime(); 836 var timeDiff = 1; 837 838 transCounter = currentTime - startTime; 839 840 if (lastFrameTime != null) 841 { 842 timeDiff = timeStep - (currentTime - lastFrameTime); 843 844 if (timeDiff <= 0) 845 timeDiff = 1; 846 } 847 848 lastFrameTime = currentTime; 849 850 window.setTimeout("effect(" + dir + ")", timeDiff); 851 } 852 else 853 { 854 window.location.hash = (activeSlide + 1) + '_' + activeEffect; 855 processingEffect = false; 856 } 857} 858 859/** Function to display the index sheet. 860 * 861 * @param offsetNumber offset number 862 */ 863function displayIndex(offsetNumber) 864{ 865 var offsetX = 0; 866 var offsetY = 0; 867 868 if (offsetNumber < 0) 869 offsetNumber = 0; 870 else if (offsetNumber >= slides.length) 871 offsetNumber = slides.length - 1; 872 873 for (var counter = 0; counter < slides.length; counter++) 874 { 875 if ((counter < offsetNumber) || (counter > offsetNumber + INDEX_COLUMNS * INDEX_COLUMNS - 1)) 876 { 877 slides[counter]["element"].setAttribute("opacity",0); 878 slides[counter]["element"].style.display = "none"; 879 } 880 else 881 { 882 offsetX = ((counter - offsetNumber) % INDEX_COLUMNS) * WIDTH; 883 offsetY = Math.floor((counter - offsetNumber) / INDEX_COLUMNS) * HEIGHT; 884 885 slides[counter]["element"].setAttribute("transform","scale("+1/INDEX_COLUMNS+") translate("+offsetX+","+offsetY+")"); 886 slides[counter]["element"].style.display = "inherit"; 887 slides[counter]["element"].setAttribute("opacity",0.5); 888 } 889 890 setSlideToState(counter, STATE_END); 891 } 892 893 //do we need to save the current offset? 894 if (INDEX_OFFSET != offsetNumber) 895 INDEX_OFFSET = offsetNumber; 896} 897 898/** Function to set the active slide in the slide view. 899 * 900 * @param nbr index of the active slide 901 */ 902function slideSetActiveSlide(nbr) 903{ 904 if (nbr >= slides.length) 905 nbr = slides.length - 1; 906 else if (nbr < 0) 907 nbr = 0; 908 909 slides[activeSlide]["element"].setAttribute("opacity",0); 910 slides[activeSlide]["element"].style.display = "none"; 911 912 activeSlide = parseInt(nbr); 913 914 setSlideToState(activeSlide, STATE_START); 915 slides[activeSlide]["element"].style.display = "inherit"; 916 slides[activeSlide]["element"].setAttribute("opacity",1); 917 918 activeEffect = 0; 919 setProgressBarValue(nbr); 920} 921 922/** Function to set the active slide in the index view. 923 * 924 * @param nbr index of the active slide 925 */ 926function indexSetActiveSlide(nbr) 927{ 928 if (nbr >= slides.length) 929 nbr = slides.length - 1; 930 else if (nbr < 0) 931 nbr = 0; 932 933 slides[activeSlide]["element"].setAttribute("opacity",0.5); 934 935 activeSlide = parseInt(nbr); 936 window.location.hash = (activeSlide + 1) + '_0'; 937 938 slides[activeSlide]["element"].setAttribute("opacity",1); 939} 940 941/** Function to set the page and active slide in index view. 942 * 943 * @param nbr index of the active slide 944 * 945 * NOTE: To force a redraw, 946 * set INDEX_OFFSET to -1 before calling indexSetPageSlide(). 947 * 948 * This is necessary for zooming (otherwise the index might not 949 * get redrawn) and when switching to index mode. 950 * 951 * INDEX_OFFSET = -1 952 * indexSetPageSlide(activeSlide); 953 */ 954function indexSetPageSlide(nbr) 955{ 956 if (nbr >= slides.length) 957 nbr = slides.length - 1; 958 else if (nbr < 0) 959 nbr = 0; 960 961 //calculate the offset 962 var offset = nbr - nbr % (INDEX_COLUMNS * INDEX_COLUMNS); 963 964 if (offset < 0) 965 offset = 0; 966 967 //if different from kept offset, then record and change the page 968 if (offset != INDEX_OFFSET) 969 { 970 INDEX_OFFSET = offset; 971 displayIndex(INDEX_OFFSET); 972 } 973 974 //set the active slide 975 indexSetActiveSlide(nbr); 976} 977 978/** Event handler for key press. 979 * 980 * @param e the event 981 */ 982function keydown(e) 983{ 984 if (!e) 985 e = window.event; 986 987 code = e.keyCode || e.charCode; 988 989 if (!processingEffect && keyCodeDictionary[currentMode] && keyCodeDictionary[currentMode][code]) 990 return keyCodeDictionary[currentMode][code](); 991 else 992 document.onkeypress = keypress; 993} 994// Set event handler for key down. 995document.onkeydown = keydown; 996 997/** Event handler for key press. 998 * 999 * @param e the event 1000 */ 1001function keypress(e) 1002{ 1003 document.onkeypress = null; 1004 1005 if (!e) 1006 e = window.event; 1007 1008 str = String.fromCharCode(e.keyCode || e.charCode); 1009 1010 if (!processingEffect && charCodeDictionary[currentMode] && charCodeDictionary[currentMode][str]) 1011 return charCodeDictionary[currentMode][str](); 1012} 1013 1014/** Function to supply the default char code dictionary. 1015 * 1016 * @returns default char code dictionary 1017 */ 1018function getDefaultCharCodeDictionary() 1019{ 1020 var charCodeDict = new Object(); 1021 1022 charCodeDict[SLIDE_MODE] = new Object(); 1023 charCodeDict[INDEX_MODE] = new Object(); 1024 charCodeDict[DRAWING_MODE] = new Object(); 1025 1026 charCodeDict[SLIDE_MODE]["i"] = function () { return toggleSlideIndex(); }; 1027 charCodeDict[SLIDE_MODE]["d"] = function () { return slideSwitchToDrawingMode(); }; 1028 charCodeDict[SLIDE_MODE]["D"] = function () { return slideQueryDuration(); }; 1029 charCodeDict[SLIDE_MODE]["n"] = function () { return slideAddSlide(activeSlide); }; 1030 charCodeDict[SLIDE_MODE]["p"] = function () { return slideToggleProgressBarVisibility(); }; 1031 charCodeDict[SLIDE_MODE]["t"] = function () { return slideResetTimer(); }; 1032 charCodeDict[SLIDE_MODE]["e"] = function () { return slideUpdateExportLayer(); }; 1033 1034 charCodeDict[DRAWING_MODE]["d"] = function () { return drawingSwitchToSlideMode(); }; 1035 charCodeDict[DRAWING_MODE]["0"] = function () { return drawingResetPathWidth(); }; 1036 charCodeDict[DRAWING_MODE]["1"] = function () { return drawingSetPathWidth(1.0); }; 1037 charCodeDict[DRAWING_MODE]["3"] = function () { return drawingSetPathWidth(3.0); }; 1038 charCodeDict[DRAWING_MODE]["5"] = function () { return drawingSetPathWidth(5.0); }; 1039 charCodeDict[DRAWING_MODE]["7"] = function () { return drawingSetPathWidth(7.0); }; 1040 charCodeDict[DRAWING_MODE]["9"] = function () { return drawingSetPathWidth(9.0); }; 1041 charCodeDict[DRAWING_MODE]["b"] = function () { return drawingSetPathColour("blue"); }; 1042 charCodeDict[DRAWING_MODE]["c"] = function () { return drawingSetPathColour("cyan"); }; 1043 charCodeDict[DRAWING_MODE]["g"] = function () { return drawingSetPathColour("green"); }; 1044 charCodeDict[DRAWING_MODE]["k"] = function () { return drawingSetPathColour("black"); }; 1045 charCodeDict[DRAWING_MODE]["m"] = function () { return drawingSetPathColour("magenta"); }; 1046 charCodeDict[DRAWING_MODE]["o"] = function () { return drawingSetPathColour("orange"); }; 1047 charCodeDict[DRAWING_MODE]["r"] = function () { return drawingSetPathColour("red"); }; 1048 charCodeDict[DRAWING_MODE]["w"] = function () { return drawingSetPathColour("white"); }; 1049 charCodeDict[DRAWING_MODE]["y"] = function () { return drawingSetPathColour("yellow"); }; 1050 charCodeDict[DRAWING_MODE]["z"] = function () { return drawingUndo(); }; 1051 1052 charCodeDict[INDEX_MODE]["i"] = function () { return toggleSlideIndex(); }; 1053 charCodeDict[INDEX_MODE]["-"] = function () { return indexDecreaseNumberOfColumns(); }; 1054 charCodeDict[INDEX_MODE]["="] = function () { return indexIncreaseNumberOfColumns(); }; 1055 charCodeDict[INDEX_MODE]["+"] = function () { return indexIncreaseNumberOfColumns(); }; 1056 charCodeDict[INDEX_MODE]["0"] = function () { return indexResetNumberOfColumns(); }; 1057 1058 return charCodeDict; 1059} 1060 1061/** Function to supply the default key code dictionary. 1062 * 1063 * @returns default key code dictionary 1064 */ 1065function getDefaultKeyCodeDictionary() 1066{ 1067 var keyCodeDict = new Object(); 1068 1069 keyCodeDict[SLIDE_MODE] = new Object(); 1070 keyCodeDict[INDEX_MODE] = new Object(); 1071 keyCodeDict[DRAWING_MODE] = new Object(); 1072 1073 keyCodeDict[SLIDE_MODE][LEFT_KEY] = function() { return dispatchEffects(-1); }; 1074 keyCodeDict[SLIDE_MODE][RIGHT_KEY] = function() { return dispatchEffects(1); }; 1075 keyCodeDict[SLIDE_MODE][UP_KEY] = function() { return skipEffects(-1); }; 1076 keyCodeDict[SLIDE_MODE][DOWN_KEY] = function() { return skipEffects(1); }; 1077 keyCodeDict[SLIDE_MODE][PAGE_UP_KEY] = function() { return dispatchEffects(-1); }; 1078 keyCodeDict[SLIDE_MODE][PAGE_DOWN_KEY] = function() { return dispatchEffects(1); }; 1079 keyCodeDict[SLIDE_MODE][HOME_KEY] = function() { return slideSetActiveSlide(0); }; 1080 keyCodeDict[SLIDE_MODE][END_KEY] = function() { return slideSetActiveSlide(slides.length - 1); }; 1081 keyCodeDict[SLIDE_MODE][SPACE_KEY] = function() { return dispatchEffects(1); }; 1082 1083 keyCodeDict[INDEX_MODE][LEFT_KEY] = function() { return indexSetPageSlide(activeSlide - 1); }; 1084 keyCodeDict[INDEX_MODE][RIGHT_KEY] = function() { return indexSetPageSlide(activeSlide + 1); }; 1085 keyCodeDict[INDEX_MODE][UP_KEY] = function() { return indexSetPageSlide(activeSlide - INDEX_COLUMNS); }; 1086 keyCodeDict[INDEX_MODE][DOWN_KEY] = function() { return indexSetPageSlide(activeSlide + INDEX_COLUMNS); }; 1087 keyCodeDict[INDEX_MODE][PAGE_UP_KEY] = function() { return indexSetPageSlide(activeSlide - INDEX_COLUMNS * INDEX_COLUMNS); }; 1088 keyCodeDict[INDEX_MODE][PAGE_DOWN_KEY] = function() { return indexSetPageSlide(activeSlide + INDEX_COLUMNS * INDEX_COLUMNS); }; 1089 keyCodeDict[INDEX_MODE][HOME_KEY] = function() { return indexSetPageSlide(0); }; 1090 keyCodeDict[INDEX_MODE][END_KEY] = function() { return indexSetPageSlide(slides.length - 1); }; 1091 keyCodeDict[INDEX_MODE][ENTER_KEY] = function() { return toggleSlideIndex(); }; 1092 1093 keyCodeDict[DRAWING_MODE][ESCAPE_KEY] = function () { return drawingSwitchToSlideMode(); }; 1094 1095 return keyCodeDict; 1096} 1097 1098/** Function to handle all mouse events. 1099 * 1100 * @param evnt event 1101 * @param action type of event (e.g. mouse up, mouse wheel) 1102 */ 1103function mouseHandlerDispatch(evnt, action) 1104{ 1105 if (!evnt) 1106 evnt = window.event; 1107 1108 var retVal = true; 1109 1110 if (!processingEffect && mouseHandlerDictionary[currentMode] && mouseHandlerDictionary[currentMode][action]) 1111 { 1112 var subRetVal = mouseHandlerDictionary[currentMode][action](evnt); 1113 1114 if (subRetVal != null && subRetVal != undefined) 1115 retVal = subRetVal; 1116 } 1117 1118 if (evnt.preventDefault && !retVal) 1119 evnt.preventDefault(); 1120 1121 evnt.returnValue = retVal; 1122 1123 return retVal; 1124} 1125 1126// Set mouse event handler. 1127document.onmousedown = function(e) { return mouseHandlerDispatch(e, MOUSE_DOWN); }; 1128document.onmouseup = function(e) { return mouseHandlerDispatch(e, MOUSE_UP); }; 1129document.onmousemove = function(e) { return mouseHandlerDispatch(e, MOUSE_MOVE); }; 1130 1131// Moz 1132if (window.addEventListener) 1133{ 1134 window.addEventListener('DOMMouseScroll', function(e) { return mouseHandlerDispatch(e, MOUSE_WHEEL); }, false); 1135} 1136 1137// Opera Safari OK - may not work in IE 1138window.onmousewheel = function(e) { return mouseHandlerDispatch(e, MOUSE_WHEEL); }; 1139 1140/** Function to supply the default mouse handler dictionary. 1141 * 1142 * @returns default mouse handler dictionary 1143 */ 1144function getDefaultMouseHandlerDictionary() 1145{ 1146 var mouseHandlerDict = new Object(); 1147 1148 mouseHandlerDict[SLIDE_MODE] = new Object(); 1149 mouseHandlerDict[INDEX_MODE] = new Object(); 1150 mouseHandlerDict[DRAWING_MODE] = new Object(); 1151 1152 mouseHandlerDict[SLIDE_MODE][MOUSE_DOWN] = function(evnt) { return dispatchEffects(1); }; 1153 mouseHandlerDict[SLIDE_MODE][MOUSE_WHEEL] = function(evnt) { return slideMousewheel(evnt); }; 1154 1155 mouseHandlerDict[INDEX_MODE][MOUSE_DOWN] = function(evnt) { return toggleSlideIndex(); }; 1156 1157 mouseHandlerDict[DRAWING_MODE][MOUSE_DOWN] = function(evnt) { return drawingMousedown(evnt); }; 1158 mouseHandlerDict[DRAWING_MODE][MOUSE_UP] = function(evnt) { return drawingMouseup(evnt); }; 1159 mouseHandlerDict[DRAWING_MODE][MOUSE_MOVE] = function(evnt) { return drawingMousemove(evnt); }; 1160 1161 return mouseHandlerDict; 1162} 1163 1164/** Function to switch from slide mode to drawing mode. 1165*/ 1166function slideSwitchToDrawingMode() 1167{ 1168 currentMode = DRAWING_MODE; 1169 1170 var tempDict; 1171 1172 if (ROOT_NODE.hasAttribute("style")) 1173 tempDict = propStrToDict(ROOT_NODE.getAttribute("style")); 1174 else 1175 tempDict = new Object(); 1176 1177 tempDict["cursor"] = "crosshair"; 1178 ROOT_NODE.setAttribute("style", dictToPropStr(tempDict)); 1179} 1180 1181/** Function to switch from drawing mode to slide mode. 1182*/ 1183function drawingSwitchToSlideMode() 1184{ 1185 currentMode = SLIDE_MODE; 1186 1187 var tempDict; 1188 1189 if (ROOT_NODE.hasAttribute("style")) 1190 tempDict = propStrToDict(ROOT_NODE.getAttribute("style")); 1191 else 1192 tempDict = new Object(); 1193 1194 tempDict["cursor"] = "auto"; 1195 ROOT_NODE.setAttribute("style", dictToPropStr(tempDict)); 1196} 1197 1198/** Function to decrease the number of columns in index mode. 1199*/ 1200function indexDecreaseNumberOfColumns() 1201{ 1202 if (INDEX_COLUMNS >= 3) 1203 { 1204 INDEX_COLUMNS -= 1; 1205 INDEX_OFFSET = -1 1206 indexSetPageSlide(activeSlide); 1207 } 1208} 1209 1210/** Function to increase the number of columns in index mode. 1211*/ 1212function indexIncreaseNumberOfColumns() 1213{ 1214 if (INDEX_COLUMNS < 7) 1215 { 1216 INDEX_COLUMNS += 1; 1217 INDEX_OFFSET = -1 1218 indexSetPageSlide(activeSlide); 1219 } 1220} 1221 1222/** Function to reset the number of columns in index mode. 1223*/ 1224function indexResetNumberOfColumns() 1225{ 1226 if (INDEX_COLUMNS != INDEX_COLUMNS_DEFAULT) 1227 { 1228 INDEX_COLUMNS = INDEX_COLUMNS_DEFAULT; 1229 INDEX_OFFSET = -1 1230 indexSetPageSlide(activeSlide); 1231 } 1232} 1233 1234/** Function to reset path width in drawing mode. 1235*/ 1236function drawingResetPathWidth() 1237{ 1238 path_width = path_width_default; 1239 set_path_paint_width(); 1240} 1241 1242/** Function to set path width in drawing mode. 1243 * 1244 * @param width new path width 1245 */ 1246function drawingSetPathWidth(width) 1247{ 1248 path_width = width; 1249 set_path_paint_width(); 1250} 1251 1252/** Function to set path colour in drawing mode. 1253 * 1254 * @param colour new path colour 1255 */ 1256function drawingSetPathColour(colour) 1257{ 1258 path_colour = colour; 1259} 1260 1261/** Function to query the duration of the presentation from the user in slide mode. 1262*/ 1263function slideQueryDuration() 1264{ 1265 var new_duration = prompt("Length of presentation in minutes?", timer_duration); 1266 1267 if ((new_duration != null) && (new_duration != '')) 1268 { 1269 timer_duration = new_duration; 1270 } 1271 1272 updateTimer(); 1273} 1274 1275/** Function to add new slide in slide mode. 1276 * 1277 * @param afterSlide after which slide to insert the new one 1278 */ 1279function slideAddSlide(afterSlide) 1280{ 1281 addSlide(afterSlide); 1282 slideSetActiveSlide(afterSlide + 1); 1283 updateTimer(); 1284} 1285 1286/** Function to toggle the visibility of the progress bar in slide mode. 1287*/ 1288function slideToggleProgressBarVisibility() 1289{ 1290 if (progress_bar_visible) 1291 { 1292 progress_bar_visible = false; 1293 hideProgressBar(); 1294 } 1295 else 1296 { 1297 progress_bar_visible = true; 1298 showProgressBar(); 1299 } 1300} 1301 1302/** Function to reset the timer in slide mode. 1303*/ 1304function slideResetTimer() 1305{ 1306 timer_start = timer_elapsed; 1307 updateTimer(); 1308} 1309 1310/** Convenience function to pad a string with zero in front up to a certain length. 1311 */ 1312function padString(str, len) 1313{ 1314 var outStr = str; 1315 1316 while (outStr.length < len) 1317 { 1318 outStr = '0' + outStr; 1319 } 1320 1321 return outStr; 1322} 1323 1324/** Function to update the export layer. 1325 */ 1326function slideUpdateExportLayer() 1327{ 1328 // Suspend redraw since we are going to mess with the slides. 1329 var suspendHandle = ROOT_NODE.suspendRedraw(2000); 1330 1331 var tmpActiveSlide = activeSlide; 1332 var tmpActiveEffect = activeEffect; 1333 var exportedLayers = new Array(); 1334 1335 for (var counterSlides = 0; counterSlides < slides.length; counterSlides++) 1336 { 1337 var exportNode; 1338 1339 setSlideToState(counterSlides, STATE_START); 1340 1341 var maxEffect = 0; 1342 1343 if (slides[counterSlides].effects) 1344 { 1345 maxEffect = slides[counterSlides].effects.length; 1346 } 1347 1348 exportNode = slides[counterSlides].element.cloneNode(true); 1349 exportNode.setAttributeNS(NSS["inkscape"], "groupmode", "layer"); 1350 exportNode.setAttributeNS(NSS["inkscape"], "label", "slide_" + padString((counterSlides + 1).toString(), slides.length.toString().length) + "_effect_" + padString("0", maxEffect.toString().length)); 1351 1352 exportedLayers.push(exportNode); 1353 1354 if (slides[counterSlides]["effects"]) 1355 { 1356 for (var counter = 0; counter < slides[counterSlides]["effects"].length; counter++) 1357 { 1358 for (var subCounter = 0; subCounter < slides[counterSlides]["effects"][counter].length; subCounter++) 1359 { 1360 var effect = slides[counterSlides]["effects"][counter][subCounter]; 1361 if (effect["effect"] == "fade") 1362 fade(parseInt(effect["dir"]), effect["element"], STATE_END, effect["options"]); 1363 else if (effect["effect"] == "appear") 1364 appear(parseInt(effect["dir"]), effect["element"], STATE_END, effect["options"]); 1365 else if (effect["effect"] == "pop") 1366 pop(parseInt(effect["dir"]), effect["element"], STATE_END, effect["options"]); 1367 else if (effect["effect"] == "view") 1368 view(parseInt(effect["dir"]), effect["element"], STATE_END, effect["options"]); 1369 } 1370 1371 var layerName = "slide_" + padString((counterSlides + 1).toString(), slides.length.toString().length) + "_effect_" + padString((counter + 1).toString(), maxEffect.toString().length); 1372 exportNode = slides[counterSlides].element.cloneNode(true); 1373 exportNode.setAttributeNS(NSS["inkscape"], "groupmode", "layer"); 1374 exportNode.setAttributeNS(NSS["inkscape"], "label", layerName); 1375 exportNode.setAttribute("id", layerName); 1376 1377 exportedLayers.push(exportNode); 1378 } 1379 } 1380 } 1381 1382 activeSlide = tmpActiveSlide; 1383 activeEffect = tmpActiveEffect; 1384 setSlideToState(activeSlide, activeEffect); 1385 1386 // Copy image. 1387 var newDoc = document.documentElement.cloneNode(true); 1388 1389 // Delete viewbox form new imag and set width and height. 1390 newDoc.removeAttribute('viewbox'); 1391 newDoc.setAttribute('width', WIDTH); 1392 newDoc.setAttribute('height', HEIGHT); 1393 1394 // Delete all layers and script elements. 1395 var nodesToBeRemoved = new Array(); 1396 1397 for (var childCounter = 0; childCounter < newDoc.childNodes.length; childCounter++) 1398 { 1399 var child = newDoc.childNodes[childCounter]; 1400 1401 if (child.nodeType == 1) 1402 { 1403 if ((child.nodeName.toUpperCase() == 'G') || (child.nodeName.toUpperCase() == 'SCRIPT')) 1404 { 1405 nodesToBeRemoved.push(child); 1406 } 1407 } 1408 } 1409 1410 for (var ndCounter = 0; ndCounter < nodesToBeRemoved.length; ndCounter++) 1411 { 1412 var nd = nodesToBeRemoved[ndCounter]; 1413 1414 // Before removing the node, check whether it contains any definitions. 1415 var defs = nd.getElementsByTagNameNS(NSS["svg"], "defs"); 1416 1417 for (var defsCounter = 0; defsCounter < defs.length; defsCounter++) 1418 { 1419 if (defs[defsCounter].id) 1420 { 1421 newDoc.appendChild(defs[defsCounter].cloneNode(true)); 1422 } 1423 } 1424 1425 // Remove node. 1426 nd.parentNode.removeChild(nd); 1427 } 1428 1429 // Set current layer. 1430 if (exportedLayers[0]) 1431 { 1432 var namedView; 1433 1434 for (var nodeCounter = 0; nodeCounter < newDoc.childNodes.length; nodeCounter++) 1435 { 1436 if ((newDoc.childNodes[nodeCounter].nodeType == 1) && (newDoc.childNodes[nodeCounter].getAttribute('id') == 'base')) 1437 { 1438 namedView = newDoc.childNodes[nodeCounter]; 1439 } 1440 } 1441 1442 if (namedView) 1443 { 1444 namedView.setAttributeNS(NSS['inkscape'], 'current-layer', exportedLayers[0].getAttributeNS(NSS['inkscape'], 'label')); 1445 } 1446 } 1447 1448 // Add exported layers. 1449 while (exportedLayers.length > 0) 1450 { 1451 var nd = exportedLayers.pop(); 1452 1453 nd.setAttribute("opacity",1); 1454 nd.style.display = "inherit"; 1455 1456 newDoc.appendChild(nd); 1457 } 1458 1459 // Serialise the new document. 1460 window.location = 'data:application/svg+xml;base64;charset=utf-8,' + window.btoa(unescape(encodeURIComponent((new XMLSerializer()).serializeToString(newDoc)))); 1461 1462 // Unsuspend redraw. 1463 ROOT_NODE.unsuspendRedraw(suspendHandle); 1464 ROOT_NODE.forceRedraw(); 1465} 1466 1467/** Function to undo last drawing operation. 1468*/ 1469function drawingUndo() 1470{ 1471 mouse_presentation_path = null; 1472 mouse_original_path = null; 1473 1474 if (history_presentation_elements.length > 0) 1475 { 1476 var p = history_presentation_elements.pop(); 1477 var parent = p.parentNode.removeChild(p); 1478 1479 p = history_original_elements.pop(); 1480 parent = p.parentNode.removeChild(p); 1481 } 1482} 1483 1484/** Event handler for mouse down in drawing mode. 1485 * 1486 * @param e the event 1487 */ 1488function drawingMousedown(e) 1489{ 1490 var value = 0; 1491 1492 if (e.button) 1493 value = e.button; 1494 else if (e.which) 1495 value = e.which; 1496 1497 if (value == 1) 1498 { 1499 history_counter++; 1500 1501 var p = calcCoord(e); 1502 1503 mouse_last_x = e.clientX; 1504 mouse_last_y = e.clientY; 1505 mouse_original_path = document.createElementNS(NSS["svg"], "path"); 1506 mouse_original_path.setAttribute("stroke", path_colour); 1507 mouse_original_path.setAttribute("stroke-width", path_paint_width); 1508 mouse_original_path.setAttribute("fill", "none"); 1509 mouse_original_path.setAttribute("id", "path " + Date()); 1510 mouse_original_path.setAttribute("d", "M" + p.x + "," + p.y); 1511 slides[activeSlide]["original_element"].appendChild(mouse_original_path); 1512 history_original_elements.push(mouse_original_path); 1513 1514 mouse_presentation_path = document.createElementNS(NSS["svg"], "path"); 1515 mouse_presentation_path.setAttribute("stroke", path_colour); 1516 mouse_presentation_path.setAttribute("stroke-width", path_paint_width); 1517 mouse_presentation_path.setAttribute("fill", "none"); 1518 mouse_presentation_path.setAttribute("id", "path " + Date() + " presentation copy"); 1519 mouse_presentation_path.setAttribute("d", "M" + p.x + "," + p.y); 1520 1521 if (slides[activeSlide]["viewGroup"]) 1522 slides[activeSlide]["viewGroup"].appendChild(mouse_presentation_path); 1523 else 1524 slides[activeSlide]["element"].appendChild(mouse_presentation_path); 1525 1526 history_presentation_elements.push(mouse_presentation_path); 1527 1528 return false; 1529 } 1530 1531 return true; 1532} 1533 1534/** Event handler for mouse up in drawing mode. 1535 * 1536 * @param e the event 1537 */ 1538function drawingMouseup(e) 1539{ 1540 if(!e) 1541 e = window.event; 1542 1543 if (mouse_presentation_path != null) 1544 { 1545 var p = calcCoord(e); 1546 var d = mouse_presentation_path.getAttribute("d"); 1547 d += " L" + p.x + "," + p.y; 1548 mouse_presentation_path.setAttribute("d", d); 1549 mouse_presentation_path = null; 1550 mouse_original_path.setAttribute("d", d); 1551 mouse_original_path = null; 1552 1553 return false; 1554 } 1555 1556 return true; 1557} 1558 1559/** Event handler for mouse move in drawing mode. 1560 * 1561 * @param e the event 1562 */ 1563function drawingMousemove(e) 1564{ 1565 if(!e) 1566 e = window.event; 1567 1568 var dist = (mouse_last_x - e.clientX) * (mouse_last_x - e.clientX) + (mouse_last_y - e.clientY) * (mouse_last_y - e.clientY); 1569 1570 if (mouse_presentation_path == null) 1571 { 1572 return true; 1573 } 1574 1575 if (dist >= mouse_min_dist_sqr) 1576 { 1577 var p = calcCoord(e); 1578 var d = mouse_presentation_path.getAttribute("d"); 1579 d += " L" + p.x + "," + p.y; 1580 mouse_presentation_path.setAttribute("d", d); 1581 mouse_original_path.setAttribute("d", d); 1582 mouse_last_x = e.clientX; 1583 mouse_last_y = e.clientY; 1584 } 1585 1586 return false; 1587} 1588 1589/** Event handler for mouse wheel events in slide mode. 1590 * based on http://adomas.org/javascript-mouse-wheel/ 1591 * 1592 * @param e the event 1593 */ 1594function slideMousewheel(e) 1595{ 1596 var delta = 0; 1597 1598 if (!e) 1599 e = window.event; 1600 1601 if (e.wheelDelta) 1602 { // IE Opera 1603 delta = e.wheelDelta/120; 1604 } 1605 else if (e.detail) 1606 { // MOZ 1607 delta = -e.detail/3; 1608 } 1609 1610 if (delta > 0) 1611 skipEffects(-1); 1612 else if (delta < 0) 1613 skipEffects(1); 1614 1615 if (e.preventDefault) 1616 e.preventDefault(); 1617 1618 e.returnValue = false; 1619} 1620 1621/** Event handler for mouse wheel events in index mode. 1622 * based on http://adomas.org/javascript-mouse-wheel/ 1623 * 1624 * @param e the event 1625 */ 1626function indexMousewheel(e) 1627{ 1628 var delta = 0; 1629 1630 if (!e) 1631 e = window.event; 1632 1633 if (e.wheelDelta) 1634 { // IE Opera 1635 delta = e.wheelDelta/120; 1636 } 1637 else if (e.detail) 1638 { // MOZ 1639 delta = -e.detail/3; 1640 } 1641 1642 if (delta > 0) 1643 indexSetPageSlide(activeSlide - INDEX_COLUMNS * INDEX_COLUMNS); 1644 else if (delta < 0) 1645 indexSetPageSlide(activeSlide + INDEX_COLUMNS * INDEX_COLUMNS); 1646 1647 if (e.preventDefault) 1648 e.preventDefault(); 1649 1650 e.returnValue = false; 1651} 1652 1653/** Function to set the path paint width. 1654*/ 1655function set_path_paint_width() 1656{ 1657 var svgPoint1 = document.documentElement.createSVGPoint(); 1658 var svgPoint2 = document.documentElement.createSVGPoint(); 1659 1660 svgPoint1.x = 0.0; 1661 svgPoint1.y = 0.0; 1662 svgPoint2.x = 1.0; 1663 svgPoint2.y = 0.0; 1664 1665 var matrix = slides[activeSlide]["element"].getTransformToElement(ROOT_NODE); 1666 1667 if (slides[activeSlide]["viewGroup"]) 1668 matrix = slides[activeSlide]["viewGroup"].getTransformToElement(ROOT_NODE); 1669 1670 svgPoint1 = svgPoint1.matrixTransform(matrix); 1671 svgPoint2 = svgPoint2.matrixTransform(matrix); 1672 1673 path_paint_width = path_width / Math.sqrt((svgPoint2.x - svgPoint1.x) * (svgPoint2.x - svgPoint1.x) + (svgPoint2.y - svgPoint1.y) * (svgPoint2.y - svgPoint1.y)); 1674} 1675 1676/** The view effect. 1677 * 1678 * @param dir direction the effect should be played (1 = forwards, -1 = backwards) 1679 * @param element the element the effect should be applied to 1680 * @param time the time that has elapsed since the beginning of the effect 1681 * @param options a dictionary with additional options (e.g. length of the effect); for the view effect the options need to contain the old and the new matrix. 1682 */ 1683function view(dir, element, time, options) 1684{ 1685 var length = 250; 1686 var fraction; 1687 1688 if (!options["matrixInitial"]) 1689 { 1690 var tempString = slides[activeSlide]["viewGroup"].getAttribute("transform"); 1691 1692 if (tempString) 1693 options["matrixInitial"] = (new matrixSVG()).fromAttribute(tempString); 1694 else 1695 options["matrixInitial"] = (new matrixSVG()).fromSVGElements(1, 0, 0, 1, 0, 0); 1696 } 1697 1698 if ((time == STATE_END) || (time == STATE_START)) 1699 fraction = 1; 1700 else 1701 { 1702 if (options && options["length"]) 1703 length = options["length"]; 1704 1705 fraction = time / length; 1706 } 1707 1708 if (dir == 1) 1709 { 1710 if (fraction <= 0) 1711 { 1712 element.setAttribute("transform", options["matrixInitial"].toAttribute()); 1713 } 1714 else if (fraction >= 1) 1715 { 1716 element.setAttribute("transform", options["matrixNew"].toAttribute()); 1717 1718 set_path_paint_width(); 1719 1720 options["matrixInitial"] = null; 1721 return true; 1722 } 1723 else 1724 { 1725 element.setAttribute("transform", options["matrixInitial"].mix(options["matrixNew"], fraction).toAttribute()); 1726 } 1727 } 1728 else if (dir == -1) 1729 { 1730 if (fraction <= 0) 1731 { 1732 element.setAttribute("transform", options["matrixInitial"].toAttribute()); 1733 } 1734 else if (fraction >= 1) 1735 { 1736 element.setAttribute("transform", options["matrixOld"].toAttribute()); 1737 set_path_paint_width(); 1738 1739 options["matrixInitial"] = null; 1740 return true; 1741 } 1742 else 1743 { 1744 element.setAttribute("transform", options["matrixInitial"].mix(options["matrixOld"], fraction).toAttribute()); 1745 } 1746 } 1747 1748 return false; 1749} 1750 1751/** The fade effect. 1752 * 1753 * @param dir direction the effect should be played (1 = forwards, -1 = backwards) 1754 * @param element the element the effect should be applied to 1755 * @param time the time that has elapsed since the beginning of the effect 1756 * @param options a dictionary with additional options (e.g. length of the effect) 1757 */ 1758function fade(dir, element, time, options) 1759{ 1760 var length = 250; 1761 var fraction; 1762 1763 if ((time == STATE_END) || (time == STATE_START)) 1764 fraction = 1; 1765 else 1766 { 1767 if (options && options["length"]) 1768 length = options["length"]; 1769 1770 fraction = time / length; 1771 } 1772 1773 if (dir == 1) 1774 { 1775 if (fraction <= 0) 1776 { 1777 element.style.display = "none"; 1778 element.setAttribute("opacity", 0); 1779 } 1780 else if (fraction >= 1) 1781 { 1782 element.style.display = "inherit"; 1783 element.setAttribute("opacity", 1); 1784 return true; 1785 } 1786 else 1787 { 1788 element.style.display = "inherit"; 1789 element.setAttribute("opacity", fraction); 1790 } 1791 } 1792 else if (dir == -1) 1793 { 1794 if (fraction <= 0) 1795 { 1796 element.style.display = "inherit"; 1797 element.setAttribute("opacity", 1); 1798 } 1799 else if (fraction >= 1) 1800 { 1801 element.setAttribute("opacity", 0); 1802 element.style.display = "none"; 1803 return true; 1804 } 1805 else 1806 { 1807 element.style.display = "inherit"; 1808 element.setAttribute("opacity", 1 - fraction); 1809 } 1810 } 1811 return false; 1812} 1813 1814/** The appear effect. 1815 * 1816 * @param dir direction the effect should be played (1 = forwards, -1 = backwards) 1817 * @param element the element the effect should be applied to 1818 * @param time the time that has elapsed since the beginning of the effect 1819 * @param options a dictionary with additional options (e.g. length of the effect) 1820 */ 1821function appear(dir, element, time, options) 1822{ 1823 if (dir == 1) 1824 { 1825 element.style.display = "inherit"; 1826 element.setAttribute("opacity",1); 1827 } 1828 else if (dir == -1) 1829 { 1830 element.style.display = "none"; 1831 element.setAttribute("opacity",0); 1832 } 1833 return true; 1834} 1835 1836/** The pop effect. 1837 * 1838 * @param dir direction the effect should be played (1 = forwards, -1 = backwards) 1839 * @param element the element the effect should be applied to 1840 * @param time the time that has elapsed since the beginning of the effect 1841 * @param options a dictionary with additional options (e.g. length of the effect) 1842 */ 1843function pop(dir, element, time, options) 1844{ 1845 var length = 500; 1846 var fraction; 1847 1848 if ((time == STATE_END) || (time == STATE_START)) 1849 fraction = 1; 1850 else 1851 { 1852 if (options && options["length"]) 1853 length = options["length"]; 1854 1855 fraction = time / length; 1856 } 1857 1858 if (dir == 1) 1859 { 1860 if (fraction <= 0) 1861 { 1862 element.setAttribute("opacity", 0); 1863 element.setAttribute("transform", "scale(0)"); 1864 element.style.display = "none"; 1865 } 1866 else if (fraction >= 1) 1867 { 1868 element.setAttribute("opacity", 1); 1869 element.removeAttribute("transform"); 1870 element.style.display = "inherit"; 1871 return true; 1872 } 1873 else 1874 { 1875 element.style.display = "inherit"; 1876 var opacityFraction = fraction * 3; 1877 if (opacityFraction > 1) 1878 opacityFraction = 1; 1879 element.setAttribute("opacity", opacityFraction); 1880 var offsetX = WIDTH * (1.0 - fraction) / 2.0; 1881 var offsetY = HEIGHT * (1.0 - fraction) / 2.0; 1882 element.setAttribute("transform", "translate(" + offsetX + "," + offsetY + ") scale(" + fraction + ")"); 1883 } 1884 } 1885 else if (dir == -1) 1886 { 1887 if (fraction <= 0) 1888 { 1889 element.setAttribute("opacity", 1); 1890 element.setAttribute("transform", "scale(1)"); 1891 element.style.display = "inherit"; 1892 } 1893 else if (fraction >= 1) 1894 { 1895 element.setAttribute("opacity", 0); 1896 element.removeAttribute("transform"); 1897 element.style.display = "none"; 1898 return true; 1899 } 1900 else 1901 { 1902 element.setAttribute("opacity", 1 - fraction); 1903 element.setAttribute("transform", "scale(" + 1 - fraction + ")"); 1904 element.style.display = "inherit"; 1905 } 1906 } 1907 return false; 1908} 1909 1910/** Function to set a slide either to the start or the end state. 1911 * 1912 * @param slide the slide to use 1913 * @param state the state into which the slide should be set 1914 */ 1915function setSlideToState(slide, state) 1916{ 1917 slides[slide]["viewGroup"].setAttribute("transform", slides[slide].initialView); 1918 1919 if (slides[slide]["effects"]) 1920 { 1921 if (state == STATE_END) 1922 { 1923 for (var counter = 0; counter < slides[slide]["effects"].length; counter++) 1924 { 1925 for (var subCounter = 0; subCounter < slides[slide]["effects"][counter].length; subCounter++) 1926 { 1927 var effect = slides[slide]["effects"][counter][subCounter]; 1928 if (effect["effect"] == "fade") 1929 fade(effect["dir"], effect["element"], STATE_END, effect["options"]); 1930 else if (effect["effect"] == "appear") 1931 appear(effect["dir"], effect["element"], STATE_END, effect["options"]); 1932 else if (effect["effect"] == "pop") 1933 pop(effect["dir"], effect["element"], STATE_END, effect["options"]); 1934 else if (effect["effect"] == "view") 1935 view(effect["dir"], effect["element"], STATE_END, effect["options"]); 1936 } 1937 } 1938 } 1939 else if (state == STATE_START) 1940 { 1941 for (var counter = slides[slide]["effects"].length - 1; counter >= 0; counter--) 1942 { 1943 for (var subCounter = 0; subCounter < slides[slide]["effects"][counter].length; subCounter++) 1944 { 1945 var effect = slides[slide]["effects"][counter][subCounter]; 1946 if (effect["effect"] == "fade") 1947 fade(parseInt(effect["dir"]) * -1, effect["element"], STATE_START, effect["options"]); 1948 else if (effect["effect"] == "appear") 1949 appear(parseInt(effect["dir"]) * -1, effect["element"], STATE_START, effect["options"]); 1950 else if (effect["effect"] == "pop") 1951 pop(parseInt(effect["dir"]) * -1, effect["element"], STATE_START, effect["options"]); 1952 else if (effect["effect"] == "view") 1953 view(parseInt(effect["dir"]) * -1, effect["element"], STATE_START, effect["options"]); 1954 } 1955 } 1956 } 1957 else 1958 { 1959 setSlideToState(slide, STATE_START); 1960 1961 for (var counter = 0; counter < slides[slide]["effects"].length && counter < state; counter++) 1962 { 1963 for (var subCounter = 0; subCounter < slides[slide]["effects"][counter].length; subCounter++) 1964 { 1965 var effect = slides[slide]["effects"][counter][subCounter]; 1966 if (effect["effect"] == "fade") 1967 fade(effect["dir"], effect["element"], STATE_END, effect["options"]); 1968 else if (effect["effect"] == "appear") 1969 appear(effect["dir"], effect["element"], STATE_END, effect["options"]); 1970 else if (effect["effect"] == "pop") 1971 pop(effect["dir"], effect["element"], STATE_END, effect["options"]); 1972 else if (effect["effect"] == "view") 1973 view(effect["dir"], effect["element"], STATE_END, effect["options"]); 1974 } 1975 } 1976 } 1977 } 1978 1979 window.location.hash = (activeSlide + 1) + '_' + activeEffect; 1980} 1981 1982/** Convenience function to translate a attribute string into a dictionary. 1983 * 1984 * @param str the attribute string 1985 * @return a dictionary 1986 * @see dictToPropStr 1987 */ 1988function propStrToDict(str) 1989{ 1990 var list = str.split(";"); 1991 var obj = new Object(); 1992 1993 for (var counter = 0; counter < list.length; counter++) 1994 { 1995 var subStr = list[counter]; 1996 var subList = subStr.split(":"); 1997 if (subList.length == 2) 1998 { 1999 obj[subList[0]] = subList[1]; 2000 } 2001 } 2002 2003 return obj; 2004} 2005 2006/** Convenience function to translate a dictionary into a string that can be used as an attribute. 2007 * 2008 * @param dict the dictionary to convert 2009 * @return a string that can be used as an attribute 2010 * @see propStrToDict 2011 */ 2012function dictToPropStr(dict) 2013{ 2014 var str = ""; 2015 2016 for (var key in dict) 2017 { 2018 str += key + ":" + dict[key] + ";"; 2019 } 2020 2021 return str; 2022} 2023 2024/** Sub-function to add a suffix to the ids of the node and all its children. 2025 * 2026 * @param node the node to change 2027 * @param suffix the suffix to add 2028 * @param replace dictionary of replaced ids 2029 * @see suffixNodeIds 2030 */ 2031function suffixNoneIds_sub(node, suffix, replace) 2032{ 2033 if (node.nodeType == 1) 2034 { 2035 if (node.getAttribute("id")) 2036 { 2037 var id = node.getAttribute("id") 2038 replace["#" + id] = id + suffix; 2039 node.setAttribute("id", id + suffix); 2040 } 2041 2042 if ((node.nodeName == "use") && (node.getAttributeNS(NSS["xlink"], "href")) && (replace[node.getAttribute(NSS["xlink"], "href")])) 2043 node.setAttribute(NSS["xlink"], "href", node.getAttribute(NSS["xlink"], "href") + suffix); 2044 2045 if (node.childNodes) 2046 { 2047 for (var counter = 0; counter < node.childNodes.length; counter++) 2048 suffixNoneIds_sub(node.childNodes[counter], suffix, replace); 2049 } 2050 } 2051} 2052 2053/** Function to add a suffix to the ids of the node and all its children. 2054 * 2055 * @param node the node to change 2056 * @param suffix the suffix to add 2057 * @return the changed node 2058 * @see suffixNodeIds_sub 2059 */ 2060function suffixNodeIds(node, suffix) 2061{ 2062 var replace = new Object(); 2063 2064 suffixNoneIds_sub(node, suffix, replace); 2065 2066 return node; 2067} 2068 2069/** Function to build a progress bar. 2070 * 2071 * @param parent node to attach the progress bar to 2072 */ 2073function createProgressBar(parent_node) 2074{ 2075 var g = document.createElementNS(NSS["svg"], "g"); 2076 g.setAttribute("clip-path", "url(#jessyInkSlideClipPath)"); 2077 g.setAttribute("id", "layer_progress_bar"); 2078 g.setAttribute("style", "display: none;"); 2079 2080 var rect_progress_bar = document.createElementNS(NSS["svg"], "rect"); 2081 rect_progress_bar.setAttribute("style", "marker: none; fill: rgb(128, 128, 128); stroke: none;"); 2082 rect_progress_bar.setAttribute("id", "rect_progress_bar"); 2083 rect_progress_bar.setAttribute("x", 0); 2084 rect_progress_bar.setAttribute("y", 0.99 * HEIGHT); 2085 rect_progress_bar.setAttribute("width", 0); 2086 rect_progress_bar.setAttribute("height", 0.01 * HEIGHT); 2087 g.appendChild(rect_progress_bar); 2088 2089 var circle_timer_indicator = document.createElementNS(NSS["svg"], "circle"); 2090 circle_timer_indicator.setAttribute("style", "marker: none; fill: rgb(255, 0, 0); stroke: none;"); 2091 circle_timer_indicator.setAttribute("id", "circle_timer_indicator"); 2092 circle_timer_indicator.setAttribute("cx", 0.005 * HEIGHT); 2093 circle_timer_indicator.setAttribute("cy", 0.995 * HEIGHT); 2094 circle_timer_indicator.setAttribute("r", 0.005 * HEIGHT); 2095 g.appendChild(circle_timer_indicator); 2096 2097 parent_node.appendChild(g); 2098} 2099 2100/** Function to hide the progress bar. 2101 * 2102 */ 2103function hideProgressBar() 2104{ 2105 var progress_bar = document.getElementById("layer_progress_bar"); 2106 2107 if (!progress_bar) 2108 { 2109 return; 2110 } 2111 2112 progress_bar.setAttribute("style", "display: none;"); 2113} 2114 2115/** Function to show the progress bar. 2116 * 2117 */ 2118function showProgressBar() 2119{ 2120 var progress_bar = document.getElementById("layer_progress_bar"); 2121 2122 if (!progress_bar) 2123 { 2124 return; 2125 } 2126 2127 progress_bar.setAttribute("style", "display: inherit;"); 2128} 2129 2130/** Set progress bar value. 2131 * 2132 * @param value the current slide number 2133 * 2134 */ 2135function setProgressBarValue(value) 2136{ 2137 var rect_progress_bar = document.getElementById("rect_progress_bar"); 2138 2139 if (!rect_progress_bar) 2140 { 2141 return; 2142 } 2143 2144 if (value < 1) 2145 { 2146 // First slide, assumed to be the title of the presentation 2147 var x = 0; 2148 var w = 0.01 * HEIGHT; 2149 } 2150 else if (value >= slides.length - 1) 2151 { 2152 // Last slide, assumed to be the end of the presentation 2153 var x = WIDTH - 0.01 * HEIGHT; 2154 var w = 0.01 * HEIGHT; 2155 } 2156 else 2157 { 2158 value -= 1; 2159 value /= (slides.length - 2); 2160 2161 var x = WIDTH * value; 2162 var w = WIDTH / (slides.length - 2); 2163 } 2164 2165 rect_progress_bar.setAttribute("x", x); 2166 rect_progress_bar.setAttribute("width", w); 2167} 2168 2169/** Set time indicator. 2170 * 2171 * @param value the percentage of time elapse so far between 0.0 and 1.0 2172 * 2173 */ 2174function setTimeIndicatorValue(value) 2175{ 2176 var circle_timer_indicator = document.getElementById("circle_timer_indicator"); 2177 2178 if (!circle_timer_indicator) 2179 { 2180 return; 2181 } 2182 2183 if (value < 0.0) 2184 { 2185 value = 0.0; 2186 } 2187 2188 if (value > 1.0) 2189 { 2190 value = 1.0; 2191 } 2192 2193 var cx = (WIDTH - 0.01 * HEIGHT) * value + 0.005 * HEIGHT; 2194 circle_timer_indicator.setAttribute("cx", cx); 2195} 2196 2197/** Update timer. 2198 * 2199 */ 2200function updateTimer() 2201{ 2202 timer_elapsed += 1; 2203 setTimeIndicatorValue((timer_elapsed - timer_start) / (60 * timer_duration)); 2204} 2205 2206/** Convert screen coordinates to document coordinates. 2207 * 2208 * @param e event with screen coordinates 2209 * 2210 * @return coordinates in SVG file coordinate system 2211 */ 2212function calcCoord(e) 2213{ 2214 var svgPoint = document.documentElement.createSVGPoint(); 2215 svgPoint.x = e.clientX + window.pageXOffset; 2216 svgPoint.y = e.clientY + window.pageYOffset; 2217 2218 var matrix = slides[activeSlide]["element"].getScreenCTM(); 2219 2220 if (slides[activeSlide]["viewGroup"]) 2221 matrix = slides[activeSlide]["viewGroup"].getScreenCTM(); 2222 2223 svgPoint = svgPoint.matrixTransform(matrix.inverse()); 2224 return svgPoint; 2225} 2226 2227/** Add slide. 2228 * 2229 * @param after_slide after which slide the new slide should be inserted into the presentation 2230 */ 2231function addSlide(after_slide) 2232{ 2233 number_of_added_slides++; 2234 2235 var g = document.createElementNS(NSS["svg"], "g"); 2236 g.setAttribute("clip-path", "url(#jessyInkSlideClipPath)"); 2237 g.setAttribute("id", "Whiteboard " + Date() + " presentation copy"); 2238 g.setAttribute("style", "display: none;"); 2239 2240 var new_slide = new Object(); 2241 new_slide["element"] = g; 2242 2243 // Set build in transition. 2244 new_slide["transitionIn"] = new Object(); 2245 var dict = defaultTransitionInDict; 2246 new_slide["transitionIn"]["name"] = dict["name"]; 2247 new_slide["transitionIn"]["options"] = new Object(); 2248 2249 for (key in dict) 2250 if (key != "name") 2251 new_slide["transitionIn"]["options"][key] = dict[key]; 2252 2253 // Set build out transition. 2254 new_slide["transitionOut"] = new Object(); 2255 dict = defaultTransitionOutDict; 2256 new_slide["transitionOut"]["name"] = dict["name"]; 2257 new_slide["transitionOut"]["options"] = new Object(); 2258 2259 for (key in dict) 2260 if (key != "name") 2261 new_slide["transitionOut"]["options"][key] = dict[key]; 2262 2263 // Copy master slide content. 2264 if (masterSlide) 2265 { 2266 var clonedNode = suffixNodeIds(masterSlide.cloneNode(true), "_" + Date() + " presentation_copy"); 2267 clonedNode.removeAttributeNS(NSS["inkscape"], "groupmode"); 2268 clonedNode.removeAttributeNS(NSS["inkscape"], "label"); 2269 clonedNode.style.display = "inherit"; 2270 2271 g.appendChild(clonedNode); 2272 } 2273 2274 // Substitute auto texts. 2275 substituteAutoTexts(g, "Whiteboard " + number_of_added_slides, "W" + number_of_added_slides, slides.length); 2276 2277 g.setAttribute("onmouseover", "if ((currentMode == INDEX_MODE) && ( activeSlide != " + (after_slide + 1) + ")) { indexSetActiveSlide(" + (after_slide + 1) + "); };"); 2278 2279 // Create a transform group. 2280 var transformGroup = document.createElementNS(NSS["svg"], "g"); 2281 2282 // Add content to transform group. 2283 while (g.firstChild) 2284 transformGroup.appendChild(g.firstChild); 2285 2286 // Transfer the transform attribute from the node to the transform group. 2287 if (g.getAttribute("transform")) 2288 { 2289 transformGroup.setAttribute("transform", g.getAttribute("transform")); 2290 g.removeAttribute("transform"); 2291 } 2292 2293 // Create a view group. 2294 var viewGroup = document.createElementNS(NSS["svg"], "g"); 2295 2296 viewGroup.appendChild(transformGroup); 2297 new_slide["viewGroup"] = g.appendChild(viewGroup); 2298 2299 // Insert background. 2300 if (BACKGROUND_COLOR != null) 2301 { 2302 var rectNode = document.createElementNS(NSS["svg"], "rect"); 2303 2304 rectNode.setAttribute("x", 0); 2305 rectNode.setAttribute("y", 0); 2306 rectNode.setAttribute("width", WIDTH); 2307 rectNode.setAttribute("height", HEIGHT); 2308 rectNode.setAttribute("id", "jessyInkBackground" + Date()); 2309 rectNode.setAttribute("fill", BACKGROUND_COLOR); 2310 2311 new_slide["viewGroup"].insertBefore(rectNode, new_slide["viewGroup"].firstChild); 2312 } 2313 2314 // Set initial view even if there are no other views. 2315 var matrixOld = (new matrixSVG()).fromElements(1, 0, 0, 0, 1, 0, 0, 0, 1); 2316 2317 new_slide["viewGroup"].setAttribute("transform", matrixOld.toAttribute()); 2318 new_slide.initialView = matrixOld.toAttribute(); 2319 2320 // Insert slide 2321 var node = slides[after_slide]["element"]; 2322 var next_node = node.nextSibling; 2323 var parent_node = node.parentNode; 2324 2325 if (next_node) 2326 { 2327 parent_node.insertBefore(g, next_node); 2328 } 2329 else 2330 { 2331 parent_node.appendChild(g); 2332 } 2333 2334 g = document.createElementNS(NSS["svg"], "g"); 2335 g.setAttributeNS(NSS["inkscape"], "groupmode", "layer"); 2336 g.setAttributeNS(NSS["inkscape"], "label", "Whiteboard " + number_of_added_slides); 2337 g.setAttribute("clip-path", "url(#jessyInkSlideClipPath)"); 2338 g.setAttribute("id", "Whiteboard " + Date()); 2339 g.setAttribute("style", "display: none;"); 2340 2341 new_slide["original_element"] = g; 2342 2343 node = slides[after_slide]["original_element"]; 2344 next_node = node.nextSibling; 2345 parent_node = node.parentNode; 2346 2347 if (next_node) 2348 { 2349 parent_node.insertBefore(g, next_node); 2350 } 2351 else 2352 { 2353 parent_node.appendChild(g); 2354 } 2355 2356 before_new_slide = slides.slice(0, after_slide + 1); 2357 after_new_slide = slides.slice(after_slide + 1); 2358 slides = before_new_slide.concat(new_slide, after_new_slide); 2359 2360 //resetting the counter attributes on the slides that follow the new slide... 2361 for (var counter = after_slide+2; counter < slides.length; counter++) 2362 { 2363 slides[counter]["element"].setAttribute("onmouseover", "if ((currentMode == INDEX_MODE) && ( activeSlide != " + counter + ")) { indexSetActiveSlide(" + counter + "); };"); 2364 } 2365} 2366 2367/** Convenience function to obtain a transformation matrix from a point matrix. 2368 * 2369 * @param mPoints Point matrix. 2370 * @return A transformation matrix. 2371 */ 2372function pointMatrixToTransformation(mPoints) 2373{ 2374 mPointsOld = (new matrixSVG()).fromElements(0, WIDTH, WIDTH, 0, 0, HEIGHT, 1, 1, 1); 2375 2376 return mPointsOld.mult(mPoints.inv()); 2377} 2378 2379/** Convenience function to obtain a matrix with three corners of a rectangle. 2380 * 2381 * @param rect an svg rectangle 2382 * @return a matrixSVG containing three corners of the rectangle 2383 */ 2384function rectToMatrix(rect) 2385{ 2386 rectWidth = rect.getBBox().width; 2387 rectHeight = rect.getBBox().height; 2388 rectX = rect.getBBox().x; 2389 rectY = rect.getBBox().y; 2390 rectXcorr = 0; 2391 rectYcorr = 0; 2392 2393 scaleX = WIDTH / rectWidth; 2394 scaleY = HEIGHT / rectHeight; 2395 2396 if (scaleX > scaleY) 2397 { 2398 scaleX = scaleY; 2399 rectXcorr -= (WIDTH / scaleX - rectWidth) / 2; 2400 rectWidth = WIDTH / scaleX; 2401 } 2402 else 2403 { 2404 scaleY = scaleX; 2405 rectYcorr -= (HEIGHT / scaleY - rectHeight) / 2; 2406 rectHeight = HEIGHT / scaleY; 2407 } 2408 2409 if (rect.transform.baseVal.numberOfItems < 1) 2410 { 2411 mRectTrans = (new matrixSVG()).fromElements(1, 0, 0, 0, 1, 0, 0, 0, 1); 2412 } 2413 else 2414 { 2415 mRectTrans = (new matrixSVG()).fromSVGMatrix(rect.transform.baseVal.consolidate().matrix); 2416 } 2417 2418 newBasePoints = (new matrixSVG()).fromElements(rectX, rectX, rectX, rectY, rectY, rectY, 1, 1, 1); 2419 newVectors = (new matrixSVG()).fromElements(rectXcorr, rectXcorr + rectWidth, rectXcorr + rectWidth, rectYcorr, rectYcorr, rectYcorr + rectHeight, 0, 0, 0); 2420 2421 return mRectTrans.mult(newBasePoints.add(newVectors)); 2422} 2423 2424/** Function to handle JessyInk elements. 2425 * 2426 * @param node Element node. 2427 */ 2428function handleElement(node) 2429{ 2430 if (node.getAttributeNS(NSS['jessyink'], 'element') == 'core.video') 2431 { 2432 var url; 2433 var width; 2434 var height; 2435 var x; 2436 var y; 2437 var transform; 2438 2439 var tspans = node.getElementsByTagNameNS("http://www.w3.org/2000/svg", "tspan"); 2440 2441 for (var tspanCounter = 0; tspanCounter < tspans.length; tspanCounter++) 2442 { 2443 if (tspans[tspanCounter].getAttributeNS("https://launchpad.net/jessyink", "video") == "url") 2444 { 2445 url = tspans[tspanCounter].firstChild.nodeValue; 2446 } 2447 } 2448 2449 var rects = node.getElementsByTagNameNS("http://www.w3.org/2000/svg", "rect"); 2450 2451 for (var rectCounter = 0; rectCounter < rects.length; rectCounter++) 2452 { 2453 if (rects[rectCounter].getAttributeNS("https://launchpad.net/jessyink", "video") == "rect") 2454 { 2455 x = rects[rectCounter].getAttribute("x"); 2456 y = rects[rectCounter].getAttribute("y"); 2457 width = rects[rectCounter].getAttribute("width"); 2458 height = rects[rectCounter].getAttribute("height"); 2459 transform = rects[rectCounter].getAttribute("transform"); 2460 } 2461 } 2462 2463 for (var childCounter = 0; childCounter < node.childNodes.length; childCounter++) 2464 { 2465 if (node.childNodes[childCounter].nodeType == 1) 2466 { 2467 if (node.childNodes[childCounter].style) 2468 { 2469 node.childNodes[childCounter].style.display = 'none'; 2470 } 2471 else 2472 { 2473 node.childNodes[childCounter].setAttribute("style", "display: none;"); 2474 } 2475 } 2476 } 2477 2478 var foreignNode = document.createElementNS("http://www.w3.org/2000/svg", "foreignObject"); 2479 foreignNode.setAttribute("x", x); 2480 foreignNode.setAttribute("y", y); 2481 foreignNode.setAttribute("width", width); 2482 foreignNode.setAttribute("height", height); 2483 foreignNode.setAttribute("transform", transform); 2484 2485 var videoNode = document.createElementNS("http://www.w3.org/1999/xhtml", "video"); 2486 videoNode.setAttribute("src", url); 2487 2488 foreignNode.appendChild(videoNode); 2489 node.appendChild(foreignNode); 2490 } 2491} 2492 2493/** Class processing the location hash. 2494 * 2495 * @param str location hash 2496 */ 2497function LocationHash(str) 2498{ 2499 this.slideNumber = 0; 2500 this.effectNumber = 0; 2501 2502 str = str.substr(1, str.length - 1); 2503 2504 var parts = str.split('_'); 2505 2506 // Try to extract slide number. 2507 if (parts.length >= 1) 2508 { 2509 try 2510 { 2511 var slideNumber = parseInt(parts[0]); 2512 2513 if (!isNaN(slideNumber)) 2514 { 2515 this.slideNumber = slideNumber - 1; 2516 } 2517 } 2518 catch (e) 2519 { 2520 } 2521 } 2522 2523 // Try to extract effect number. 2524 if (parts.length >= 2) 2525 { 2526 try 2527 { 2528 var effectNumber = parseInt(parts[1]); 2529 2530 if (!isNaN(effectNumber)) 2531 { 2532 this.effectNumber = effectNumber; 2533 } 2534 } 2535 catch (e) 2536 { 2537 } 2538 } 2539} 2540 2541/** Class representing an svg matrix. 2542*/ 2543function matrixSVG() 2544{ 2545 this.e11 = 0; // a 2546 this.e12 = 0; // c 2547 this.e13 = 0; // e 2548 this.e21 = 0; // b 2549 this.e22 = 0; // d 2550 this.e23 = 0; // f 2551 this.e31 = 0; 2552 this.e32 = 0; 2553 this.e33 = 0; 2554} 2555 2556/** Constructor function. 2557 * 2558 * @param a element a (i.e. 1, 1) as described in the svg standard. 2559 * @param b element b (i.e. 2, 1) as described in the svg standard. 2560 * @param c element c (i.e. 1, 2) as described in the svg standard. 2561 * @param d element d (i.e. 2, 2) as described in the svg standard. 2562 * @param e element e (i.e. 1, 3) as described in the svg standard. 2563 * @param f element f (i.e. 2, 3) as described in the svg standard. 2564 */ 2565matrixSVG.prototype.fromSVGElements = function(a, b, c, d, e, f) 2566{ 2567 this.e11 = a; 2568 this.e12 = c; 2569 this.e13 = e; 2570 this.e21 = b; 2571 this.e22 = d; 2572 this.e23 = f; 2573 this.e31 = 0; 2574 this.e32 = 0; 2575 this.e33 = 1; 2576 2577 return this; 2578} 2579 2580/** Constructor function. 2581 * 2582 * @param matrix an svg matrix as described in the svg standard. 2583 */ 2584matrixSVG.prototype.fromSVGMatrix = function(m) 2585{ 2586 this.e11 = m.a; 2587 this.e12 = m.c; 2588 this.e13 = m.e; 2589 this.e21 = m.b; 2590 this.e22 = m.d; 2591 this.e23 = m.f; 2592 this.e31 = 0; 2593 this.e32 = 0; 2594 this.e33 = 1; 2595 2596 return this; 2597} 2598 2599/** Constructor function. 2600 * 2601 * @param e11 element 1, 1 of the matrix. 2602 * @param e12 element 1, 2 of the matrix. 2603 * @param e13 element 1, 3 of the matrix. 2604 * @param e21 element 2, 1 of the matrix. 2605 * @param e22 element 2, 2 of the matrix. 2606 * @param e23 element 2, 3 of the matrix. 2607 * @param e31 element 3, 1 of the matrix. 2608 * @param e32 element 3, 2 of the matrix. 2609 * @param e33 element 3, 3 of the matrix. 2610 */ 2611matrixSVG.prototype.fromElements = function(e11, e12, e13, e21, e22, e23, e31, e32, e33) 2612{ 2613 this.e11 = e11; 2614 this.e12 = e12; 2615 this.e13 = e13; 2616 this.e21 = e21; 2617 this.e22 = e22; 2618 this.e23 = e23; 2619 this.e31 = e31; 2620 this.e32 = e32; 2621 this.e33 = e33; 2622 2623 return this; 2624} 2625 2626/** Constructor function. 2627 * 2628 * @param attrString string value of the "transform" attribute (currently only "matrix" is accepted) 2629 */ 2630matrixSVG.prototype.fromAttribute = function(attrString) 2631{ 2632 str = attrString.substr(7, attrString.length - 8); 2633 2634 str = str.trim(); 2635 2636 strArray = str.split(","); 2637 2638 // Opera does not use commas to separate the values of the matrix, only spaces. 2639 if (strArray.length != 6) 2640 strArray = str.split(" "); 2641 2642 this.e11 = parseFloat(strArray[0]); 2643 this.e21 = parseFloat(strArray[1]); 2644 this.e31 = 0; 2645 this.e12 = parseFloat(strArray[2]); 2646 this.e22 = parseFloat(strArray[3]); 2647 this.e32 = 0; 2648 this.e13 = parseFloat(strArray[4]); 2649 this.e23 = parseFloat(strArray[5]); 2650 this.e33 = 1; 2651 2652 return this; 2653} 2654 2655/** Output function 2656 * 2657 * @return a string that can be used as the "transform" attribute. 2658 */ 2659matrixSVG.prototype.toAttribute = function() 2660{ 2661 return "matrix(" + this.e11 + ", " + this.e21 + ", " + this.e12 + ", " + this.e22 + ", " + this.e13 + ", " + this.e23 + ")"; 2662} 2663 2664/** Matrix nversion. 2665 * 2666 * @return the inverse of the matrix 2667 */ 2668matrixSVG.prototype.inv = function() 2669{ 2670 out = new matrixSVG(); 2671 2672 det = this.e11 * (this.e33 * this.e22 - this.e32 * this.e23) - this.e21 * (this.e33 * this.e12 - this.e32 * this.e13) + this.e31 * (this.e23 * this.e12 - this.e22 * this.e13); 2673 2674 out.e11 = (this.e33 * this.e22 - this.e32 * this.e23) / det; 2675 out.e12 = -(this.e33 * this.e12 - this.e32 * this.e13) / det; 2676 out.e13 = (this.e23 * this.e12 - this.e22 * this.e13) / det; 2677 out.e21 = -(this.e33 * this.e21 - this.e31 * this.e23) / det; 2678 out.e22 = (this.e33 * this.e11 - this.e31 * this.e13) / det; 2679 out.e23 = -(this.e23 * this.e11 - this.e21 * this.e13) / det; 2680 out.e31 = (this.e32 * this.e21 - this.e31 * this.e22) / det; 2681 out.e32 = -(this.e32 * this.e11 - this.e31 * this.e12) / det; 2682 out.e33 = (this.e22 * this.e11 - this.e21 * this.e12) / det; 2683 2684 return out; 2685} 2686 2687/** Matrix multiplication. 2688 * 2689 * @param op another svg matrix 2690 * @return this * op 2691 */ 2692matrixSVG.prototype.mult = function(op) 2693{ 2694 out = new matrixSVG(); 2695 2696 out.e11 = this.e11 * op.e11 + this.e12 * op.e21 + this.e13 * op.e31; 2697 out.e12 = this.e11 * op.e12 + this.e12 * op.e22 + this.e13 * op.e32; 2698 out.e13 = this.e11 * op.e13 + this.e12 * op.e23 + this.e13 * op.e33; 2699 out.e21 = this.e21 * op.e11 + this.e22 * op.e21 + this.e23 * op.e31; 2700 out.e22 = this.e21 * op.e12 + this.e22 * op.e22 + this.e23 * op.e32; 2701 out.e23 = this.e21 * op.e13 + this.e22 * op.e23 + this.e23 * op.e33; 2702 out.e31 = this.e31 * op.e11 + this.e32 * op.e21 + this.e33 * op.e31; 2703 out.e32 = this.e31 * op.e12 + this.e32 * op.e22 + this.e33 * op.e32; 2704 out.e33 = this.e31 * op.e13 + this.e32 * op.e23 + this.e33 * op.e33; 2705 2706 return out; 2707} 2708 2709/** Matrix addition. 2710 * 2711 * @param op another svg matrix 2712 * @return this + op 2713 */ 2714matrixSVG.prototype.add = function(op) 2715{ 2716 out = new matrixSVG(); 2717 2718 out.e11 = this.e11 + op.e11; 2719 out.e12 = this.e12 + op.e12; 2720 out.e13 = this.e13 + op.e13; 2721 out.e21 = this.e21 + op.e21; 2722 out.e22 = this.e22 + op.e22; 2723 out.e23 = this.e23 + op.e23; 2724 out.e31 = this.e31 + op.e31; 2725 out.e32 = this.e32 + op.e32; 2726 out.e33 = this.e33 + op.e33; 2727 2728 return out; 2729} 2730 2731/** Matrix mixing. 2732 * 2733 * @param op another svg matrix 2734 * @parma contribOp contribution of the other matrix (0 <= contribOp <= 1) 2735 * @return (1 - contribOp) * this + contribOp * op 2736 */ 2737matrixSVG.prototype.mix = function(op, contribOp) 2738{ 2739 contribThis = 1.0 - contribOp; 2740 out = new matrixSVG(); 2741 2742 out.e11 = contribThis * this.e11 + contribOp * op.e11; 2743 out.e12 = contribThis * this.e12 + contribOp * op.e12; 2744 out.e13 = contribThis * this.e13 + contribOp * op.e13; 2745 out.e21 = contribThis * this.e21 + contribOp * op.e21; 2746 out.e22 = contribThis * this.e22 + contribOp * op.e22; 2747 out.e23 = contribThis * this.e23 + contribOp * op.e23; 2748 out.e31 = contribThis * this.e31 + contribOp * op.e31; 2749 out.e32 = contribThis * this.e32 + contribOp * op.e32; 2750 out.e33 = contribThis * this.e33 + contribOp * op.e33; 2751 2752 return out; 2753} 2754 2755/** Trimming function for strings. 2756*/ 2757String.prototype.trim = function() 2758{ 2759 return this.replace(/^\s+|\s+$/g, ''); 2760} 2761 2762/** SVGElement.getTransformToElement polyfill */ 2763SVGElement.prototype.getTransformToElement = SVGElement.prototype.getTransformToElement || function(elem) { 2764 return elem.getScreenCTM().inverse().multiply(this.getScreenCTM()); 2765}; 2766</svg:script></svg> 2767