dicetower.svg 111 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112
  1. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2. <svg
  3. xmlns:ns1="http://sozi.baierouge.fr"
  4. xmlns:dc="http://purl.org/dc/elements/1.1/"
  5. xmlns:cc="http://creativecommons.org/ns#"
  6. xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  7. xmlns:svg="http://www.w3.org/2000/svg"
  8. xmlns="http://www.w3.org/2000/svg"
  9. xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
  10. xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
  11. viewBox="0 0 399.99999 299.99999"
  12. sodipodi:docname="dicetower.svg"
  13. inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
  14. version="1.1"
  15. id="svg3962"
  16. height="300mm"
  17. width="400mm">
  18. <sodipodi:namedview
  19. inkscape:document-rotation="0"
  20. inkscape:bbox-nodes="true"
  21. inkscape:snap-bbox="true"
  22. inkscape:snap-nodes="false"
  23. inkscape:guide-bbox="true"
  24. showguides="true"
  25. inkscape:object-paths="false"
  26. inkscape:object-nodes="true"
  27. inkscape:window-maximized="1"
  28. inkscape:window-y="-9"
  29. inkscape:window-x="-9"
  30. inkscape:window-height="1001"
  31. inkscape:window-width="1920"
  32. units="mm"
  33. showgrid="false"
  34. inkscape:current-layer="layer1"
  35. inkscape:document-units="mm"
  36. inkscape:cy="310.67374"
  37. inkscape:cx="118.39732"
  38. inkscape:zoom="1.2319838"
  39. inkscape:pageshadow="2"
  40. inkscape:pageopacity="0.0"
  41. borderopacity="1.0"
  42. bordercolor="#666666"
  43. pagecolor="#ffffff"
  44. id="base"
  45. inkscape:snap-smooth-nodes="true">
  46. <sodipodi:guide
  47. id="guide3374"
  48. orientation="0,1"
  49. position="209.26113,52.46408" />
  50. <sodipodi:guide
  51. id="guide3376"
  52. orientation="0,1"
  53. position="283.63939,72.804365" />
  54. </sodipodi:namedview>
  55. <defs
  56. id="defs3964" />
  57. <metadata
  58. id="metadata3967">
  59. <rdf:RDF>
  60. <cc:Work
  61. rdf:about="">
  62. <dc:format>image/svg+xml</dc:format>
  63. <dc:type
  64. rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
  65. <dc:title />
  66. </cc:Work>
  67. </rdf:RDF>
  68. </metadata>
  69. <g
  70. style="display:inline"
  71. inkscape:label="Work"
  72. inkscape:groupmode="layer"
  73. id="layer1"
  74. transform="translate(0,23.346473)">
  75. <path
  76. inkscape:connector-curvature="0"
  77. id="rect3340"
  78. d="M 186.39674,-11.163192 V 133.83675 h 80.00008 V -11.163192 Z m 73.50015,3.9952093 1.49986,2.598428 -25.98099,14.9996727 -1.49986,-2.5978794 z m -67.00022,17.5981007 43.30127,25.000369 -1.49986,2.597879 -43.30127,-24.99982 z m 67.00022,37.89054 1.49986,2.597878 -43.30128,24.999819 -1.49985,-2.597878 z m -67.00022,38.790123 69.28225,40.000039 -1.50041,2.59788 -69.2817,-40.000041 z"
  79. style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffff00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.6299;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
  80. <rect
  81. y="-11.163192"
  82. x="266.39639"
  83. height="113.27361"
  84. width="60.000004"
  85. id="rect3342"
  86. style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.6299;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
  87. <rect
  88. style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:11.1487;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
  89. id="rect3378"
  90. width="65.999763"
  91. height="145.00002"
  92. x="5.8258758"
  93. y="-11.163196" />
  94. <path
  95. inkscape:connector-curvature="0"
  96. id="rect3362-0"
  97. d="m 8.8255854,133.83682 v 5.00008 H 5.8258758 v 29.9999 h 2.9997096 v 1.99981 h 1.4210196 c 3.95747,-2.68828 15.51605,-8.20244 28.57941,-8.20346 13.05359,0.004 24.598487,5.51719 28.552987,8.20346 h 1.44693 v -1.99981 h 2.99971 v -29.9999 h -2.99971 v -5.00008 z"
  98. style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff00ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.6299;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
  99. sodipodi:nodetypes="cccccccccccccccc" />
  100. <path
  101. inkscape:connector-curvature="0"
  102. id="rect3346-3"
  103. d="m 102.82546,196.83688 h 5.00007 v 2.99971 h 50.00019 v -2.99971 h 1.99981 v -1.42102 c -2.68828,-3.95746 -8.20243,-15.51606 -8.20345,-28.57941 0.004,-13.05359 5.51718,-24.59846 8.20345,-28.55296 v -1.44696 h -1.99981 v -2.99971 h -50.00019 v 2.99971 h -5.00007 z"
  104. style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff00ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.6299;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
  105. sodipodi:nodetypes="cccccccccccccccc" />
  106. <path
  107. inkscape:connector-curvature="0"
  108. id="rect3440-6"
  109. d="m 159.82553,196.83688 h 5.00008 v 3.00025 h 80.00008 v -3.00025 h 1.99981 v -1.42215 c -2.68815,-3.95728 -8.20227,-15.51501 -8.20345,-28.57774 0.004,-13.05359 5.51718,-24.59846 8.20345,-28.55296 v -1.44696 h -1.99981 v -3.00025 h -80.00008 v 3.00025 h -5.00008 z"
  110. style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff00ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.6299;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
  111. sodipodi:nodetypes="cccccccccccccccc" />
  112. <path
  113. style="color:#000000;font-variation-settings:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ff00ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.6299;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1"
  114. d="m 246.82551,196.83688 h 5.00007 v 2.99971 h 50.0002 v -2.99971 h 1.99981 v -1.42102 c -2.68828,-3.95746 -8.20243,-15.51606 -8.20345,-28.57941 0.004,-13.05359 5.51718,-24.59846 8.20345,-28.55296 v -1.44696 h -1.99981 v -2.99971 h -50.0002 v 2.99971 h -5.00008 z"
  115. id="path3797"
  116. inkscape:connector-curvature="0"
  117. sodipodi:nodetypes="cccccccccccccccc" />
  118. <path
  119. style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffff00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.6299;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
  120. d="M 167.34662,-11.163192 V 133.83675 H 87.346439 V -11.163192 Z m -73.500251,3.9952093 -1.49986,2.598428 25.981091,14.9996727 1.49986,-2.5978794 z m 67.000321,17.5981007 -43.30127,25.000369 1.49986,2.597879 43.30127,-24.99982 z m -67.000321,37.89054 -1.49986,2.597878 43.301381,24.999819 1.49985,-2.597878 z m 67.000321,38.790123 -69.282351,40.000039 1.50041,2.59788 69.281801,-40.000041 z"
  121. id="path3807"
  122. inkscape:connector-curvature="0" />
  123. <g
  124. id="g154">
  125. <g
  126. transform="matrix(1,0,0,-1.4999995,-2.8535004,28.759089)"
  127. id="g56">
  128. <rect
  129. style="opacity:0.65;fill:#ff00ff;stroke-width:9.75807;stop-color:#000000"
  130. id="rect52"
  131. width="3"
  132. height="5"
  133. x="74.679138"
  134. y="6.2815266" />
  135. <rect
  136. y="1.2815266"
  137. x="77.679138"
  138. height="10"
  139. width="3"
  140. id="rect54"
  141. style="opacity:0.65;fill:#ff00ff;stroke-width:13.8;stop-color:#000000" />
  142. </g>
  143. <rect
  144. transform="scale(-1,1)"
  145. y="-11.163196"
  146. x="-77.825638"
  147. height="23"
  148. width="6.0000038"
  149. id="rect96"
  150. style="opacity:0.65;fill:#ff00ff;stroke-width:29.5978;stop-color:#000000" />
  151. <g
  152. id="g104"
  153. transform="matrix(1,0,0,-1.4999995,-2.8534927,71.759112)">
  154. <rect
  155. y="6.2815266"
  156. x="74.679138"
  157. height="5"
  158. width="3"
  159. id="rect100"
  160. style="opacity:0.65;fill:#ff00ff;stroke-width:9.75807;stop-color:#000000" />
  161. <rect
  162. style="opacity:0.65;fill:#ff00ff;stroke-width:13.8;stop-color:#000000"
  163. id="rect102"
  164. width="3"
  165. height="10"
  166. x="77.679138"
  167. y="1.2815266" />
  168. </g>
  169. <g
  170. transform="matrix(1,0,0,-1.4999995,-2.8534927,112.75911)"
  171. id="g110">
  172. <rect
  173. style="opacity:0.65;fill:#ff00ff;stroke-width:9.75807;stop-color:#000000"
  174. id="rect106"
  175. width="3"
  176. height="5"
  177. x="74.679138"
  178. y="6.2815266" />
  179. <rect
  180. y="1.2815266"
  181. x="77.679138"
  182. height="10"
  183. width="3"
  184. id="rect108"
  185. style="opacity:0.65;fill:#ff00ff;stroke-width:13.8;stop-color:#000000" />
  186. </g>
  187. <rect
  188. style="opacity:0.65;fill:#ff00ff;stroke-width:27.6002;stop-color:#000000"
  189. id="rect114"
  190. width="6.0000076"
  191. height="20.000029"
  192. x="-77.825645"
  193. y="34.8368"
  194. transform="scale(-1,1)" />
  195. <rect
  196. transform="scale(-1,1)"
  197. y="77.836823"
  198. x="-77.825645"
  199. height="18"
  200. width="6"
  201. id="rect124"
  202. style="opacity:0.65;fill:#ff00ff;stroke-width:26.1838;stop-color:#000000" />
  203. <rect
  204. transform="scale(-1,1)"
  205. y="118.83682"
  206. x="-77.825645"
  207. height="15"
  208. width="6"
  209. id="rect126"
  210. style="opacity:0.65;fill:#ff00ff;stroke-width:23.9024;stop-color:#000000" />
  211. <rect
  212. style="opacity:0.65;fill:#00ff00;stroke-width:3.76969;stop-color:#000000"
  213. id="rect128"
  214. width="3"
  215. height="8"
  216. x="74.825638"
  217. y="26.8368" />
  218. <rect
  219. y="69.836823"
  220. x="74.825645"
  221. height="8"
  222. width="3"
  223. id="rect130"
  224. style="opacity:0.65;fill:#00ff00;stroke-width:3.76969;stop-color:#000000" />
  225. <rect
  226. style="opacity:0.65;fill:#00ff00;stroke-width:3.76969;stop-color:#000000"
  227. id="rect132"
  228. width="3"
  229. height="8"
  230. x="74.825645"
  231. y="110.83682" />
  232. </g>
  233. <g
  234. transform="rotate(180,79.586037,61.336815)"
  235. id="g188">
  236. <g
  237. id="g160"
  238. transform="matrix(1,0,0,-1.4999995,-2.8535004,28.759089)">
  239. <rect
  240. y="6.2815266"
  241. x="74.679138"
  242. height="5"
  243. width="3"
  244. id="rect156"
  245. style="opacity:0.65;fill:#ff00ff;stroke-width:9.75807;stop-color:#000000" />
  246. <rect
  247. style="opacity:0.65;fill:#ff00ff;stroke-width:13.8;stop-color:#000000"
  248. id="rect158"
  249. width="3"
  250. height="10"
  251. x="77.679138"
  252. y="1.2815266" />
  253. </g>
  254. <rect
  255. style="opacity:0.65;fill:#ff00ff;stroke-width:29.5978;stop-color:#000000"
  256. id="rect162"
  257. width="6.0000038"
  258. height="23"
  259. x="-77.825638"
  260. y="-11.163196"
  261. transform="scale(-1,1)" />
  262. <g
  263. transform="matrix(1,0,0,-1.4999995,-2.8534927,71.759112)"
  264. id="g168">
  265. <rect
  266. style="opacity:0.65;fill:#ff00ff;stroke-width:9.75807;stop-color:#000000"
  267. id="rect164"
  268. width="3"
  269. height="5"
  270. x="74.679138"
  271. y="6.2815266" />
  272. <rect
  273. y="1.2815266"
  274. x="77.679138"
  275. height="10"
  276. width="3"
  277. id="rect166"
  278. style="opacity:0.65;fill:#ff00ff;stroke-width:13.8;stop-color:#000000" />
  279. </g>
  280. <g
  281. id="g174"
  282. transform="matrix(1,0,0,-1.4999995,-2.8534927,112.75911)">
  283. <rect
  284. y="6.2815266"
  285. x="74.679138"
  286. height="5"
  287. width="3"
  288. id="rect170"
  289. style="opacity:0.65;fill:#ff00ff;stroke-width:9.75807;stop-color:#000000" />
  290. <rect
  291. style="opacity:0.65;fill:#ff00ff;stroke-width:13.8;stop-color:#000000"
  292. id="rect172"
  293. width="3"
  294. height="10"
  295. x="77.679138"
  296. y="1.2815266" />
  297. </g>
  298. <rect
  299. transform="scale(-1,1)"
  300. y="34.8368"
  301. x="-77.825645"
  302. height="20.000029"
  303. width="6.0000076"
  304. id="rect176"
  305. style="opacity:0.65;fill:#ff00ff;stroke-width:27.6002;stop-color:#000000" />
  306. <rect
  307. style="opacity:0.65;fill:#ff00ff;stroke-width:26.1838;stop-color:#000000"
  308. id="rect178"
  309. width="6"
  310. height="18"
  311. x="-77.825645"
  312. y="77.836823"
  313. transform="scale(-1,1)" />
  314. <rect
  315. style="opacity:0.65;fill:#ff00ff;stroke-width:23.9024;stop-color:#000000"
  316. id="rect180"
  317. width="6"
  318. height="15"
  319. x="-77.825645"
  320. y="118.83682"
  321. transform="scale(-1,1)" />
  322. <rect
  323. y="26.8368"
  324. x="74.825638"
  325. height="8"
  326. width="3"
  327. id="rect182"
  328. style="opacity:0.65;fill:#00ff00;stroke-width:3.76969;stop-color:#000000" />
  329. <rect
  330. style="opacity:0.65;fill:#00ff00;stroke-width:3.76969;stop-color:#000000"
  331. id="rect184"
  332. width="3"
  333. height="8"
  334. x="74.825645"
  335. y="69.836823" />
  336. <rect
  337. y="110.83682"
  338. x="74.825645"
  339. height="8"
  340. width="3"
  341. id="rect186"
  342. style="opacity:0.65;fill:#00ff00;stroke-width:3.76969;stop-color:#000000" />
  343. </g>
  344. <path
  345. transform="matrix(0.26458333,0,0,0.26458333,0,-23.346473)"
  346. d="M -306.71875 29.001953 L -306.71875 577.0332 L -57.271484 577.0332 L -34.59375 577.0332 L -34.59375 520.33984 L -57.271484 520.33984 L -57.271484 461.75781 L -45.931641 461.75781 L -45.931641 490.10352 L -34.59375 490.10352 L -34.59375 433.41016 L -34.59375 365.37891 L -57.271484 365.37891 L -57.271484 306.79688 L -45.931641 306.79688 L -45.931641 335.14258 L -34.59375 335.14258 L -34.59375 278.45117 L -34.59375 202.85938 L -57.271484 202.85938 L -57.271484 144.27734 L -45.931641 144.27734 L -45.931641 172.62305 L -34.59375 172.62305 L -34.59375 115.92969 L -34.59375 29.001953 L -57.271484 29.001953 L -306.71875 29.001953 z "
  347. style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:42.1368;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
  348. id="rect190" />
  349. </g>
  350. <script
  351. id="sozi-script"
  352. ns1:version="13.11-30213629">/*
  353. * Sozi - A presentation tool using the SVG standard
  354. *
  355. * Copyright (C) 2010-2013 Guillaume Savaton
  356. *
  357. * This program is dual licensed under the terms of the MIT license
  358. * or the GNU General Public License (GPL) version 3.
  359. * A copy of both licenses is provided in the doc/ folder of the
  360. * official release of Sozi.
  361. *
  362. * See http://sozi.baierouge.fr/wiki/en:license for details.
  363. */
  364. /**
  365. * Create or augment a namespace.
  366. *
  367. * &lt;p&gt;A typical use of this function is:&lt;/p&gt;
  368. *
  369. * &lt;pre&gt;
  370. * namespace(this, &quot;a.b.c&quot;, function (exports, globals) {
  371. * exports.foo = function (x) {
  372. * ...
  373. * };
  374. * });
  375. * &lt;/pre&gt;
  376. *
  377. * &lt;p&gt;where &lt;code&gt;this&lt;/code&gt; is the global object.&lt;/p&gt;
  378. *
  379. * &lt;p&gt;In this example, function &lt;code&gt;foo&lt;/code&gt; is exported and can be
  380. * called as &lt;code&gt;a.b.c.foo(someValue)&lt;/code&gt;.&lt;/p&gt;
  381. *
  382. * @memberOf _global_
  383. * @param globals The global object
  384. * @param {String} path The dot-separated path to the namespace
  385. * @param {Function} body A function to execute in the context of the namespace
  386. */
  387. function namespace(globals, path, body) {
  388. &quot;use strict&quot;;
  389. // Start name lookup in the global object
  390. var current = globals;
  391. // For each name in the given path
  392. path.split(&quot;.&quot;).forEach(function (name) {
  393. // If the current path element does not exist
  394. // in the current namespace, create a new sub-namespace
  395. if (typeof current[name] === &quot;undefined&quot;) {
  396. current[name] = {};
  397. }
  398. // Move to the namespace for the current path element
  399. current = current[name];
  400. });
  401. // Execute the given function in the last namespace
  402. if (body) {
  403. body(current, globals);
  404. }
  405. return current;
  406. }
  407. /*
  408. * Sozi - A presentation tool using the SVG standard
  409. *
  410. * Copyright (C) 2010-2013 Guillaume Savaton
  411. *
  412. * This program is dual licensed under the terms of the MIT license
  413. * or the GNU General Public License (GPL) version 3.
  414. * A copy of both licenses is provided in the doc/ folder of the
  415. * official release of Sozi.
  416. *
  417. * See http://sozi.baierouge.fr/wiki/en:license for details.
  418. */
  419. /**
  420. * @name sozi.events
  421. * @namespace A simple event system for Sozi.
  422. * @depend namespace.js
  423. */
  424. namespace(this, &quot;sozi.events&quot;, function (exports) {
  425. /** @lends sozi.events */
  426. &quot;use strict&quot;;
  427. /**
  428. * A registry of callback functions for each event type.
  429. *
  430. * &lt;p&gt;Call {@link sozi.events.listen} to add a new listener.&lt;/p&gt;
  431. */
  432. var listenerRegistry = {};
  433. /**
  434. * Adds a listener for a given event type.
  435. *
  436. * @memberOf sozi.events
  437. * @name listen
  438. * @function
  439. * @param {String} key The identifier of the event type to listen
  440. * @param {Function} handler The function to call when a corresponding event is fired
  441. */
  442. exports.listen = function (key, handler) {
  443. if (!listenerRegistry.hasOwnProperty(key)) {
  444. listenerRegistry[key] = [];
  445. }
  446. listenerRegistry[key].push(handler);
  447. };
  448. /**
  449. * Fire an event of a given type.
  450. *
  451. * &lt;p&gt;All event handlers added for the given event type are
  452. * executed.&lt;/p&gt;
  453. *
  454. * &lt;p&gt;Additional arguments provided to this function are passed
  455. * to the event handlers.&lt;/p&gt;
  456. *
  457. * @memberOf sozi.events
  458. * @name fire
  459. * @function
  460. * @param {String} key The identifier of the event type to fire
  461. */
  462. exports.fire = function (key) {
  463. var args = Array.prototype.slice.call(arguments, 1);
  464. if (listenerRegistry.hasOwnProperty(key)) {
  465. listenerRegistry[key].forEach(function (listener) {
  466. listener.apply(null, args);
  467. });
  468. }
  469. };
  470. });
  471. /*
  472. * Sozi - A presentation tool using the SVG standard
  473. *
  474. * Copyright (C) 2010-2013 Guillaume Savaton
  475. *
  476. * This program is dual licensed under the terms of the MIT license
  477. * or the GNU General Public License (GPL) version 3.
  478. * A copy of both licenses is provided in the doc/ folder of the
  479. * official release of Sozi.
  480. *
  481. * See http://sozi.baierouge.fr/wiki/en:license for details.
  482. */
  483. /**
  484. * @name sozi.proto
  485. * @namespace Helpers for prototype inheritance.
  486. * @depend namespace.js
  487. */
  488. namespace(this, &quot;sozi.proto&quot;, function (exports) {
  489. &quot;use strict&quot;;
  490. exports.Object = {
  491. installConstructors: function () {
  492. function InstanceConstructor() {}
  493. InstanceConstructor.prototype = this;
  494. this.instance = function () {
  495. var result = new InstanceConstructor();
  496. result.construct.apply(result, arguments);
  497. return result;
  498. };
  499. this.subtype = function (anObject) {
  500. var result = new InstanceConstructor();
  501. result.augment(anObject);
  502. result.installConstructors();
  503. return result;
  504. };
  505. },
  506. construct: function () {},
  507. augment: function (anObject) {
  508. for (var attr in anObject) {
  509. if (anObject.hasOwnProperty(attr)) {
  510. this[attr] = anObject[attr];
  511. }
  512. }
  513. return this;
  514. },
  515. bind: function (aFunction) {
  516. var self = this;
  517. return function () {
  518. return aFunction.apply(self, arguments);
  519. }
  520. }
  521. };
  522. // Bootstrap the root object
  523. exports.Object.installConstructors();
  524. });
  525. /*
  526. * Sozi - A presentation tool using the SVG standard
  527. *
  528. * Copyright (C) 2010-2013 Guillaume Savaton
  529. *
  530. * This program is dual licensed under the terms of the MIT license
  531. * or the GNU General Public License (GPL) version 3.
  532. * A copy of both licenses is provided in the doc/ folder of the
  533. * official release of Sozi.
  534. *
  535. * See http://sozi.baierouge.fr/wiki/en:license for details.
  536. */
  537. /**
  538. * @name sozi.actions
  539. * @namespace Callback functions for DOM event handlers
  540. * @depend namespace.js
  541. */
  542. namespace(this, &quot;sozi.actions&quot;, function (exports, window) {
  543. /** @lends sozi.actions */
  544. &quot;use strict&quot;;
  545. // Module aliases
  546. var player = namespace(window, &quot;sozi.player&quot;);
  547. var display = namespace(window, &quot;sozi.display&quot;);
  548. // The global document object
  549. var document = window.document;
  550. // Constants: mouse button numbers
  551. var DRAG_BUTTON = 0; // Left button
  552. var TOC_BUTTON = 1; // Middle button
  553. // Constants: increments for zooming and rotating,
  554. // threshold for dragging
  555. var SCALE_FACTOR = 1.05;
  556. var ROTATE_STEP = 5;
  557. var DRAG_THRESHOLD_PX = 5;
  558. /**
  559. * The status of the current drag operation.
  560. *
  561. * @type Boolean
  562. */
  563. var mouseDragged = false;
  564. /**
  565. * The X coordinate of the mouse on the latest &quot;down&quot; or &quot;drag&quot; event.
  566. *
  567. * @type Number
  568. */
  569. var mouseLastX = 0;
  570. /**
  571. * The Y coordinate of the mouse on the latest &quot;down&quot; or &quot;drag&quot; event.
  572. *
  573. * @type Number
  574. */
  575. var mouseLastY = 0;
  576. /**
  577. * Zooms the display in the given direction.
  578. *
  579. * &lt;p&gt;Only the sign of &lt;code&gt;direction&lt;/code&gt; is used:&lt;/p&gt;
  580. * &lt;ul&gt;
  581. * &lt;li&gt;zoom in when &lt;code&gt;direction &gt; 0&lt;/code&gt;&lt;/li&gt;
  582. * &lt;li&gt;zoom out when &lt;code&gt;direction &lt;= 0&lt;/code&gt;&lt;/li&gt;
  583. * &lt;/ul&gt;
  584. *
  585. * &lt;p&gt;The scaling is centered around point (&lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;).&lt;/p&gt;
  586. *
  587. * @param {Number} direction The direction of the scaling operation
  588. * @param {Number} x The X coordinate of the scaling center
  589. * @param {Number} y The Y coordinate of the scaling center
  590. */
  591. function zoom(direction, x, y) {
  592. player.stop();
  593. display.viewPorts[&quot;player&quot;].zoom(direction &gt; 0 ? SCALE_FACTOR : 1 / SCALE_FACTOR, x, y);
  594. }
  595. /**
  596. * Rotate the display in the given direction.
  597. *
  598. * &lt;p&gt;Only the sign of &lt;code&gt;direction&lt;/code&gt; is used:&lt;/p&gt;
  599. * &lt;ul&gt;
  600. * &lt;li&gt;rotate anticlockwise when direction &gt; 0&lt;/li&gt;
  601. * &lt;li&gt;rotate clockwise when direction &lt;= 0&lt;/li&gt;
  602. * &lt;/ul&gt;
  603. *
  604. * @param {Number} direction The direction of the rotation
  605. */
  606. function rotate(direction) {
  607. player.stop();
  608. display.viewPorts[&quot;player&quot;].rotate(direction &gt; 0 ? ROTATE_STEP : -ROTATE_STEP);
  609. }
  610. /**
  611. * Show/hide the frame list.
  612. *
  613. * &lt;p&gt;The presentation stops when the frame list is showed,
  614. * and restarts when the frame list is hidden.&lt;/p&gt;
  615. */
  616. function toggleFrameList() {
  617. if (sozi.framelist.isVisible()) {
  618. sozi.framelist.hide();
  619. player.restart();
  620. } else {
  621. player.stop();
  622. sozi.framelist.show();
  623. }
  624. }
  625. function isPlayerEvent(evt) {
  626. return display.viewPorts[&quot;player&quot;].contains(evt.clientX, evt.clientY);
  627. }
  628. /**
  629. * Event handler: mouse down.
  630. *
  631. * &lt;p&gt;When the left button is pressed, we register the current coordinates
  632. * in case the mouse will be dragged. Handler {@link sozi.actions-onMouseDrag} is set until
  633. * the button is released ({@link sozi.actions-onMouseUp}).&lt;/p&gt;
  634. *
  635. * &lt;p&gt;When the middle button is pressed, the table of contents is shown or hidden.&lt;/p&gt;
  636. *
  637. * @param {Event} evt The DOM event object
  638. */
  639. function onMouseDown(evt) {
  640. if (!isPlayerEvent(evt)) {
  641. return;
  642. }
  643. if (evt.button === DRAG_BUTTON) {
  644. document.documentElement.addEventListener(&quot;mousemove&quot;, onMouseDrag, false);
  645. mouseDragged = false;
  646. mouseLastX = evt.clientX;
  647. mouseLastY = evt.clientY;
  648. } else if (evt.button === TOC_BUTTON) {
  649. toggleFrameList();
  650. }
  651. evt.stopPropagation();
  652. evt.preventDefault();
  653. }
  654. /**
  655. * Event handler: mouse move.
  656. *
  657. * &lt;p&gt;If the left mouse button is down, then the mouse move is a drag action.
  658. * This method computes the displacement since the button was pressed or
  659. * since the last move, and updates the reference coordinates for the next move.&lt;/p&gt;
  660. *
  661. * @param {Event} evt The DOM event object
  662. */
  663. function onMouseDrag(evt) {
  664. if (!isPlayerEvent(evt)) {
  665. return;
  666. }
  667. player.stop();
  668. // The drag action is confirmed when one of the mouse coordinates
  669. // has moved past the threshold
  670. if (!mouseDragged &amp;&amp; (Math.abs(evt.clientX - mouseLastX) &gt; DRAG_THRESHOLD_PX ||
  671. Math.abs(evt.clientY - mouseLastY) &gt; DRAG_THRESHOLD_PX)) {
  672. mouseDragged = true;
  673. }
  674. if (mouseDragged) {
  675. sozi.events.fire(&quot;sozi.player.cleanup&quot;);
  676. display.viewPorts[&quot;player&quot;].drag(evt.clientX - mouseLastX, evt.clientY - mouseLastY);
  677. mouseLastX = evt.clientX;
  678. mouseLastY = evt.clientY;
  679. }
  680. evt.stopPropagation();
  681. }
  682. /**
  683. * Event handler: mouse up.
  684. *
  685. * &lt;p&gt;Releasing the left button removes the {@link sozi.actions-onMouseDrag} handler.&lt;/p&gt;
  686. *
  687. * @param {Event} evt The DOM event object
  688. */
  689. function onMouseUp(evt) {
  690. if (!isPlayerEvent(evt)) {
  691. return;
  692. }
  693. if (evt.button === DRAG_BUTTON) {
  694. document.documentElement.removeEventListener(&quot;mousemove&quot;, onMouseDrag, false);
  695. }
  696. evt.stopPropagation();
  697. evt.preventDefault();
  698. }
  699. /**
  700. * Event handler: context menu (i.e right click).
  701. *
  702. * &lt;p&gt;Right click goes one frame back.&lt;/p&gt;
  703. *
  704. * &lt;p&gt;There is no &quot;click&quot; event for the right mouse button and the menu
  705. * can't be disabled in {@link sozi.actions-onMouseDown}.&lt;/p&gt;
  706. *
  707. * @param {Event} evt The DOM event object
  708. */
  709. function onContextMenu(evt) {
  710. if (!isPlayerEvent(evt)) {
  711. return;
  712. }
  713. player.moveToPrevious();
  714. evt.stopPropagation();
  715. evt.preventDefault();
  716. }
  717. /**
  718. * Event handler: mouse click.
  719. *
  720. * &lt;p&gt;Left-click moves the presentation to the next frame.&lt;/p&gt;
  721. *
  722. * &lt;p&gt;No &quot;click&quot; event is generated for the middle button in Firefox.
  723. * See {@link sozi.actions-onMouseDown} for middle click handling.&lt;/p&gt;
  724. *
  725. * &lt;p&gt;Dragging the mouse produces a &quot;click&quot; event when the button is released.
  726. * If flag {@link sozi.actions-mouseDragged} was set by {@link sozi.actions-onMouseDrag},
  727. * then the click event is the result of a drag action.&lt;/p&gt;
  728. *
  729. * @param {Event} evt The DOM event object
  730. */
  731. function onClick(evt) {
  732. if (!isPlayerEvent(evt)) {
  733. return;
  734. }
  735. if (!mouseDragged &amp;&amp; evt.button !== TOC_BUTTON) {
  736. player.moveToNext();
  737. }
  738. evt.stopPropagation();
  739. evt.preventDefault();
  740. }
  741. /**
  742. * Event handler: mouse wheel.
  743. *
  744. * &lt;p&gt;Rolling the mouse wheel stops the presentation and zooms the current display.&lt;/p&gt;
  745. *
  746. * FIXME shift key does not work in Opera
  747. *
  748. * @param {Event} evt The DOM event object
  749. */
  750. function onWheel(evt) {
  751. if (!isPlayerEvent(evt)) {
  752. return;
  753. }
  754. if (!evt) {
  755. evt = window.event;
  756. }
  757. var delta = 0;
  758. if (evt.wheelDelta) { // IE and Opera
  759. delta = evt.wheelDelta;
  760. }
  761. else if (evt.detail) { // Mozilla
  762. delta = -evt.detail;
  763. }
  764. if (delta !== 0) {
  765. if (evt.shiftKey) {
  766. rotate(delta);
  767. }
  768. else {
  769. zoom(delta, evt.clientX, evt.clientY);
  770. }
  771. }
  772. evt.stopPropagation();
  773. evt.preventDefault();
  774. }
  775. /**
  776. * Event handler: key press.
  777. *
  778. * &lt;p&gt;Keyboard handling is split into two methods:
  779. * {@link sozi.actions-onKeyPress} and {@link sozi.actions-onKeyDown}
  780. * in order to get the same behavior across browsers.&lt;/p&gt;
  781. *
  782. * &lt;p&gt;This method handles character keys &quot;+&quot;, &quot;-&quot;, &quot;=&quot;, &quot;F&quot; and &quot;T&quot;.&lt;/p&gt;
  783. *
  784. * @param {Event} evt The DOM event object
  785. */
  786. function onKeyPress(evt) {
  787. // Keys with modifiers are ignored
  788. if (evt.altKey || evt.ctrlKey || evt.metaKey) {
  789. return;
  790. }
  791. switch (evt.charCode || evt.which) {
  792. case 43: // +
  793. zoom(1, window.innerWidth / 2, window.innerHeight / 2);
  794. break;
  795. case 45: // -
  796. zoom(-1, window.innerWidth / 2, window.innerHeight / 2);
  797. break;
  798. case 61: // =
  799. player.moveToCurrent();
  800. break;
  801. case 70: // F
  802. case 102: // f
  803. player.showAll();
  804. break;
  805. case 84: // T
  806. case 116: // t
  807. toggleFrameList();
  808. break;
  809. case 82: // R
  810. rotate(-1);
  811. break;
  812. case 114: // r
  813. rotate(1);
  814. break;
  815. default:
  816. return;
  817. }
  818. evt.stopPropagation();
  819. evt.preventDefault();
  820. }
  821. /**
  822. * Event handler: key down.
  823. *
  824. * &lt;p&gt;Keyboard handling is split into two methods:
  825. * {@link sozi.actions-onKeyPress} and {@link sozi.actions-onKeyDown}
  826. * in order to get the same behavior across browsers.&lt;/p&gt;
  827. *
  828. * &lt;p&gt;This method handles navigation keys (arrows, page up/down, home, end)
  829. * and the space and enter keys.&lt;/p&gt;
  830. *
  831. * @param {Event} evt The DOM event object
  832. */
  833. function onKeyDown(evt) {
  834. // Keys with Alt/Ctrl/Meta modifiers are ignored
  835. if (evt.altKey || evt.ctrlKey || evt.metaKey) {
  836. return;
  837. }
  838. switch (evt.keyCode) {
  839. case 36: // Home
  840. if (evt.shiftKey) {
  841. player.jumpToFirst();
  842. }
  843. else {
  844. player.moveToFirst();
  845. }
  846. break;
  847. case 35: // End
  848. if (evt.shiftKey) {
  849. player.jumpToLast();
  850. }
  851. else {
  852. player.moveToLast();
  853. }
  854. break;
  855. case 38: // Arrow up
  856. case 33: // Page up
  857. case 37: // Arrow left
  858. if (evt.shiftKey) {
  859. player.jumpToPrevious();
  860. }
  861. else {
  862. player.moveToPrevious();
  863. }
  864. break;
  865. case 40: // Arrow down
  866. case 34: // Page down
  867. case 39: // Arrow right
  868. case 13: // Enter
  869. case 32: // Space
  870. if (evt.shiftKey) {
  871. player.jumpToNext();
  872. }
  873. else {
  874. player.moveToNext();
  875. }
  876. break;
  877. default:
  878. // Ignore other keys and propagate the event
  879. return;
  880. }
  881. // Stop event propagation for supported keys
  882. evt.stopPropagation();
  883. // In some versions of Chrome/Chromium, preventDefault() inhibits the &quot;keypress&quot; event
  884. evt.preventDefault();
  885. }
  886. /**
  887. * Dummy event handler: stop event propagation.
  888. *
  889. * @param {Event} evt The DOM event object
  890. */
  891. function stopEvent(evt) {
  892. evt.stopPropagation();
  893. }
  894. /**
  895. * Event handler: document load.
  896. *
  897. * &lt;p&gt;This function sets up all other event handlers for the player.&lt;/p&gt;
  898. */
  899. function onDisplayReady() {
  900. // Prevent event propagation when clicking on a link
  901. // FIXME does not work in Firefox when the &lt;a&gt; is referenced through a &lt;use&gt;
  902. var links = document.getElementsByTagName(&quot;a&quot;);
  903. for (var i = 0; i &lt; links.length; i += 1) {
  904. links[i].addEventListener(&quot;click&quot;, stopEvent, false);
  905. links[i].addEventListener(&quot;contextmenu&quot;, stopEvent, false);
  906. }
  907. // Mouse events are constrained to the player viewport
  908. // see isPlayerEvent()
  909. // TODO also use shift-click as an alternative for middle-click
  910. var svgRoot = document.documentElement;
  911. svgRoot.addEventListener(&quot;click&quot;, onClick, false);
  912. svgRoot.addEventListener(&quot;mousedown&quot;, onMouseDown, false);
  913. svgRoot.addEventListener(&quot;mouseup&quot;, onMouseUp, false);
  914. svgRoot.addEventListener(&quot;contextmenu&quot;, onContextMenu, false);
  915. svgRoot.addEventListener(&quot;DOMMouseScroll&quot;, onWheel, false); // Mozilla
  916. window.onmousewheel = onWheel;
  917. // Keyboard events are global to the SVG document
  918. svgRoot.addEventListener(&quot;keypress&quot;, onKeyPress, false);
  919. svgRoot.addEventListener(&quot;keydown&quot;, onKeyDown, false);
  920. }
  921. sozi.events.listen(&quot;sozi.display.ready&quot;, onDisplayReady); // @depend events.js
  922. });
  923. /*
  924. * Sozi - A presentation tool using the SVG standard
  925. *
  926. * Copyright (C) 2010-2013 Guillaume Savaton
  927. *
  928. * This program is dual licensed under the terms of the MIT license
  929. * or the GNU General Public License (GPL) version 3.
  930. * A copy of both licenses is provided in the doc/ folder of the
  931. * official release of Sozi.
  932. *
  933. * See http://sozi.baierouge.fr/wiki/en:license for details.
  934. */
  935. /**
  936. * @name sozi.animation
  937. * @namespace A general-purpose animation controller.
  938. * @depend namespace.js
  939. */
  940. namespace(this, &quot;sozi.animation&quot;, function (exports, window) {
  941. /** @lends sozi.animation */
  942. &quot;use strict&quot;;
  943. /**
  944. * The browser-specific function to request an animation frame.
  945. *
  946. * @function
  947. */
  948. var requestAnimationFrame =
  949. window.mozRequestAnimationFrame ||
  950. window.webkitRequestAnimationFrame ||
  951. window.msRequestAnimationFrame ||
  952. window.oRequestAnimationFrame;
  953. var getCurrentTime = function () {
  954. return window.performance &amp;&amp; window.performance.now ?
  955. window.performance.now() :
  956. Date.now();
  957. };
  958. exports.setAnimationFrameHandlers = function (requestAnimationFrameFunction, getCurrentTimeFunction) {
  959. requestAnimationFrame = requestAnimationFrameFunction;
  960. getCurrentTime = getCurrentTimeFunction;
  961. };
  962. /**
  963. * The default time step.
  964. *
  965. * &lt;p&gt;For browsers that do not support animation frames.&lt;/p&gt;
  966. *
  967. * @constant
  968. * @type Number
  969. */
  970. var TIME_STEP_MS = 40;
  971. /**
  972. * The handle provided by &lt;code&gt;setInterval()&lt;/code&gt;.
  973. *
  974. * &lt;p&gt;For browsers that do not support animation frames.&lt;/p&gt;
  975. */
  976. var timer;
  977. /**
  978. * The list of running animators.
  979. *
  980. * @type Array
  981. */
  982. var animatorList = [];
  983. /**
  984. * The main animation loop.
  985. *
  986. * &lt;p&gt;This function is called periodically and triggers the
  987. * animation steps in all running animators.&lt;/p&gt;
  988. *
  989. * &lt;p&gt;If all animators are removed from the list of running animators,
  990. * then the periodic calling is disabled.&lt;/p&gt;
  991. *
  992. * &lt;p&gt;This function can be called either through {@link sozi.animation-requestAnimationFrame}
  993. * if the browser supports it, or through &lt;code&gt;setInterval()&lt;/code&gt;.&lt;/p&gt;
  994. */
  995. function loop() {
  996. if (animatorList.length &gt; 0) {
  997. // If there is at least one animator,
  998. // and if the browser provides animation frames,
  999. // schedule this function to be called again in the next frame.
  1000. if (requestAnimationFrame) {
  1001. requestAnimationFrame(loop);
  1002. }
  1003. // Step all animators
  1004. animatorList.forEach(function (animator) {
  1005. // TODO use timestamp argument:
  1006. // browser compatibility issue with Date.now()
  1007. // and performance.now() timestamps.
  1008. animator.step(getCurrentTime());
  1009. });
  1010. }
  1011. else {
  1012. // If all animators have been removed,
  1013. // and if this function is called periodically
  1014. // through setInterval, disable the periodic calling.
  1015. if (!requestAnimationFrame) {
  1016. window.clearInterval(timer);
  1017. }
  1018. }
  1019. }
  1020. /**
  1021. * Start the animation loop.
  1022. *
  1023. * &lt;p&gt;This function delegates the periodic update of all animators
  1024. * to the {@link sozi.animation-loop} function, either through {@link sozi.animation-requestAnimationFrame}
  1025. * if the browser supports it, or through &lt;code&gt;setInterval()&lt;/code&gt;.&lt;/p&gt;
  1026. */
  1027. function start() {
  1028. if (requestAnimationFrame) {
  1029. requestAnimationFrame(loop);
  1030. }
  1031. else {
  1032. timer = window.setInterval(function () {
  1033. loop(getCurrentTime());
  1034. }, TIME_STEP_MS);
  1035. }
  1036. }
  1037. /**
  1038. * Add a new animator object to the list of running animators.
  1039. *
  1040. * &lt;p&gt;If the animator list was empty before calling this function,
  1041. * then the animation loop is started.&lt;/p&gt;
  1042. *
  1043. * @param {sozi.animation.Animator} animator The animator object to add.
  1044. */
  1045. function addAnimator(animator) {
  1046. animatorList.push(animator);
  1047. if (animatorList.length === 1) {
  1048. start();
  1049. }
  1050. }
  1051. /**
  1052. * Remove the given animator from the list of running animators.
  1053. *
  1054. * @param {sozi.animation.Animator} animator The animator object to add.
  1055. */
  1056. function removeAnimator(animator) {
  1057. animatorList.splice(animatorList.indexOf(animator), 1);
  1058. }
  1059. /**
  1060. * @class
  1061. *
  1062. * An animator provides the logic for animating other objects.
  1063. *
  1064. * &lt;p&gt;The main purpose of an animator is to schedule the update
  1065. * operations in the animated objects.&lt;/p&gt;
  1066. *
  1067. * @memberOf sozi.animation
  1068. * @name Animator
  1069. * @depend proto.js
  1070. */
  1071. exports.Animator = sozi.proto.Object.subtype({
  1072. /** @lends sozi.animation.Animator */
  1073. /**
  1074. * Construct a new animator.
  1075. */
  1076. construct: function () {
  1077. /**
  1078. * The animation duration, in milliseconds.
  1079. * @type Number
  1080. */
  1081. this.durationMs = 0;
  1082. /**
  1083. * A &quot;payload&quot; object that can be used by {@link sozi.animation.Animator.onStep}
  1084. * and {@link sozi.animation.Animator.onDone}.
  1085. */
  1086. this.data = null;
  1087. /**
  1088. * The start time of the animation.
  1089. * @type Number
  1090. */
  1091. this.initialTime = 0;
  1092. /**
  1093. * The current state of this animator.
  1094. * @type Boolean
  1095. */
  1096. this.started = false;
  1097. },
  1098. /**
  1099. * Start the current animator.
  1100. *
  1101. * &lt;p&gt;The current animator is added to the list of running animators
  1102. * and is put in the &quot;started&quot; state.
  1103. * It will be removed from the list automatically when the given duration
  1104. * has elapsed.&lt;/p&gt;
  1105. *
  1106. * &lt;p&gt;Method {@link sozi.animation.Animator.onStep} is called once before starting the animation.&lt;/p&gt;
  1107. *
  1108. * @param {Number} durationMs The animation duration, in milliseconds
  1109. * @param data Some data that can be used in {@link sozi.animation.Animator.onStep}
  1110. * and {@link sozi.animation.Animator.onDone}
  1111. */
  1112. start: function (durationMs, data) {
  1113. this.durationMs = durationMs;
  1114. this.data = data;
  1115. this.initialTime = getCurrentTime();
  1116. this.onStep(0);
  1117. if (!this.started) {
  1118. this.started = true;
  1119. addAnimator(this);
  1120. }
  1121. },
  1122. /**
  1123. * Stop the current animator.
  1124. *
  1125. * &lt;p&gt;The current animator is removed from the list of running animators
  1126. * and is put in the &quot;stopped&quot; state.&lt;/p&gt;
  1127. */
  1128. stop: function () {
  1129. if (this.started) {
  1130. removeAnimator(this);
  1131. this.started = false;
  1132. }
  1133. },
  1134. /**
  1135. * Perform one animation step.
  1136. *
  1137. * &lt;p&gt;This function is called automatically by the {@link sozi.animation-loop} function.
  1138. * It calls {@link sozi.animation.Animator.onStep}.
  1139. * If the animation duration has elapsed, {@link sozi.animation.Animator.onDone} is called.&lt;/p&gt;
  1140. *
  1141. * @param {Number} currentTime The current time
  1142. */
  1143. step: function (currentTime) {
  1144. var elapsedTime = currentTime - this.initialTime;
  1145. if (elapsedTime &gt;= this.durationMs) {
  1146. this.stop();
  1147. this.onStep(1);
  1148. this.onDone();
  1149. } else {
  1150. this.onStep(elapsedTime / this.durationMs);
  1151. }
  1152. },
  1153. /**
  1154. * This method is called automatically on each animation step.
  1155. *
  1156. * &lt;p&gt;The default implementation does nothing. Override it in a
  1157. * subclass or instance to provide your own implementation.&lt;p&gt;
  1158. *
  1159. * @param {Number} progress The elapsed fraction of the total duration (comprised between 0 and 1 included).
  1160. */
  1161. onStep: function (progress) {
  1162. // Do nothing
  1163. },
  1164. /**
  1165. * This method is called automatically when the animation ends.
  1166. *
  1167. * &lt;p&gt;The default implementation does nothing. Override it in a
  1168. * subclass or instance to provide your own implementation.&lt;p&gt;
  1169. */
  1170. onDone: function () {
  1171. // Do nothing
  1172. }
  1173. });
  1174. /*
  1175. * The acceleration profiles.
  1176. *
  1177. * Each profile is a function that operates in the interval [0, 1]
  1178. * and produces a result in the same interval.
  1179. *
  1180. * These functions are meant to be called in {@link sozi.animation.Animator.onStep}
  1181. * to transform the progress indicator according to the desired
  1182. * acceleration effect.
  1183. */
  1184. exports.profiles = {
  1185. &quot;linear&quot;: function (x) {
  1186. return x;
  1187. },
  1188. &quot;accelerate&quot;: function (x) {
  1189. return Math.pow(x, 3);
  1190. },
  1191. &quot;strong-accelerate&quot;: function (x) {
  1192. return Math.pow(x, 5);
  1193. },
  1194. &quot;decelerate&quot;: function (x) {
  1195. return 1 - Math.pow(1 - x, 3);
  1196. },
  1197. &quot;strong-decelerate&quot;: function (x) {
  1198. return 1 - Math.pow(1 - x, 5);
  1199. },
  1200. &quot;accelerate-decelerate&quot;: function (x) {
  1201. var xs = x &lt;= 0.5 ? x : 1 - x,
  1202. y = Math.pow(2 * xs, 3) / 2;
  1203. return x &lt;= 0.5 ? y : 1 - y;
  1204. },
  1205. &quot;strong-accelerate-decelerate&quot;: function (x) {
  1206. var xs = x &lt;= 0.5 ? x : 1 - x,
  1207. y = Math.pow(2 * xs, 5) / 2;
  1208. return x &lt;= 0.5 ? y : 1 - y;
  1209. },
  1210. &quot;decelerate-accelerate&quot;: function (x) {
  1211. var xs = x &lt;= 0.5 ? x : 1 - x,
  1212. y = (1 - Math.pow(1 - 2 * xs, 2)) / 2;
  1213. return x &lt;= 0.5 ? y : 1 - y;
  1214. },
  1215. &quot;strong-decelerate-accelerate&quot;: function (x) {
  1216. var xs = x &lt;= 0.5 ? x : 1 - x,
  1217. y = (1 - Math.pow(1 - 2 * xs, 3)) / 2;
  1218. return x &lt;= 0.5 ? y : 1 - y;
  1219. },
  1220. &quot;immediate-beginning&quot;: function (x) {
  1221. return 1;
  1222. },
  1223. &quot;immediate-end&quot;: function (x) {
  1224. return x === 1 ? 1 : 0;
  1225. },
  1226. &quot;immediate-middle&quot;: function (x) {
  1227. return x &gt;= 0.5 ? 1 : 0;
  1228. }
  1229. };
  1230. });
  1231. /*
  1232. * Sozi - A presentation tool using the SVG standard
  1233. *
  1234. * Copyright (C) 2010-2013 Guillaume Savaton
  1235. *
  1236. * This program is dual licensed under the terms of the MIT license
  1237. * or the GNU General Public License (GPL) version 3.
  1238. * A copy of both licenses is provided in the doc/ folder of the
  1239. * official release of Sozi.
  1240. *
  1241. * See http://sozi.baierouge.fr/wiki/en:license for details.
  1242. */
  1243. /**
  1244. * @name sozi.display
  1245. * @namespace Display management.
  1246. * @depend namespace.js
  1247. */
  1248. namespace(this, &quot;sozi.display&quot;, function (exports, window) {
  1249. &quot;use strict&quot;;
  1250. // Constant: the Sozi namespace
  1251. var SVG_NS = &quot;http://www.w3.org/2000/svg&quot;;
  1252. var XLINK_NS = &quot;http://www.w3.org/1999/xlink&quot;;
  1253. // The global document object
  1254. var document = window.document;
  1255. // The initial bounding box of the whole document,
  1256. // assigned in onDocumentReady()
  1257. var initialBBox;
  1258. var lastWindowWidth;
  1259. var lastWindowHeight;
  1260. exports.viewPorts = {};
  1261. var primaryViewport;
  1262. /**
  1263. * @depend proto.js
  1264. */
  1265. exports.CameraState = sozi.proto.Object.subtype({
  1266. construct : function () {
  1267. // Center coordinates
  1268. this.cx = this.cy = 0;
  1269. // Dimensions
  1270. this.width = this.height = 1;
  1271. // Rotation angle, in degrees
  1272. this.angle = 0;
  1273. // Clipping
  1274. this.clipped = true;
  1275. // Transition zoom
  1276. this.transitionZoomPercent = 0;
  1277. // Transition profile
  1278. this.transitionProfile = sozi.animation.profiles.linear;
  1279. // Transition path
  1280. this.transitionPath = null;
  1281. },
  1282. setCenter: function (cx, cy) {
  1283. this.cx = cx;
  1284. this.cy = cy;
  1285. return this;
  1286. },
  1287. setSize: function (width, height) {
  1288. this.width = width;
  1289. this.height = height;
  1290. return this;
  1291. },
  1292. setClipped: function (clipped) {
  1293. this.clipped = clipped;
  1294. return this;
  1295. },
  1296. /*
  1297. * Set the angle of the current camera state.
  1298. * The angle of the current state is normalized
  1299. * in the interval [-180 ; 180]
  1300. */
  1301. setAngle: function (angle) {
  1302. this.angle = (angle + 180) % 360 - 180;
  1303. return this;
  1304. },
  1305. setRawAngle: function (angle) {
  1306. this.angle = angle;
  1307. return this;
  1308. },
  1309. setTransitionZoomPercent: function (zoomPercent) {
  1310. this.transitionZoomPercent = zoomPercent;
  1311. return this;
  1312. },
  1313. setTransitionProfile: function (profile) {
  1314. this.transitionProfile = profile;
  1315. return this;
  1316. },
  1317. setTransitionPath: function (svgPath) {
  1318. this.transitionPath = svgPath;
  1319. return this;
  1320. },
  1321. /*
  1322. * Set the current camera's properties to the given SVG element.
  1323. *
  1324. * If the element is a rectangle, the properties of the frames are based
  1325. * on the geometrical properties of the rectangle.
  1326. * Otherwise, the properties of the frame are based on the bounding box
  1327. * of the given element.
  1328. *
  1329. * Parameters:
  1330. * - svgElement: an element from the SVG DOM
  1331. */
  1332. setAtElement: function (svgElement) {
  1333. // Read the raw bounding box of the given SVG element
  1334. var x, y, w, h;
  1335. if (svgElement.nodeName === &quot;rect&quot;) {
  1336. x = svgElement.x.baseVal.value;
  1337. y = svgElement.y.baseVal.value;
  1338. w = svgElement.width.baseVal.value;
  1339. h = svgElement.height.baseVal.value;
  1340. } else {
  1341. var b = svgElement.getBBox();
  1342. x = b.x;
  1343. y = b.y;
  1344. w = b.width;
  1345. h = b.height;
  1346. }
  1347. // Compute the raw coordinates of the center
  1348. // of the given SVG element
  1349. var c = document.documentElement.createSVGPoint();
  1350. c.x = x + w / 2;
  1351. c.y = y + h / 2;
  1352. // Compute the coordinates of the center of the given SVG element
  1353. // after its current transformation
  1354. var matrix = svgElement.getCTM();
  1355. c = c.matrixTransform(matrix);
  1356. // Compute the scaling factor applied to the given SVG element
  1357. var scale = Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b);
  1358. // Update the camera to match the bounding box information of the
  1359. // given SVG element after its current transformation
  1360. return this.setCenter(c.x, c.y)
  1361. .setSize(w * scale, h * scale)
  1362. .setAngle(Math.atan2(matrix.b, matrix.a) * 180 / Math.PI);
  1363. },
  1364. setAtState: function (other) {
  1365. return this.setCenter(other.cx, other.cy)
  1366. .setSize(other.width, other.height)
  1367. .setAngle(other.angle)
  1368. .setClipped(other.clipped)
  1369. .setTransitionZoomPercent(other.transitionZoomPercent)
  1370. .setTransitionProfile(other.transitionProfile)
  1371. .setTransitionPath(other.transitionPath);
  1372. },
  1373. interpolatableAttributes: [&quot;width&quot;, &quot;height&quot;, &quot;angle&quot;],
  1374. interpolate: function (initialState, finalState, ratio, useTransitionPath, reverseTransitionPath) {
  1375. var remaining = 1 - ratio;
  1376. for (var i = 0; i &lt; this.interpolatableAttributes.length; i += 1) {
  1377. var attr = this.interpolatableAttributes[i];
  1378. this[attr] = finalState[attr] * ratio + initialState[attr] * remaining;
  1379. }
  1380. var svgPath = reverseTransitionPath ? initialState.transitionPath : finalState.transitionPath;
  1381. if (useTransitionPath &amp;&amp; svgPath) {
  1382. var pathLength = svgPath.getTotalLength();
  1383. if (reverseTransitionPath) {
  1384. var startPoint = svgPath.getPointAtLength(pathLength);
  1385. var endPoint = svgPath.getPointAtLength(0);
  1386. var currentPoint = svgPath.getPointAtLength(pathLength * remaining);
  1387. }
  1388. else {
  1389. var startPoint = svgPath.getPointAtLength(0);
  1390. var endPoint = svgPath.getPointAtLength(pathLength);
  1391. var currentPoint = svgPath.getPointAtLength(pathLength * ratio);
  1392. }
  1393. this.cx = currentPoint.x + (finalState.cx - endPoint.x) * ratio + (initialState.cx - startPoint.x) * remaining;
  1394. this.cy = currentPoint.y + (finalState.cy - endPoint.y) * ratio + (initialState.cy - startPoint.y) * remaining;
  1395. }
  1396. else {
  1397. this.cx = finalState.cx * ratio + initialState.cx * remaining;
  1398. this.cy = finalState.cy * ratio + initialState.cy * remaining;
  1399. }
  1400. }
  1401. });
  1402. exports.Camera = exports.CameraState.subtype({
  1403. construct: function (viewPort, idLayer) {
  1404. exports.CameraState.construct.call(this);
  1405. this.viewPort = viewPort;
  1406. // Clipping rectangle
  1407. this.svgClipRect = document.createElementNS(SVG_NS, &quot;rect&quot;);
  1408. // Clipping path
  1409. var svgClipPath = document.createElementNS(SVG_NS, &quot;clipPath&quot;);
  1410. svgClipPath.setAttribute(&quot;id&quot;, &quot;sozi-clip-path-&quot; + viewPort.id + &quot;-&quot; + idLayer);
  1411. svgClipPath.appendChild(this.svgClipRect);
  1412. viewPort.svgGroup.appendChild(svgClipPath);
  1413. // The group that will support the clipping operation
  1414. var svgClippedGroup = document.createElementNS(SVG_NS, &quot;g&quot;);
  1415. svgClippedGroup.setAttribute(&quot;clip-path&quot;, &quot;url(#sozi-clip-path-&quot; + viewPort.id + &quot;-&quot; + idLayer + &quot;)&quot;);
  1416. viewPort.svgGroup.appendChild(svgClippedGroup);
  1417. if (viewPort.isPrimary) {
  1418. // This group will support transformations
  1419. // we keep the layer group clean since it can be referenced
  1420. // from &lt;use&gt; elements
  1421. this.svgLayer = document.createElementNS(SVG_NS, &quot;g&quot;);
  1422. this.svgLayer.appendChild(document.getElementById(idLayer));
  1423. }
  1424. else {
  1425. // A &lt;use&gt; element referencing the target layer
  1426. this.svgLayer = document.createElementNS(SVG_NS, &quot;use&quot;);
  1427. this.svgLayer.setAttributeNS(XLINK_NS, &quot;href&quot;, &quot;#&quot; + idLayer);
  1428. }
  1429. svgClippedGroup.appendChild(this.svgLayer);
  1430. },
  1431. setAtState: function (other) {
  1432. return exports.CameraState.setAtState.call(this, other).update();
  1433. },
  1434. getScale: function () {
  1435. return Math.min(this.viewPort.width / this.width, this.viewPort.height / this.height);
  1436. },
  1437. rotate: function (angle) {
  1438. return this.setAngle(this.angle + angle).update();
  1439. },
  1440. zoom: function (factor, x, y) {
  1441. return this.setSize(this.width / factor, this.height / factor)
  1442. .drag(
  1443. (1 - factor) * (x - this.viewPort.width / 2),
  1444. (1 - factor) * (y - this.viewPort.height / 2)
  1445. );
  1446. },
  1447. drag: function (deltaX, deltaY) {
  1448. var scale = this.getScale();
  1449. var angleRad = this.angle * Math.PI / 180;
  1450. var si = Math.sin(angleRad);
  1451. var co = Math.cos(angleRad);
  1452. return this.setCenter(
  1453. this.cx - (deltaX * co - deltaY * si) / scale,
  1454. this.cy - (deltaX * si + deltaY * co) / scale
  1455. ).setClipped(false).update();
  1456. },
  1457. update: function () {
  1458. var scale = this.getScale();
  1459. // Compute the size and location of the frame on the screen
  1460. var width = this.width * scale;
  1461. var height = this.height * scale;
  1462. var x = (this.viewPort.width - width) / 2;
  1463. var y = (this.viewPort.height - height) / 2;
  1464. // Adjust the location and size of the clipping rectangle and the frame rectangle
  1465. this.svgClipRect.setAttribute(&quot;x&quot;, this.clipped ? x : 0);
  1466. this.svgClipRect.setAttribute(&quot;y&quot;, this.clipped ? y : 0);
  1467. this.svgClipRect.setAttribute(&quot;width&quot;, this.clipped ? width : this.viewPort.width);
  1468. this.svgClipRect.setAttribute(&quot;height&quot;, this.clipped ? height : this.viewPort.height);
  1469. // Compute and apply the geometrical transformation to the layer group
  1470. var translateX = -this.cx + this.width / 2 + x / scale;
  1471. var translateY = -this.cy + this.height / 2 + y / scale;
  1472. this.svgLayer.setAttribute(&quot;transform&quot;,
  1473. &quot;scale(&quot; + scale + &quot;)&quot; +
  1474. &quot;translate(&quot; + translateX + &quot;,&quot; + translateY + &quot;)&quot; +
  1475. &quot;rotate(&quot; + (-this.angle) + ',' + this.cx + &quot;,&quot; + this.cy + &quot;)&quot;
  1476. );
  1477. return this;
  1478. }
  1479. });
  1480. /**
  1481. * @depend proto.js
  1482. */
  1483. exports.ViewPort = sozi.proto.Object.subtype({
  1484. construct: function (id, idLayerList, primary) {
  1485. this.id = id;
  1486. exports.viewPorts[id] = this;
  1487. this.isPrimary = !!primary;
  1488. if (this.isPrimary) {
  1489. if (primaryViewport) {
  1490. throw &quot;Failed to create a primary viewport. A primary viewport already exists.&quot;;
  1491. }
  1492. else {
  1493. primaryViewport = this;
  1494. }
  1495. }
  1496. // TODO add a clip path for the viewport
  1497. this.svgGroup = document.createElementNS(SVG_NS, &quot;g&quot;);
  1498. this.svgGroup.setAttribute(&quot;class&quot;, &quot;sozi-viewport&quot;);
  1499. this.svgGroup.setAttribute(&quot;id&quot;, &quot;sozi-viewport-&quot; + id);
  1500. document.documentElement.appendChild(this.svgGroup);
  1501. this.setLocation(0, 0).setSize(window.innerWidth, window.innerHeight);
  1502. // Create a camera for each layer
  1503. this.cameras = {};
  1504. idLayerList.forEach(function (idLayer) {
  1505. this.cameras[idLayer] = exports.Camera.instance(this, idLayer);
  1506. }, this);
  1507. },
  1508. setSize: function (width, height) {
  1509. this.width = width;
  1510. this.height = height;
  1511. return this;
  1512. },
  1513. setLocation: function (x, y) {
  1514. this.x = x;
  1515. this.y = y;
  1516. return this;
  1517. },
  1518. contains: function (x, y) {
  1519. return x &gt;= this.x &amp;&amp; x &lt; this.x + this.width &amp;&amp;
  1520. y &gt;= this.y &amp;&amp; y &lt; this.y + this.height;
  1521. },
  1522. /*
  1523. * Returns the geometrical properties of the SVG document
  1524. *
  1525. * Returns:
  1526. * - The default size, translation and rotation for the document's bounding box
  1527. */
  1528. getDocumentState: function () {
  1529. // This object defines the bounding box of the whole document
  1530. var camera = exports.CameraState.instance()
  1531. .setCenter(initialBBox.x + initialBBox.width / 2,
  1532. initialBBox.y + initialBBox.height / 2)
  1533. .setSize(initialBBox.width, initialBBox.height)
  1534. .setClipped(false);
  1535. // Copy the document's bounding box to all layers
  1536. var result = {};
  1537. for (var idLayer in this.cameras) {
  1538. result[idLayer] = camera;
  1539. }
  1540. return result;
  1541. },
  1542. /*
  1543. * Apply geometrical transformations to the image according to the current
  1544. * geometrical attributes of this Display.
  1545. *
  1546. * This method is called automatically when the window is resized.
  1547. */
  1548. update: function () {
  1549. this.svgGroup.setAttribute(&quot;transform&quot;, &quot;translate(&quot; + this.x + &quot;,&quot; + this.y + &quot;)&quot;);
  1550. for (var idLayer in this.cameras) {
  1551. this.cameras[idLayer].update();
  1552. }
  1553. return this;
  1554. },
  1555. /*
  1556. * Transform the SVG document to show the given frame.
  1557. *
  1558. * Parameters:
  1559. * - frame: the frame to show
  1560. */
  1561. showFrame: function (frame) {
  1562. for (var idLayer in frame.states) {
  1563. this.cameras[idLayer].setAtState(frame.states[idLayer]);
  1564. }
  1565. return this;
  1566. },
  1567. /*
  1568. * Apply an additional translation to the SVG document based on onscreen coordinates.
  1569. *
  1570. * Parameters:
  1571. * - deltaX: the horizontal displacement, in pixels
  1572. * - deltaY: the vertical displacement, in pixels
  1573. */
  1574. drag: function (deltaX, deltaY) {
  1575. for (var idLayer in this.cameras) {
  1576. this.cameras[idLayer].drag(deltaX, deltaY);
  1577. }
  1578. return this;
  1579. },
  1580. /*
  1581. * Zooms the display with the given factor.
  1582. *
  1583. * The zoom is centered around (x, y) with respect to the center of the display area.
  1584. */
  1585. zoom: function (factor, x, y) {
  1586. for (var idLayer in this.cameras) {
  1587. this.cameras[idLayer].zoom(factor, x, y);
  1588. }
  1589. return this;
  1590. },
  1591. /*
  1592. * Rotate the display with the given angle.
  1593. *
  1594. * The rotation is centered around the center of the display area.
  1595. */
  1596. rotate: function (angle) {
  1597. for (var idLayer in this.cameras) {
  1598. this.cameras[idLayer].rotate(angle);
  1599. }
  1600. return this;
  1601. },
  1602. /**
  1603. * The default handler for window resize events.
  1604. *
  1605. * @param widthRatio The horizontal resize ratio
  1606. * @param heightRatio The vertical resize ratio
  1607. */
  1608. onWindowResize: function (widthRatio, heightRatio) {
  1609. this.setLocation(this.x * widthRatio, this.y * heightRatio)
  1610. .setSize(this.width * widthRatio, this.height * heightRatio)
  1611. .update();
  1612. }
  1613. });
  1614. /*
  1615. * Initializes the current Display.
  1616. *
  1617. * This method prepares the DOM representation of the current SVG document.
  1618. * All the image is embedded into a global &quot;g&quot; element on which transformations will be applied.
  1619. * A clipping rectangle is added.
  1620. *
  1621. * This method must be called when the document is ready to be manipulated.
  1622. */
  1623. function onDocumentReady() {
  1624. var svgRoot = document.documentElement; // TODO check SVG tag
  1625. // Save the initial bounding box of the document
  1626. // and force its dimensions to the browser window
  1627. initialBBox = svgRoot.getBBox();
  1628. lastWindowWidth = window.innerWidth;
  1629. lastWindowHeight = window.innerHeight;
  1630. svgRoot.setAttribute(&quot;width&quot;, lastWindowWidth);
  1631. svgRoot.setAttribute(&quot;height&quot;, lastWindowHeight);
  1632. sozi.events.fire(&quot;sozi.display.ready&quot;);
  1633. }
  1634. /*
  1635. * Resizes the SVG document to fit the browser window.
  1636. *
  1637. * This method calls onWindowResize on all registered viewports.
  1638. */
  1639. function resize() {
  1640. var svgRoot = document.documentElement;
  1641. svgRoot.setAttribute(&quot;width&quot;, window.innerWidth);
  1642. svgRoot.setAttribute(&quot;height&quot;, window.innerHeight);
  1643. for (var vp in exports.viewPorts) {
  1644. exports.viewPorts[vp].onWindowResize(window.innerWidth / lastWindowWidth, window.innerHeight / lastWindowHeight);
  1645. }
  1646. lastWindowWidth = window.innerWidth;
  1647. lastWindowHeight = window.innerHeight;
  1648. }
  1649. sozi.events.listen(&quot;sozi.document.ready&quot;, onDocumentReady); // @depend events.js
  1650. window.addEventListener(&quot;resize&quot;, resize, false);
  1651. });
  1652. /*
  1653. * Sozi - A presentation tool using the SVG standard
  1654. *
  1655. * Copyright (C) 2010-2013 Guillaume Savaton
  1656. *
  1657. * This program is dual licensed under the terms of the MIT license
  1658. * or the GNU General Public License (GPL) version 3.
  1659. * A copy of both licenses is provided in the doc/ folder of the
  1660. * official release of Sozi.
  1661. *
  1662. * See http://sozi.baierouge.fr/wiki/en:license for details.
  1663. */
  1664. /**
  1665. * @name sozi.document
  1666. * @namespace Document analysis.
  1667. * @depend namespace.js
  1668. */
  1669. namespace(this, &quot;sozi.document&quot;, function (exports, window) {
  1670. &quot;use strict&quot;;
  1671. // An alias to the global document object
  1672. var document = window.document;
  1673. // Constant: the Sozi namespace
  1674. var SOZI_NS = &quot;http://sozi.baierouge.fr&quot;;
  1675. // Constant: the default frame properties, if missing in the SVG document
  1676. var DEFAULTS = {
  1677. &quot;title&quot;: &quot;Untitled&quot;,
  1678. &quot;sequence&quot;: &quot;0&quot;,
  1679. &quot;hide&quot;: &quot;true&quot;,
  1680. &quot;clip&quot;: &quot;true&quot;,
  1681. &quot;show-in-frame-list&quot;: &quot;true&quot;,
  1682. &quot;timeout-enable&quot;: &quot;false&quot;,
  1683. &quot;timeout-ms&quot;: &quot;5000&quot;,
  1684. &quot;transition-duration-ms&quot;: &quot;1000&quot;,
  1685. &quot;transition-zoom-percent&quot;: &quot;0&quot;,
  1686. &quot;transition-profile&quot;: &quot;linear&quot;,
  1687. &quot;transition-path-hide&quot;: &quot;true&quot;
  1688. };
  1689. var DRAWABLE_TAGS = [ &quot;g&quot;, &quot;image&quot;, &quot;path&quot;, &quot;rect&quot;, &quot;circle&quot;,
  1690. &quot;ellipse&quot;, &quot;line&quot;, &quot;polyline&quot;, &quot;polygon&quot;, &quot;text&quot;, &quot;clippath&quot; ];
  1691. // The definitions of all valid frames in the current document
  1692. exports.frames = [];
  1693. // The list of layer ids managed by Sozi
  1694. exports.idLayerList = [];
  1695. /*
  1696. * Returns the value of an attribute of a given Sozi SVG element.
  1697. *
  1698. * If the attribute is empty or does not exist,
  1699. * then a default value is returned (See DEFAULTS).
  1700. */
  1701. function readAttribute(soziElement, attr) {
  1702. return soziElement.getAttributeNS(SOZI_NS, attr) || DEFAULTS[attr];
  1703. }
  1704. function readStateForLayer(frame, idLayer, soziElement) {
  1705. var state = frame.states[idLayer] =
  1706. frame.states[idLayer] || sozi.display.CameraState.instance();
  1707. if (typeof state.transitionZoomPercent === &quot;undefined&quot; || soziElement.hasAttributeNS(SOZI_NS, &quot;transition-zoom-percent&quot;)) {
  1708. state.setTransitionZoomPercent(parseInt(readAttribute(soziElement, &quot;transition-zoom-percent&quot;), 10));
  1709. }
  1710. if (typeof state.transitionProfile === &quot;undefined&quot; || soziElement.hasAttributeNS(SOZI_NS, &quot;transition-profile&quot;)) {
  1711. state.setTransitionProfile(sozi.animation.profiles[readAttribute(soziElement, &quot;transition-profile&quot;)]);
  1712. }
  1713. if (typeof state.transitionPath === &quot;undefined&quot; || soziElement.hasAttributeNS(SOZI_NS, &quot;transition-path&quot;)) {
  1714. var svgPath = document.getElementById(soziElement.getAttributeNS(SOZI_NS, &quot;transition-path&quot;));
  1715. if (svgPath &amp;&amp; svgPath.nodeName === &quot;path&quot;) {
  1716. state.setTransitionPath(svgPath);
  1717. if (readAttribute(soziElement, &quot;transition-path-hide&quot;) === &quot;true&quot;) {
  1718. svgPath.style.visibility = &quot;hidden&quot;;
  1719. }
  1720. }
  1721. }
  1722. if (soziElement.hasAttributeNS(SOZI_NS, &quot;refid&quot;)) {
  1723. var svgElement = document.getElementById(soziElement.getAttributeNS(SOZI_NS, &quot;refid&quot;));
  1724. if (svgElement) {
  1725. state.setAtElement(svgElement);
  1726. if (readAttribute(soziElement, &quot;hide&quot;) === &quot;true&quot;) {
  1727. svgElement.style.visibility = &quot;hidden&quot;;
  1728. }
  1729. }
  1730. }
  1731. if (soziElement.hasAttributeNS(SOZI_NS, &quot;clip&quot;)) {
  1732. state.setClipped(readAttribute(soziElement, &quot;clip&quot;) === &quot;true&quot;);
  1733. }
  1734. }
  1735. /*
  1736. * Builds the list of frames from the current document.
  1737. *
  1738. * This method collects all elements with tag &quot;sozi:frame&quot; and
  1739. * retrieves their geometrical and animation attributes.
  1740. * SVG elements that should be hidden during the presentation are hidden.
  1741. *
  1742. * The resulting list is available in frames, sorted by frame indices.
  1743. */
  1744. function readFrames() {
  1745. // Collect all group ids referenced in &lt;layer&gt; elements
  1746. var idLayerRefList = [];
  1747. var soziLayerList = document.getElementsByTagNameNS(SOZI_NS, &quot;layer&quot;);
  1748. for (var i = 0; i &lt; soziLayerList.length; i += 1) {
  1749. var idLayer = soziLayerList[i].getAttributeNS(SOZI_NS, &quot;group&quot;);
  1750. if (idLayer &amp;&amp; idLayerRefList.indexOf(idLayer) === -1) {
  1751. idLayerRefList.push(idLayer);
  1752. }
  1753. }
  1754. // Reorganize the document, grouping objects that do not belong
  1755. // to a group referenced in &lt;layer&gt; elements
  1756. var svgRoot = document.documentElement;
  1757. var SVG_NS = &quot;http://www.w3.org/2000/svg&quot;;
  1758. // Create the first wrapper group
  1759. var svgWrapper = document.createElementNS(SVG_NS, &quot;g&quot;);
  1760. // For each child of the root SVG element
  1761. var svgElementList = Array.prototype.slice.call(svgRoot.childNodes);
  1762. svgElementList.forEach(function (svgElement, index) {
  1763. if (!svgElement.getAttribute) {
  1764. // Remove text elements
  1765. svgRoot.removeChild(svgElement);
  1766. }
  1767. else if (idLayerRefList.indexOf(svgElement.getAttribute(&quot;id&quot;)) !== -1) {
  1768. // If the current element is a referenced layer ...
  1769. if (svgWrapper.firstChild) {
  1770. // ... and if there were other non-referenced elements before it,
  1771. // append the wrapper group to the &lt;defs&gt; element
  1772. svgWrapper.setAttribute(&quot;id&quot;, &quot;sozi-wrapper-&quot; + index);
  1773. exports.idLayerList.push(&quot;sozi-wrapper-&quot; + index);
  1774. svgRoot.insertBefore(svgWrapper, svgElement);
  1775. // Prepare a new wrapper element
  1776. svgWrapper = document.createElementNS(SVG_NS, &quot;g&quot;);
  1777. }
  1778. // ... append the current element to the &lt;defs&gt; element
  1779. exports.idLayerList.push(svgElement.getAttribute(&quot;id&quot;));
  1780. }
  1781. else if (DRAWABLE_TAGS.indexOf(svgElement.localName.toLowerCase()) !== -1) {
  1782. // If the current element is not a referenced layer
  1783. // and is drawable, move it to the current wrapper element
  1784. svgRoot.removeChild(svgElement);
  1785. svgWrapper.appendChild(svgElement);
  1786. }
  1787. });
  1788. // Append last wrapper if needed
  1789. if (svgWrapper.firstChild) {
  1790. svgWrapper.setAttribute(&quot;id&quot;, &quot;sozi-wrapper-&quot; + svgElementList.length);
  1791. exports.idLayerList.push(&quot;sozi-wrapper-&quot; + svgElementList.length);
  1792. svgRoot.appendChild(svgWrapper);
  1793. }
  1794. // Analyze &lt;frame&gt; elements sorted by sequence number
  1795. var soziFrameList = Array.prototype.slice.call(document.getElementsByTagNameNS(SOZI_NS, &quot;frame&quot;));
  1796. soziFrameList.sort(
  1797. function (a, b) {
  1798. var seqA = parseInt(readAttribute(a, &quot;sequence&quot;), 10);
  1799. var seqB = parseInt(readAttribute(b, &quot;sequence&quot;), 10)
  1800. return seqA - seqB;
  1801. }
  1802. );
  1803. soziFrameList.forEach(function (soziFrame, indexFrame) {
  1804. var newFrame = {
  1805. id: soziFrame.getAttribute(&quot;id&quot;),
  1806. title: readAttribute(soziFrame, &quot;title&quot;),
  1807. showInFrameList: readAttribute(soziFrame, &quot;show-in-frame-list&quot;) === &quot;true&quot;,
  1808. sequence: parseInt(readAttribute(soziFrame, &quot;sequence&quot;), 10),
  1809. timeoutEnable: readAttribute(soziFrame, &quot;timeout-enable&quot;) === &quot;true&quot;,
  1810. timeoutMs: parseInt(readAttribute(soziFrame, &quot;timeout-ms&quot;), 10),
  1811. transitionDurationMs: parseInt(readAttribute(soziFrame, &quot;transition-duration-ms&quot;), 10),
  1812. states: {}
  1813. };
  1814. // Get the default properties for all layers, either from
  1815. // the current &lt;frame&gt; element or from the corresponding
  1816. // layer in the previous frame.
  1817. // Those properties can later be overriden by &lt;layer&gt; elements
  1818. exports.idLayerList.forEach(function (idLayer) {
  1819. if (indexFrame === 0 || idLayer.search(&quot;sozi-wrapper-[0-9]+&quot;) !== -1) {
  1820. // In the first frame, or in wrapper layers,
  1821. // read layer attributes from the &lt;frame&gt; element
  1822. readStateForLayer(newFrame, idLayer, soziFrame);
  1823. }
  1824. else {
  1825. // After the first frame, in referenced layers,
  1826. // copy attributes from the corresponding layer in the previous frame
  1827. var currentState = newFrame.states[idLayer] = sozi.display.CameraState.instance();
  1828. var previousState = exports.frames[exports.frames.length - 1].states[idLayer];
  1829. currentState.setAtState(previousState);
  1830. }
  1831. });
  1832. // Collect and analyze &lt;layer&gt; elements in the current &lt;frame&gt; element
  1833. var soziLayerList = Array.prototype.slice.call(soziFrame.getElementsByTagNameNS(SOZI_NS, &quot;layer&quot;));
  1834. soziLayerList.forEach(function (soziLayer) {
  1835. var idLayer = soziLayer.getAttributeNS(SOZI_NS, &quot;group&quot;);
  1836. if (idLayer &amp;&amp; exports.idLayerList.indexOf(idLayer) !== -1) {
  1837. readStateForLayer(newFrame, idLayer, soziLayer);
  1838. }
  1839. });
  1840. // If the &lt;frame&gt; element has at least one valid layer,
  1841. // add it to the frame list
  1842. for (var idLayer in newFrame.states) {
  1843. if (newFrame.states.hasOwnProperty(idLayer)) {
  1844. exports.frames.push(newFrame);
  1845. break;
  1846. }
  1847. }
  1848. });
  1849. }
  1850. /**
  1851. * Return the frame with the given id.
  1852. *
  1853. * @return The index of the frame with the given id. -1 if not found.
  1854. */
  1855. exports.getFrameIndexForId = function (idFrame) {
  1856. for (var indexFrame = 0; indexFrame &lt; exports.frames.length; indexFrame += 1) {
  1857. if (exports.frames[indexFrame].id === idFrame) {
  1858. return indexFrame;
  1859. }
  1860. }
  1861. return - 1;
  1862. };
  1863. /*
  1864. * Event handler: document load.
  1865. *
  1866. * This function reads the frames from the document and fires
  1867. * the &quot;documentready&quot; event.
  1868. *
  1869. * @depend events.js
  1870. */
  1871. function onLoad() {
  1872. document.documentElement.removeAttribute(&quot;viewBox&quot;);
  1873. readFrames();
  1874. sozi.events.fire(&quot;sozi.document.ready&quot;);
  1875. }
  1876. window.addEventListener(&quot;load&quot;, onLoad, false);
  1877. });
  1878. /*
  1879. * Sozi - A presentation tool using the SVG standard
  1880. *
  1881. * Copyright (C) 2010-2013 Guillaume Savaton
  1882. *
  1883. * This program is dual licensed under the terms of the MIT license
  1884. * or the GNU General Public License (GPL) version 3.
  1885. * A copy of both licenses is provided in the doc/ folder of the
  1886. * official release of Sozi.
  1887. *
  1888. * See http://sozi.baierouge.fr/wiki/en:license for details.
  1889. */
  1890. /**
  1891. * @name sozi.framelist
  1892. * @namespace Show the frame list.
  1893. * @depend namespace.js
  1894. */
  1895. namespace(this, &quot;sozi.framelist&quot;, function (exports, window) {
  1896. &quot;use strict&quot;;
  1897. // An alias to the global document object
  1898. var document = window.document;
  1899. // Constant: the margin around the text of the frame list
  1900. var MARGIN = 5;
  1901. // The SVG group that will contain the frame list
  1902. var svgTocGroup;
  1903. // The SVG group that will contain the frame titles
  1904. var svgTitlesGroup;
  1905. // The current height of the frame list,
  1906. // computed during the initialization
  1907. var tocHeight = 0;
  1908. // The X coordinate of the frame list in its hidden state
  1909. var translateXHidden;
  1910. // The X coordinate of the frame list when it is completely visible
  1911. var translateXVisible;
  1912. // The initial X coordinate of the frame list before starting an animation.
  1913. // This variable is set before showing/hiding the frame list.
  1914. var translateXStart;
  1915. // The final X coordinate of the frame list for the starting animation.
  1916. // This variable is set before showing/hiding the frame list.
  1917. var translateXEnd;
  1918. // The current X coordinate of the frame list for the running animation.
  1919. // This variable is updated on each animation step.
  1920. var translateX;
  1921. // The animator object that will manage animations of the frame list
  1922. var animator;
  1923. // Constant: the duration of the showing/hiding animation, in milliseconds
  1924. var ANIMATION_TIME_MS = 300;
  1925. // Constant: the acceleration profile of the showing/hiding animation
  1926. var ANIMATION_PROFILE = &quot;decelerate&quot;;
  1927. // Constant: the SVG namespace
  1928. var SVG_NS = &quot;http://www.w3.org/2000/svg&quot;;
  1929. function onMouseOut(evt) {
  1930. var rel = evt.relatedTarget,
  1931. svgRoot = document.documentElement;
  1932. while (rel &amp;&amp; rel !== svgTocGroup &amp;&amp; rel !== svgRoot) {
  1933. rel = rel.parentNode;
  1934. }
  1935. if (rel !== svgTocGroup) {
  1936. exports.hide();
  1937. sozi.player.restart();
  1938. evt.stopPropagation();
  1939. }
  1940. }
  1941. function onClickArrowUp(evt) {
  1942. var ty = svgTitlesGroup.getCTM().f;
  1943. if (ty &lt;= -window.innerHeight / 2) {
  1944. ty += window.innerHeight / 2;
  1945. } else if (ty &lt; 0) {
  1946. ty = 0;
  1947. }
  1948. svgTitlesGroup.setAttribute(&quot;transform&quot;, &quot;translate(0,&quot; + ty + &quot;)&quot;);
  1949. evt.stopPropagation();
  1950. }
  1951. function onClickArrowDown(evt) {
  1952. var ty = svgTitlesGroup.getCTM().f;
  1953. if (ty + tocHeight &gt;= window.innerHeight * 3 / 2) {
  1954. ty -= window.innerHeight / 2;
  1955. } else if (ty + tocHeight &gt; window.innerHeight + 2 * MARGIN) {
  1956. ty = window.innerHeight - tocHeight - 4 * MARGIN;
  1957. }
  1958. svgTitlesGroup.setAttribute(&quot;transform&quot;, &quot;translate(0,&quot; + ty + &quot;)&quot;);
  1959. evt.stopPropagation();
  1960. }
  1961. /*
  1962. * Create a function that responds to clicks on frame list entries.
  1963. */
  1964. function makeClickHandler(index) {
  1965. return function (evt) {
  1966. sozi.player.previewFrame(index);
  1967. evt.stopPropagation();
  1968. };
  1969. }
  1970. /*
  1971. * The default event handler, to prevent event propagation
  1972. * through the frame list.
  1973. */
  1974. function defaultEventHandler(evt) {
  1975. evt.stopPropagation();
  1976. }
  1977. /*
  1978. * Adds a table of contents to the document.
  1979. *
  1980. * The table of contents is a rectangular region with the list of frame titles.
  1981. * Clicking on a title moves the presentation to the corresponding frame.
  1982. *
  1983. * The table of contents is hidden by default.
  1984. */
  1985. function onPlayerReady() {
  1986. svgTocGroup = document.createElementNS(SVG_NS, &quot;g&quot;);
  1987. svgTocGroup.setAttribute(&quot;id&quot;, &quot;sozi-toc&quot;);
  1988. document.documentElement.appendChild(svgTocGroup);
  1989. svgTitlesGroup = document.createElementNS(SVG_NS, &quot;g&quot;);
  1990. svgTocGroup.appendChild(svgTitlesGroup);
  1991. // The background rectangle of the frame list
  1992. var tocBackground = document.createElementNS(SVG_NS, &quot;rect&quot;);
  1993. tocBackground.setAttribute(&quot;id&quot;, &quot;sozi-toc-background&quot;);
  1994. tocBackground.setAttribute(&quot;x&quot;, MARGIN);
  1995. tocBackground.setAttribute(&quot;y&quot;, MARGIN);
  1996. tocBackground.setAttribute(&quot;rx&quot;, MARGIN);
  1997. tocBackground.setAttribute(&quot;ry&quot;, MARGIN);
  1998. tocBackground.addEventListener(&quot;click&quot;, defaultEventHandler, false);
  1999. tocBackground.addEventListener(&quot;mousedown&quot;, defaultEventHandler, false);
  2000. tocBackground.addEventListener(&quot;mouseout&quot;, onMouseOut, false);
  2001. svgTitlesGroup.appendChild(tocBackground);
  2002. var tocWidth = 0;
  2003. sozi.document.frames.forEach(function (frame, frameIndex) {
  2004. if (frame.showInFrameList) {
  2005. var text = document.createElementNS(SVG_NS, &quot;text&quot;);
  2006. text.appendChild(document.createTextNode(frame.title));
  2007. text.setAttribute(&quot;id&quot;, &quot;sozi-toc-&quot; + frame.id);
  2008. svgTitlesGroup.appendChild(text);
  2009. if (frameIndex === sozi.player.currentFrameIndex) {
  2010. text.setAttribute(&quot;class&quot;, &quot;sozi-toc-current&quot;);
  2011. }
  2012. var textWidth = text.getBBox().width;
  2013. tocHeight += text.getBBox().height;
  2014. if (textWidth &gt; tocWidth) {
  2015. tocWidth = textWidth;
  2016. }
  2017. text.setAttribute(&quot;x&quot;, 2 * MARGIN);
  2018. text.setAttribute(&quot;y&quot;, tocHeight + MARGIN);
  2019. text.addEventListener(&quot;click&quot;, makeClickHandler(frameIndex), false);
  2020. text.addEventListener(&quot;mousedown&quot;, defaultEventHandler, false);
  2021. }
  2022. });
  2023. // The &quot;up&quot; button
  2024. var tocUp = document.createElementNS(SVG_NS, &quot;path&quot;);
  2025. tocUp.setAttribute(&quot;class&quot;, &quot;sozi-toc-arrow&quot;);
  2026. tocUp.setAttribute(&quot;d&quot;, &quot;M&quot; + (tocWidth + 3 * MARGIN) + &quot;,&quot; + (5 * MARGIN) +
  2027. &quot; l&quot; + (4 * MARGIN) + &quot;,0&quot; +
  2028. &quot; l-&quot; + (2 * MARGIN) + &quot;,-&quot; + (3 * MARGIN) +
  2029. &quot; z&quot;);
  2030. tocUp.addEventListener(&quot;click&quot;, onClickArrowUp, false);
  2031. tocUp.addEventListener(&quot;mousedown&quot;, defaultEventHandler, false);
  2032. svgTocGroup.appendChild(tocUp);
  2033. // The &quot;down&quot; button
  2034. var tocDown = document.createElementNS(SVG_NS, &quot;path&quot;);
  2035. tocDown.setAttribute(&quot;class&quot;, &quot;sozi-toc-arrow&quot;);
  2036. tocDown.setAttribute(&quot;d&quot;, &quot;M&quot; + (tocWidth + 3 * MARGIN) + &quot;,&quot; + (7 * MARGIN) +
  2037. &quot; l&quot; + (4 * MARGIN) + &quot;,0&quot; +
  2038. &quot; l-&quot; + (2 * MARGIN) + &quot;,&quot; + (3 * MARGIN) +
  2039. &quot; z&quot;);
  2040. tocDown.addEventListener(&quot;click&quot;, onClickArrowDown, false);
  2041. tocDown.addEventListener(&quot;mousedown&quot;, defaultEventHandler, false);
  2042. svgTocGroup.appendChild(tocDown);
  2043. tocBackground.setAttribute(&quot;width&quot;, tocWidth + 7 * MARGIN);
  2044. tocBackground.setAttribute(&quot;height&quot;, tocHeight + 2 * MARGIN);
  2045. translateXHidden = -tocWidth - 9 * MARGIN;
  2046. translateXVisible = 0;
  2047. translateX = translateXEnd = translateXHidden;
  2048. svgTocGroup.setAttribute(&quot;transform&quot;, &quot;translate(&quot; + translateXHidden + &quot;,0)&quot;);
  2049. animator = sozi.animation.Animator.instance().augment({
  2050. onStep: function (progress) {
  2051. var profileProgress = sozi.animation.profiles[ANIMATION_PROFILE](progress),
  2052. remaining = 1 - profileProgress;
  2053. translateX = translateXEnd * profileProgress + translateXStart * remaining;
  2054. svgTocGroup.setAttribute(&quot;transform&quot;, &quot;translate(&quot; + translateX + &quot;,0)&quot;);
  2055. }
  2056. });
  2057. }
  2058. /*
  2059. * Highlight the current frame title in the frame list.
  2060. *
  2061. * This handler is called on each frame change,
  2062. * even when the frame list is hidden.
  2063. */
  2064. function onFrameChange(index) {
  2065. var currentElementList = Array.prototype.slice.call(document.getElementsByClassName(&quot;sozi-toc-current&quot;));
  2066. currentElementList.forEach(function (svgElement) {
  2067. svgElement.removeAttribute(&quot;class&quot;);
  2068. });
  2069. var frame = sozi.document.frames[index];
  2070. if (frame.showInFrameList) {
  2071. document.getElementById(&quot;sozi-toc-&quot; + frame.id).setAttribute(&quot;class&quot;, &quot;sozi-toc-current&quot;);
  2072. }
  2073. }
  2074. /*
  2075. * Makes the table of contents visible.
  2076. */
  2077. exports.show = function () {
  2078. // Bring frame list to front
  2079. document.documentElement.appendChild(svgTocGroup);
  2080. translateXStart = translateX;
  2081. translateXEnd = translateXVisible;
  2082. animator.start(ANIMATION_TIME_MS); // FIXME depends on current elapsed time
  2083. };
  2084. /*
  2085. * Makes the table of contents invisible.
  2086. */
  2087. exports.hide = function () {
  2088. translateXStart = translateX;
  2089. translateXEnd = translateXHidden;
  2090. animator.start(ANIMATION_TIME_MS); // FIXME depends on current elapsed time
  2091. };
  2092. /*
  2093. * Returns true if the table of contents is visible, false otherwise.
  2094. */
  2095. exports.isVisible = function () {
  2096. return translateXEnd === translateXVisible;
  2097. };
  2098. // @depend events.js
  2099. sozi.events.listen(&quot;sozi.player.ready&quot;, onPlayerReady);
  2100. sozi.events.listen(&quot;sozi.player.cleanup&quot;, exports.hide);
  2101. sozi.events.listen(&quot;sozi.player.framechange&quot;, onFrameChange);
  2102. });
  2103. /*
  2104. * Sozi - A presentation tool using the SVG standard
  2105. *
  2106. * Copyright (C) 2010-2013 Guillaume Savaton
  2107. *
  2108. * This program is dual licensed under the terms of the MIT license
  2109. * or the GNU General Public License (GPL) version 3.
  2110. * A copy of both licenses is provided in the doc/ folder of the
  2111. * official release of Sozi.
  2112. *
  2113. * See http://sozi.baierouge.fr/wiki/en:license for details.
  2114. */
  2115. /**
  2116. * @name sozi.framenumber
  2117. * @namespace Show the frame number.
  2118. * @depend namespace.js
  2119. */
  2120. namespace(this, &quot;sozi.framenumber&quot;, function (exports, window) {
  2121. &quot;use strict&quot;;
  2122. // An alias to the global document object
  2123. var document = window.document;
  2124. // The SVG group containing the frame number
  2125. var svgGroup;
  2126. // The SVG text element and its text node containing the frame number
  2127. var svgText, svgTextNode;
  2128. // The SVG circle enclosing the frame number
  2129. var svgCircle;
  2130. // Constant: the SVG namespace
  2131. var SVG_NS = &quot;http://www.w3.org/2000/svg&quot;;
  2132. function adjust() {
  2133. var textBBox = svgText.getBBox(),
  2134. d = Math.max(textBBox.width, textBBox.height) * 0.75,
  2135. t = d * 1.25;
  2136. svgCircle.setAttribute(&quot;r&quot;, d);
  2137. svgGroup.setAttribute(&quot;transform&quot;, &quot;translate(&quot; + t + &quot;,&quot; + t + &quot;)&quot;);
  2138. }
  2139. function onPlayerReady() {
  2140. svgGroup = document.createElementNS(SVG_NS, &quot;g&quot;);
  2141. svgText = document.createElementNS(SVG_NS, &quot;text&quot;);
  2142. svgCircle = document.createElementNS(SVG_NS, &quot;circle&quot;);
  2143. svgGroup.setAttribute(&quot;id&quot;, &quot;sozi-framenumber&quot;);
  2144. svgCircle.setAttribute(&quot;cx&quot;, 0);
  2145. svgCircle.setAttribute(&quot;cy&quot;, 0);
  2146. svgGroup.appendChild(svgCircle);
  2147. svgTextNode = document.createTextNode(sozi.player.currentFrameIndex + 1);
  2148. svgText.setAttribute(&quot;text-anchor&quot;, &quot;middle&quot;);
  2149. svgText.setAttribute(&quot;dominant-baseline&quot;, &quot;central&quot;);
  2150. svgText.setAttribute(&quot;x&quot;, 0);
  2151. svgText.setAttribute(&quot;y&quot;, 0);
  2152. svgText.appendChild(svgTextNode);
  2153. svgGroup.appendChild(svgText);
  2154. document.documentElement.appendChild(svgGroup);
  2155. adjust();
  2156. }
  2157. function onFrameChange(index) {
  2158. svgTextNode.nodeValue = index + 1;
  2159. }
  2160. // @depend events.js
  2161. sozi.events.listen(&quot;sozi.player.ready&quot;, onPlayerReady);
  2162. sozi.events.listen(&quot;sozi.player.framechange&quot;, onFrameChange);
  2163. });
  2164. /*
  2165. * Sozi - A presentation tool using the SVG standard
  2166. *
  2167. * Copyright (C) 2010-2013 Guillaume Savaton
  2168. *
  2169. * This program is dual licensed under the terms of the MIT license
  2170. * or the GNU General Public License (GPL) version 3.
  2171. * A copy of both licenses is provided in the doc/ folder of the
  2172. * official release of Sozi.
  2173. *
  2174. * See http://sozi.baierouge.fr/wiki/en:license for details.
  2175. */
  2176. /**
  2177. * @name sozi.links
  2178. * @namespace Links fix for Webkit.
  2179. * @depend namespace.js
  2180. */
  2181. namespace(this, &quot;sozi.links&quot;, function (exports, window) {
  2182. &quot;use strict&quot;;
  2183. var SVG_NS = &quot;http://www.w3.org/2000/svg&quot;;
  2184. var XLINK_NS = &quot;http://www.w3.org/1999/xlink&quot;;
  2185. function getClickHandler(index) {
  2186. return function (evt) {
  2187. sozi.player.moveToFrame(index);
  2188. evt.preventDefault();
  2189. evt.stopPropagation();
  2190. };
  2191. }
  2192. /*
  2193. * Event handler: document ready.
  2194. *
  2195. * This function adds an event listener to each internal link.
  2196. * Clicking on a link that targets a frame of this document
  2197. * will call sozi.player.moveToFrame().
  2198. */
  2199. function onDocumentReady() {
  2200. var links = window.document.getElementsByTagNameNS(SVG_NS, &quot;a&quot;);
  2201. for (var i = 0; i &lt; links.length; i += 1) {
  2202. var href = links[i].getAttributeNS(XLINK_NS, &quot;href&quot;);
  2203. if (href &amp;&amp; href[0] === &quot;#&quot;) {
  2204. links[i].addEventListener(&quot;click&quot;, getClickHandler(sozi.location.getFrameIndexForHash(href)), false);
  2205. }
  2206. }
  2207. }
  2208. sozi.events.listen(&quot;sozi.document.ready&quot;, onDocumentReady); // @depend events.js
  2209. });
  2210. /*
  2211. * Sozi - A presentation tool using the SVG standard
  2212. *
  2213. * Copyright (C) 2010-2013 Guillaume Savaton
  2214. *
  2215. * This program is dual licensed under the terms of the MIT license
  2216. * or the GNU General Public License (GPL) version 3.
  2217. * A copy of both licenses is provided in the doc/ folder of the
  2218. * official release of Sozi.
  2219. *
  2220. * See http://sozi.baierouge.fr/wiki/en:license for details.
  2221. */
  2222. /**
  2223. * @name sozi.location
  2224. * @namespace Manage the URL in the address bar of the browser window.
  2225. * @depend namespace.js
  2226. */
  2227. namespace(this, &quot;sozi.location&quot;, function (exports, window) {
  2228. &quot;use strict&quot;;
  2229. var changedFromWithin = false;
  2230. /*
  2231. * Returns the frame index corresponding to the URL hash.
  2232. *
  2233. * This is a shortcut for sozi.location.getFrameIndexForHash(window.location.hash)
  2234. */
  2235. exports.getFrameIndex = function () {
  2236. return exports.getFrameIndexForHash(window.location.hash);
  2237. };
  2238. /*
  2239. * Returns the frame index corresponding to the given URL hash.
  2240. *
  2241. * The URL hash can be either a frame index or a frame id.
  2242. * In the URL, the frame index starts a 1.
  2243. * This method converts it into a 0-based index.
  2244. *
  2245. * If the URL hash is not a positive integer, then 0 is returned.
  2246. * It the URL hash is an integer greater than the last frame index, then
  2247. * the last frame index is returned.
  2248. */
  2249. exports.getFrameIndexForHash = function (hash) {
  2250. var indexOrId = hash ? hash.slice(1) : &quot;1&quot;;
  2251. var index;
  2252. if (/^[0-9]+$/.test(indexOrId)) {
  2253. index = parseInt(indexOrId, 10) - 1;
  2254. }
  2255. else {
  2256. index = sozi.document.getFrameIndexForId(indexOrId);
  2257. }
  2258. if (index &lt; 0) {
  2259. return 0;
  2260. }
  2261. else if (index &gt;= sozi.document.frames.length) {
  2262. return sozi.document.frames.length - 1;
  2263. }
  2264. else {
  2265. return index;
  2266. }
  2267. };
  2268. /*
  2269. * Event handler: hash change.
  2270. *
  2271. * This function is called when the URL hash is changed.
  2272. * If the hash was changed manually in the address bar, and if it corresponds to
  2273. * a valid frame number, then the presentation moves to that frame.
  2274. *
  2275. * The hashchange event can be triggered externally, by the user modifying the URL,
  2276. * or internally, by the script modifying window.location.hash.
  2277. */
  2278. function onHashChange() {
  2279. var index = exports.getFrameIndex();
  2280. if (!changedFromWithin) {
  2281. sozi.player.moveToFrame(index);
  2282. }
  2283. changedFromWithin = false;
  2284. }
  2285. /*
  2286. * Event handler: frame change.
  2287. *
  2288. * This function is called when the presentation has reached a new frame.
  2289. * The URL hash is set to the current frame id.
  2290. */
  2291. function onFrameChange(index) {
  2292. changedFromWithin = true;
  2293. window.location.hash = &quot;#&quot; + sozi.document.frames[index].id;
  2294. }
  2295. window.addEventListener(&quot;hashchange&quot;, onHashChange, false);
  2296. sozi.events.listen(&quot;sozi.player.framechange&quot;, onFrameChange); // @depend events.js
  2297. });
  2298. /*
  2299. * Sozi - A presentation tool using the SVG standard
  2300. *
  2301. * Copyright (C) 2010-2013 Guillaume Savaton
  2302. *
  2303. * This program is dual licensed under the terms of the MIT license
  2304. * or the GNU General Public License (GPL) version 3.
  2305. * A copy of both licenses is provided in the doc/ folder of the
  2306. * official release of Sozi.
  2307. *
  2308. * See http://sozi.baierouge.fr/wiki/en:license for details.
  2309. */
  2310. /**
  2311. * @name sozi.player
  2312. * @namespace Presentation player.
  2313. * @depend namespace.js
  2314. */
  2315. namespace(this, &quot;sozi.player&quot;, function (exports, window) {
  2316. &quot;use strict&quot;;
  2317. var viewPort;
  2318. // The animator object used to animate transitions
  2319. var animator;
  2320. // The handle returned by setTimeout() for frame timeout
  2321. var nextFrameTimeout;
  2322. // Constants: default animation properties
  2323. // for out-of-sequence transitions
  2324. var DEFAULT_DURATION_MS = 500;
  2325. var DEFAULT_ZOOM_PERCENT = -10;
  2326. var DEFAULT_PROFILE = &quot;linear&quot;;
  2327. // The source frame index for the current transition
  2328. var sourceFrameIndex = 0;
  2329. // The index of the visible frame
  2330. exports.currentFrameIndex = 0;
  2331. // The state of the presentation.
  2332. // If false, no automatic transition will be fired.
  2333. var playing = false;
  2334. // The state of the current frame.
  2335. // If true, an automatic transition will be fired after the current timeout.
  2336. var waiting = false;
  2337. /*
  2338. * Starts waiting before moving to the next frame.
  2339. *
  2340. * It the current frame has a timeout set, this method
  2341. * will register a timer to move to the next frame automatically
  2342. * after the specified time.
  2343. *
  2344. * If the current frame is the last, the presentation will
  2345. * move to the first frame.
  2346. */
  2347. function waitTimeout() {
  2348. if (sozi.document.frames[exports.currentFrameIndex].timeoutEnable) {
  2349. waiting = true;
  2350. var index = (exports.currentFrameIndex + 1) % sozi.document.frames.length;
  2351. nextFrameTimeout = window.setTimeout(function () {
  2352. exports.moveToFrame(index);
  2353. },
  2354. sozi.document.frames[exports.currentFrameIndex].timeoutMs
  2355. );
  2356. }
  2357. }
  2358. /*
  2359. * Starts the presentation from the given frame index (0-based).
  2360. *
  2361. * This method sets the &quot;playing&quot; flag, shows the desired frame
  2362. * and calls waitTimeout.
  2363. */
  2364. exports.startFromIndex = function (index) {
  2365. playing = true;
  2366. waiting = false;
  2367. sourceFrameIndex = index;
  2368. exports.currentFrameIndex = index;
  2369. viewPort.showFrame(sozi.document.frames[index]);
  2370. waitTimeout();
  2371. };
  2372. exports.restart = function () {
  2373. exports.startFromIndex(exports.currentFrameIndex);
  2374. };
  2375. /*
  2376. * Stops the presentation.
  2377. *
  2378. * This method clears the &quot;playing&quot;.
  2379. * If the presentation was in &quot;waiting&quot; mode due to a timeout
  2380. * in the current frame, then it stops waiting.
  2381. * The current animation is stopped in its current state.
  2382. */
  2383. exports.stop = function () {
  2384. animator.stop();
  2385. if (waiting) {
  2386. window.clearTimeout(nextFrameTimeout);
  2387. waiting = false;
  2388. }
  2389. playing = false;
  2390. sourceFrameIndex = exports.currentFrameIndex;
  2391. };
  2392. function getZoomData(zoomPercent, s0, s1) {
  2393. var result = {
  2394. ss: ((zoomPercent &lt; 0) ? Math.max(s0, s1) : Math.min(s0, s1)) * (100 - zoomPercent) / 100,
  2395. ts: 0.5,
  2396. k: 0
  2397. };
  2398. if (zoomPercent !== 0) {
  2399. var a = s0 - s1;
  2400. var b = s0 - result.ss;
  2401. var c = s1 - result.ss;
  2402. if (a !== 0) {
  2403. var d = Math.sqrt(b * c);
  2404. var u = (b - d) / a;
  2405. var v = (b + d) / a;
  2406. result.ts = (u &gt; 0 &amp;&amp; u &lt;= 1) ? u : v;
  2407. }
  2408. result.k = b / result.ts / result.ts;
  2409. }
  2410. return result;
  2411. }
  2412. /*
  2413. * Jump to a frame with the given index (0-based).
  2414. *
  2415. * This method does not animate the transition from the current
  2416. * state of the display to the desired frame.
  2417. *
  2418. * The presentation is stopped: if a timeout has been set for the
  2419. * target frame, it will be ignored.
  2420. *
  2421. * The URL hash is set to the given frame index (1-based).
  2422. */
  2423. exports.jumpToFrame = function (index) {
  2424. exports.stop();
  2425. sozi.events.fire(&quot;sozi.player.cleanup&quot;);
  2426. sourceFrameIndex = index;
  2427. exports.currentFrameIndex = index;
  2428. viewPort.showFrame(sozi.document.frames[index]);
  2429. sozi.events.fire(&quot;sozi.player.framechange&quot;, index);
  2430. };
  2431. /*
  2432. * Returns an associative array where keys are layer names
  2433. * and values are objects in the form { initialState: finalState: profile: zoomWidth: zoomHeight:}
  2434. */
  2435. exports.getAnimationData = function (initialState, finalState, zoomPercent, profile, useTransitionPath, reverseTransitionPath) {
  2436. var data = {};
  2437. for (var idLayer in initialState) {
  2438. data[idLayer] = {
  2439. initialState: sozi.display.CameraState.instance(),
  2440. finalState: sozi.display.CameraState.instance(),
  2441. useTransitionPath: useTransitionPath,
  2442. reverseTransitionPath: reverseTransitionPath
  2443. };
  2444. data[idLayer].profile = profile || finalState[idLayer].transitionProfile;
  2445. data[idLayer].initialState.setAtState(initialState[idLayer]);
  2446. // If the current layer is referenced in final state, copy the final properties
  2447. // else, copy initial state to final state for the current layer.
  2448. if (finalState.hasOwnProperty(idLayer)) {
  2449. data[idLayer].finalState.setAtState(finalState[idLayer]);
  2450. }
  2451. else {
  2452. data[idLayer].finalState.setAtState(initialState[idLayer]);
  2453. }
  2454. // Keep the smallest angle difference between initial state and final state
  2455. // TODO this should be handled in the interpolation function
  2456. if (data[idLayer].finalState.angle - data[idLayer].initialState.angle &gt; 180) {
  2457. data[idLayer].finalState.setRawAngle(data[idLayer].finalState.angle - 360);
  2458. }
  2459. else if (data[idLayer].finalState.angle - data[idLayer].initialState.angle &lt; -180) {
  2460. data[idLayer].initialState.setRawAngle(data[idLayer].initialState.angle - 360);
  2461. }
  2462. var zp = zoomPercent || finalState[idLayer].transitionZoomPercent;
  2463. if (zp &amp;&amp; finalState.hasOwnProperty(idLayer)) {
  2464. data[idLayer].zoomWidth = getZoomData(zp,
  2465. initialState[idLayer].width,
  2466. finalState[idLayer].width);
  2467. data[idLayer].zoomHeight = getZoomData(zp,
  2468. initialState[idLayer].height,
  2469. finalState[idLayer].height);
  2470. }
  2471. }
  2472. return data;
  2473. };
  2474. exports.previewFrame = function (index) {
  2475. exports.currentFrameIndex = index;
  2476. animator.start(DEFAULT_DURATION_MS,
  2477. exports.getAnimationData(viewPort.cameras, sozi.document.frames[index].states,
  2478. DEFAULT_ZOOM_PERCENT, sozi.animation.profiles[DEFAULT_PROFILE]),
  2479. false, false);
  2480. sozi.events.fire(&quot;sozi.player.framechange&quot;, index);
  2481. };
  2482. /*
  2483. * Moves to a frame with the given index (0-based).
  2484. *
  2485. * This method animates the transition from the current
  2486. * state of the display to the desired frame.
  2487. *
  2488. * If the given frame index corresponds to the next frame in the list,
  2489. * the transition properties of the next frame are used.
  2490. * Otherwise, default transition properties are used.
  2491. */
  2492. exports.moveToFrame = function (index) {
  2493. if (waiting) {
  2494. window.clearTimeout(nextFrameTimeout);
  2495. waiting = false;
  2496. }
  2497. var durationMs, zoomPercent, profile, useTransitionPath, reverseTransitionPath;
  2498. if (index === (exports.currentFrameIndex - 1) % sozi.document.frames.length) {
  2499. durationMs = sozi.document.frames[exports.currentFrameIndex].transitionDurationMs;
  2500. zoomPercent = undefined; // Set for each layer
  2501. profile = undefined; // Set for each layer
  2502. useTransitionPath = true;
  2503. reverseTransitionPath = true;
  2504. }
  2505. else if (index === (exports.currentFrameIndex + 1) % sozi.document.frames.length) {
  2506. durationMs = sozi.document.frames[index].transitionDurationMs;
  2507. zoomPercent = undefined; // Set for each layer
  2508. profile = undefined; // Set for each layer
  2509. useTransitionPath = true;
  2510. reverseTransitionPath = false;
  2511. }
  2512. else {
  2513. durationMs = DEFAULT_DURATION_MS;
  2514. zoomPercent = DEFAULT_ZOOM_PERCENT;
  2515. profile = sozi.animation.profiles[DEFAULT_PROFILE];
  2516. useTransitionPath = false;
  2517. reverseTransitionPath = false;
  2518. }
  2519. sozi.events.fire(&quot;sozi.player.cleanup&quot;);
  2520. playing = true;
  2521. exports.currentFrameIndex = index;
  2522. animator.start(durationMs, exports.getAnimationData(
  2523. viewPort.cameras, sozi.document.frames[index].states,
  2524. zoomPercent, profile,
  2525. useTransitionPath, reverseTransitionPath));
  2526. sozi.events.fire(&quot;sozi.player.framechange&quot;, index);
  2527. };
  2528. /**
  2529. * Jumps to the first frame of the presentation.
  2530. */
  2531. exports.jumpToFirst = function () {
  2532. exports.jumpToFrame(0);
  2533. };
  2534. /**
  2535. * Moves to the first frame of the presentation.
  2536. */
  2537. exports.moveToFirst = function () {
  2538. exports.moveToFrame(0);
  2539. };
  2540. /**
  2541. * Jumps to the previous frame.
  2542. */
  2543. exports.jumpToPrevious = function () {
  2544. var index = exports.currentFrameIndex;
  2545. if (!animator.started || sourceFrameIndex &lt;= exports.currentFrameIndex) {
  2546. index -= 1;
  2547. }
  2548. if (index &gt;= 0) {
  2549. exports.jumpToFrame(index);
  2550. }
  2551. };
  2552. /*
  2553. * Moves to the previous frame.
  2554. */
  2555. exports.moveToPrevious = function () {
  2556. for (var index = exports.currentFrameIndex - 1; index &gt;= 0; index -= 1) {
  2557. var frame = sozi.document.frames[index];
  2558. if (!frame.timeoutEnable || frame.timeoutMs !== 0) {
  2559. exports.moveToFrame(index);
  2560. break;
  2561. }
  2562. }
  2563. };
  2564. /**
  2565. * Jumps to the next frame.
  2566. */
  2567. exports.jumpToNext = function () {
  2568. var index = exports.currentFrameIndex;
  2569. if (!animator.started || sourceFrameIndex &gt;= exports.currentFrameIndex) {
  2570. index += 1;
  2571. }
  2572. if (index &lt; sozi.document.frames.length) {
  2573. exports.jumpToFrame(index);
  2574. }
  2575. };
  2576. /**
  2577. * Moves to the next frame.
  2578. */
  2579. exports.moveToNext = function () {
  2580. if (exports.currentFrameIndex &lt; sozi.document.frames.length - 1 || sozi.document.frames[exports.currentFrameIndex].timeoutEnable) {
  2581. exports.moveToFrame((exports.currentFrameIndex + 1) % sozi.document.frames.length);
  2582. }
  2583. };
  2584. /**
  2585. * Jumps to the last frame of the presentation.
  2586. */
  2587. exports.jumpToLast = function () {
  2588. exports.jumpToFrame(sozi.document.frames.length - 1);
  2589. };
  2590. /**
  2591. * Moves to the last frame of the presentation.
  2592. */
  2593. exports.moveToLast = function () {
  2594. exports.moveToFrame(sozi.document.frames.length - 1);
  2595. };
  2596. /*
  2597. * Restores the current frame.
  2598. *
  2599. * This method restores the display to fit the current frame,
  2600. * e.g. after the display has been zoomed or dragged.
  2601. */
  2602. exports.moveToCurrent = function () {
  2603. exports.moveToFrame(exports.currentFrameIndex);
  2604. };
  2605. /*
  2606. * Shows all the document in the browser window.
  2607. */
  2608. exports.showAll = function () {
  2609. exports.stop();
  2610. sozi.events.fire(&quot;sozi.player.cleanup&quot;);
  2611. animator.start(DEFAULT_DURATION_MS,
  2612. exports.getAnimationData(viewPort.cameras, viewPort.getDocumentState(),
  2613. DEFAULT_ZOOM_PERCENT, sozi.animation.profiles[DEFAULT_PROFILE],
  2614. false, false
  2615. )
  2616. );
  2617. };
  2618. /*
  2619. * Event handler: display ready.
  2620. */
  2621. function onDisplayReady() {
  2622. viewPort = sozi.display.ViewPort.instance(&quot;player&quot;, sozi.document.idLayerList, true);
  2623. exports.startFromIndex(sozi.location.getFrameIndex());
  2624. // Hack to fix the blank screen bug in Chrome/Chromium
  2625. // See https://github.com/senshu/Sozi/issues/109
  2626. window.setTimeout(viewPort.bind(viewPort.update), 1);
  2627. sozi.events.fire(&quot;sozi.player.ready&quot;);
  2628. }
  2629. // TODO move the zoom code to display.js
  2630. exports.onAnimationStep = function (progress, data) {
  2631. for (var idLayer in data) {
  2632. var camera = viewPort.cameras[idLayer];
  2633. camera.interpolate(
  2634. data[idLayer].initialState,
  2635. data[idLayer].finalState,
  2636. data[idLayer].profile(progress),
  2637. data[idLayer].useTransitionPath,
  2638. data[idLayer].reverseTransitionPath
  2639. );
  2640. var ps;
  2641. if (data[idLayer].zoomWidth &amp;&amp; data[idLayer].zoomWidth.k !== 0) {
  2642. ps = progress - data[idLayer].zoomWidth.ts;
  2643. camera.width = data[idLayer].zoomWidth.k * ps * ps + data[idLayer].zoomWidth.ss;
  2644. }
  2645. if (data[idLayer].zoomHeight &amp;&amp; data[idLayer].zoomHeight.k !== 0) {
  2646. ps = progress - data[idLayer].zoomHeight.ts;
  2647. camera.height = data[idLayer].zoomHeight.k * ps * ps + data[idLayer].zoomHeight.ss;
  2648. }
  2649. camera.setClipped(data[idLayer].finalState.clipped);
  2650. }
  2651. viewPort.update();
  2652. };
  2653. /**
  2654. * @depend animation.js
  2655. */
  2656. animator = sozi.animation.Animator.instance().augment({
  2657. /*
  2658. * Event handler: animation step.
  2659. *
  2660. * This method is called periodically by animator after the animation
  2661. * has been started, and until the animation time is elapsed.
  2662. *
  2663. * Parameter data provides the following information:
  2664. * - initialState and finalState contain the geometrical properties of the display
  2665. * at the start and end of the animation.
  2666. * - profile is a reference to the speed profile function to use.
  2667. * - zoomWidth and zoomHeight are the parameters of the zooming polynomial if the current
  2668. * animation has a non-zero zooming effect.
  2669. *
  2670. * Parameter progress is a float number between 0 (start of the animation)
  2671. * and 1 (end of the animation).
  2672. */
  2673. onStep: function (progress) {
  2674. exports.onAnimationStep(progress, this.data);
  2675. },
  2676. /*
  2677. * Event handler: animation done.
  2678. *
  2679. * This method is called by animator when the current animation is finished.
  2680. *
  2681. * If the animation was a transition in the normal course of the presentation,
  2682. * then we call the waitTimeout method to process the timeout property of the current frame.
  2683. */
  2684. onDone: function () {
  2685. for (var idLayer in this.data) {
  2686. viewPort.cameras[idLayer].setAtState(this.data[idLayer].finalState);
  2687. }
  2688. viewPort.update();
  2689. sourceFrameIndex = exports.currentFrameIndex;
  2690. if (playing) {
  2691. waitTimeout();
  2692. }
  2693. }
  2694. });
  2695. sozi.events.listen(&quot;sozi.display.ready&quot;, onDisplayReady); // @depend events.js
  2696. });
  2697. /*
  2698. @depend framenumber.js
  2699. @depend framelist.js
  2700. @depend actions.js
  2701. @depend player.js
  2702. @depend display.js
  2703. @depend document.js
  2704. @depend location.js
  2705. @depend links.js
  2706. */
  2707. </script>
  2708. <style
  2709. id="sozi-style"
  2710. ns1:version="13.11-30213629">/*
  2711. * Sozi - A presentation tool using the SVG standard
  2712. *
  2713. * Copyright (C) 2010-2013 Guillaume Savaton
  2714. *
  2715. * This program is dual licensed under the terms of the MIT license
  2716. * or the GNU General Public License (GPL) version 3.
  2717. * A copy of both licenses is provided in the doc/ folder of the
  2718. * official release of Sozi.
  2719. *
  2720. * See http://sozi.baierouge.fr/wiki/en:license for details.
  2721. */
  2722. #sozi-toc text {
  2723. fill: #eff;
  2724. font-family: Verdana, sans-serif;
  2725. font-size: 12pt;
  2726. }
  2727. #sozi-toc text:hover {
  2728. fill: #0cf;
  2729. cursor: pointer;
  2730. }
  2731. #sozi-toc text.sozi-toc-current {
  2732. fill: #fa4;
  2733. }
  2734. #sozi-toc-background {
  2735. stroke: #222;
  2736. stroke-opacity: 0.1;
  2737. stroke-width: 10;
  2738. fill: #222;
  2739. fill-opacity: 0.9;
  2740. }
  2741. .sozi-toc-arrow {
  2742. fill: #eff;
  2743. fill-opacity: 0.75;
  2744. stroke: none;
  2745. }
  2746. .sozi-toc-arrow:hover {
  2747. fill: #0cf;
  2748. }
  2749. #sozi-framenumber circle {
  2750. stroke: #222;
  2751. stroke-opacity: 0.1;
  2752. stroke-width: 4;
  2753. fill: #222;
  2754. fill-opacity: 0.9;
  2755. }
  2756. #sozi-framenumber text {
  2757. fill: #eff;
  2758. font-family: Verdana, sans-serif;
  2759. font-size: 12pt;
  2760. }
  2761. </style>
  2762. </svg>