| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112 |
- <?xml version="1.0" encoding="UTF-8" standalone="no"?>
- <svg
- xmlns:ns1="http://sozi.baierouge.fr"
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- viewBox="0 0 399.99999 299.99999"
- sodipodi:docname="dicetower.svg"
- inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
- version="1.1"
- id="svg3962"
- height="300mm"
- width="400mm">
- <sodipodi:namedview
- inkscape:document-rotation="0"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox="true"
- inkscape:snap-nodes="false"
- inkscape:guide-bbox="true"
- showguides="true"
- inkscape:object-paths="false"
- inkscape:object-nodes="true"
- inkscape:window-maximized="1"
- inkscape:window-y="-9"
- inkscape:window-x="-9"
- inkscape:window-height="1001"
- inkscape:window-width="1920"
- units="mm"
- showgrid="false"
- inkscape:current-layer="layer1"
- inkscape:document-units="mm"
- inkscape:cy="310.67374"
- inkscape:cx="118.39732"
- inkscape:zoom="1.2319838"
- inkscape:pageshadow="2"
- inkscape:pageopacity="0.0"
- borderopacity="1.0"
- bordercolor="#666666"
- pagecolor="#ffffff"
- id="base"
- inkscape:snap-smooth-nodes="true">
- <sodipodi:guide
- id="guide3374"
- orientation="0,1"
- position="209.26113,52.46408" />
- <sodipodi:guide
- id="guide3376"
- orientation="0,1"
- position="283.63939,72.804365" />
- </sodipodi:namedview>
- <defs
- id="defs3964" />
- <metadata
- id="metadata3967">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- style="display:inline"
- inkscape:label="Work"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,23.346473)">
- <path
- inkscape:connector-curvature="0"
- id="rect3340"
- 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"
- 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" />
- <rect
- y="-11.163192"
- x="266.39639"
- height="113.27361"
- width="60.000004"
- id="rect3342"
- 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" />
- <rect
- 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"
- id="rect3378"
- width="65.999763"
- height="145.00002"
- x="5.8258758"
- y="-11.163196" />
- <path
- inkscape:connector-curvature="0"
- id="rect3362-0"
- 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"
- 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"
- sodipodi:nodetypes="cccccccccccccccc" />
- <path
- inkscape:connector-curvature="0"
- id="rect3346-3"
- 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"
- 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"
- sodipodi:nodetypes="cccccccccccccccc" />
- <path
- inkscape:connector-curvature="0"
- id="rect3440-6"
- 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"
- 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"
- sodipodi:nodetypes="cccccccccccccccc" />
- <path
- 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"
- 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"
- id="path3797"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccc" />
- <path
- 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"
- 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"
- id="path3807"
- inkscape:connector-curvature="0" />
- <g
- id="g154">
- <g
- transform="matrix(1,0,0,-1.4999995,-2.8535004,28.759089)"
- id="g56">
- <rect
- style="opacity:0.65;fill:#ff00ff;stroke-width:9.75807;stop-color:#000000"
- id="rect52"
- width="3"
- height="5"
- x="74.679138"
- y="6.2815266" />
- <rect
- y="1.2815266"
- x="77.679138"
- height="10"
- width="3"
- id="rect54"
- style="opacity:0.65;fill:#ff00ff;stroke-width:13.8;stop-color:#000000" />
- </g>
- <rect
- transform="scale(-1,1)"
- y="-11.163196"
- x="-77.825638"
- height="23"
- width="6.0000038"
- id="rect96"
- style="opacity:0.65;fill:#ff00ff;stroke-width:29.5978;stop-color:#000000" />
- <g
- id="g104"
- transform="matrix(1,0,0,-1.4999995,-2.8534927,71.759112)">
- <rect
- y="6.2815266"
- x="74.679138"
- height="5"
- width="3"
- id="rect100"
- style="opacity:0.65;fill:#ff00ff;stroke-width:9.75807;stop-color:#000000" />
- <rect
- style="opacity:0.65;fill:#ff00ff;stroke-width:13.8;stop-color:#000000"
- id="rect102"
- width="3"
- height="10"
- x="77.679138"
- y="1.2815266" />
- </g>
- <g
- transform="matrix(1,0,0,-1.4999995,-2.8534927,112.75911)"
- id="g110">
- <rect
- style="opacity:0.65;fill:#ff00ff;stroke-width:9.75807;stop-color:#000000"
- id="rect106"
- width="3"
- height="5"
- x="74.679138"
- y="6.2815266" />
- <rect
- y="1.2815266"
- x="77.679138"
- height="10"
- width="3"
- id="rect108"
- style="opacity:0.65;fill:#ff00ff;stroke-width:13.8;stop-color:#000000" />
- </g>
- <rect
- style="opacity:0.65;fill:#ff00ff;stroke-width:27.6002;stop-color:#000000"
- id="rect114"
- width="6.0000076"
- height="20.000029"
- x="-77.825645"
- y="34.8368"
- transform="scale(-1,1)" />
- <rect
- transform="scale(-1,1)"
- y="77.836823"
- x="-77.825645"
- height="18"
- width="6"
- id="rect124"
- style="opacity:0.65;fill:#ff00ff;stroke-width:26.1838;stop-color:#000000" />
- <rect
- transform="scale(-1,1)"
- y="118.83682"
- x="-77.825645"
- height="15"
- width="6"
- id="rect126"
- style="opacity:0.65;fill:#ff00ff;stroke-width:23.9024;stop-color:#000000" />
- <rect
- style="opacity:0.65;fill:#00ff00;stroke-width:3.76969;stop-color:#000000"
- id="rect128"
- width="3"
- height="8"
- x="74.825638"
- y="26.8368" />
- <rect
- y="69.836823"
- x="74.825645"
- height="8"
- width="3"
- id="rect130"
- style="opacity:0.65;fill:#00ff00;stroke-width:3.76969;stop-color:#000000" />
- <rect
- style="opacity:0.65;fill:#00ff00;stroke-width:3.76969;stop-color:#000000"
- id="rect132"
- width="3"
- height="8"
- x="74.825645"
- y="110.83682" />
- </g>
- <g
- transform="rotate(180,79.586037,61.336815)"
- id="g188">
- <g
- id="g160"
- transform="matrix(1,0,0,-1.4999995,-2.8535004,28.759089)">
- <rect
- y="6.2815266"
- x="74.679138"
- height="5"
- width="3"
- id="rect156"
- style="opacity:0.65;fill:#ff00ff;stroke-width:9.75807;stop-color:#000000" />
- <rect
- style="opacity:0.65;fill:#ff00ff;stroke-width:13.8;stop-color:#000000"
- id="rect158"
- width="3"
- height="10"
- x="77.679138"
- y="1.2815266" />
- </g>
- <rect
- style="opacity:0.65;fill:#ff00ff;stroke-width:29.5978;stop-color:#000000"
- id="rect162"
- width="6.0000038"
- height="23"
- x="-77.825638"
- y="-11.163196"
- transform="scale(-1,1)" />
- <g
- transform="matrix(1,0,0,-1.4999995,-2.8534927,71.759112)"
- id="g168">
- <rect
- style="opacity:0.65;fill:#ff00ff;stroke-width:9.75807;stop-color:#000000"
- id="rect164"
- width="3"
- height="5"
- x="74.679138"
- y="6.2815266" />
- <rect
- y="1.2815266"
- x="77.679138"
- height="10"
- width="3"
- id="rect166"
- style="opacity:0.65;fill:#ff00ff;stroke-width:13.8;stop-color:#000000" />
- </g>
- <g
- id="g174"
- transform="matrix(1,0,0,-1.4999995,-2.8534927,112.75911)">
- <rect
- y="6.2815266"
- x="74.679138"
- height="5"
- width="3"
- id="rect170"
- style="opacity:0.65;fill:#ff00ff;stroke-width:9.75807;stop-color:#000000" />
- <rect
- style="opacity:0.65;fill:#ff00ff;stroke-width:13.8;stop-color:#000000"
- id="rect172"
- width="3"
- height="10"
- x="77.679138"
- y="1.2815266" />
- </g>
- <rect
- transform="scale(-1,1)"
- y="34.8368"
- x="-77.825645"
- height="20.000029"
- width="6.0000076"
- id="rect176"
- style="opacity:0.65;fill:#ff00ff;stroke-width:27.6002;stop-color:#000000" />
- <rect
- style="opacity:0.65;fill:#ff00ff;stroke-width:26.1838;stop-color:#000000"
- id="rect178"
- width="6"
- height="18"
- x="-77.825645"
- y="77.836823"
- transform="scale(-1,1)" />
- <rect
- style="opacity:0.65;fill:#ff00ff;stroke-width:23.9024;stop-color:#000000"
- id="rect180"
- width="6"
- height="15"
- x="-77.825645"
- y="118.83682"
- transform="scale(-1,1)" />
- <rect
- y="26.8368"
- x="74.825638"
- height="8"
- width="3"
- id="rect182"
- style="opacity:0.65;fill:#00ff00;stroke-width:3.76969;stop-color:#000000" />
- <rect
- style="opacity:0.65;fill:#00ff00;stroke-width:3.76969;stop-color:#000000"
- id="rect184"
- width="3"
- height="8"
- x="74.825645"
- y="69.836823" />
- <rect
- y="110.83682"
- x="74.825645"
- height="8"
- width="3"
- id="rect186"
- style="opacity:0.65;fill:#00ff00;stroke-width:3.76969;stop-color:#000000" />
- </g>
- <path
- transform="matrix(0.26458333,0,0,0.26458333,0,-23.346473)"
- 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 "
- 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"
- id="rect190" />
- </g>
- <script
- id="sozi-script"
- ns1:version="13.11-30213629">/*
- * Sozi - A presentation tool using the SVG standard
- *
- * Copyright (C) 2010-2013 Guillaume Savaton
- *
- * This program is dual licensed under the terms of the MIT license
- * or the GNU General Public License (GPL) version 3.
- * A copy of both licenses is provided in the doc/ folder of the
- * official release of Sozi.
- *
- * See http://sozi.baierouge.fr/wiki/en:license for details.
- */
- /**
- * Create or augment a namespace.
- *
- * <p>A typical use of this function is:</p>
- *
- * <pre>
- * namespace(this, "a.b.c", function (exports, globals) {
- * exports.foo = function (x) {
- * ...
- * };
- * });
- * </pre>
- *
- * <p>where <code>this</code> is the global object.</p>
- *
- * <p>In this example, function <code>foo</code> is exported and can be
- * called as <code>a.b.c.foo(someValue)</code>.</p>
- *
- * @memberOf _global_
- * @param globals The global object
- * @param {String} path The dot-separated path to the namespace
- * @param {Function} body A function to execute in the context of the namespace
- */
- function namespace(globals, path, body) {
- "use strict";
-
- // Start name lookup in the global object
- var current = globals;
-
- // For each name in the given path
- path.split(".").forEach(function (name) {
- // If the current path element does not exist
- // in the current namespace, create a new sub-namespace
- if (typeof current[name] === "undefined") {
- current[name] = {};
- }
-
- // Move to the namespace for the current path element
- current = current[name];
- });
-
- // Execute the given function in the last namespace
- if (body) {
- body(current, globals);
- }
-
- return current;
- }
- /*
- * Sozi - A presentation tool using the SVG standard
- *
- * Copyright (C) 2010-2013 Guillaume Savaton
- *
- * This program is dual licensed under the terms of the MIT license
- * or the GNU General Public License (GPL) version 3.
- * A copy of both licenses is provided in the doc/ folder of the
- * official release of Sozi.
- *
- * See http://sozi.baierouge.fr/wiki/en:license for details.
- */
- /**
- * @name sozi.events
- * @namespace A simple event system for Sozi.
- * @depend namespace.js
- */
- namespace(this, "sozi.events", function (exports) {
- /** @lends sozi.events */
- "use strict";
-
- /**
- * A registry of callback functions for each event type.
- *
- * <p>Call {@link sozi.events.listen} to add a new listener.</p>
- */
- var listenerRegistry = {};
- /**
- * Adds a listener for a given event type.
- *
- * @memberOf sozi.events
- * @name listen
- * @function
- * @param {String} key The identifier of the event type to listen
- * @param {Function} handler The function to call when a corresponding event is fired
- */
- exports.listen = function (key, handler) {
- if (!listenerRegistry.hasOwnProperty(key)) {
- listenerRegistry[key] = [];
- }
- listenerRegistry[key].push(handler);
- };
-
- /**
- * Fire an event of a given type.
- *
- * <p>All event handlers added for the given event type are
- * executed.</p>
- *
- * <p>Additional arguments provided to this function are passed
- * to the event handlers.</p>
- *
- * @memberOf sozi.events
- * @name fire
- * @function
- * @param {String} key The identifier of the event type to fire
- */
- exports.fire = function (key) {
- var args = Array.prototype.slice.call(arguments, 1);
- if (listenerRegistry.hasOwnProperty(key)) {
- listenerRegistry[key].forEach(function (listener) {
- listener.apply(null, args);
- });
- }
- };
- });
- /*
- * Sozi - A presentation tool using the SVG standard
- *
- * Copyright (C) 2010-2013 Guillaume Savaton
- *
- * This program is dual licensed under the terms of the MIT license
- * or the GNU General Public License (GPL) version 3.
- * A copy of both licenses is provided in the doc/ folder of the
- * official release of Sozi.
- *
- * See http://sozi.baierouge.fr/wiki/en:license for details.
- */
- /**
- * @name sozi.proto
- * @namespace Helpers for prototype inheritance.
- * @depend namespace.js
- */
- namespace(this, "sozi.proto", function (exports) {
- "use strict";
-
- exports.Object = {
- installConstructors: function () {
- function InstanceConstructor() {}
- InstanceConstructor.prototype = this;
-
- this.instance = function () {
- var result = new InstanceConstructor();
- result.construct.apply(result, arguments);
- return result;
- };
-
- this.subtype = function (anObject) {
- var result = new InstanceConstructor();
- result.augment(anObject);
- result.installConstructors();
- return result;
- };
- },
-
- construct: function () {},
-
- augment: function (anObject) {
- for (var attr in anObject) {
- if (anObject.hasOwnProperty(attr)) {
- this[attr] = anObject[attr];
- }
- }
- return this;
- },
-
- bind: function (aFunction) {
- var self = this;
- return function () {
- return aFunction.apply(self, arguments);
- }
- }
- };
-
- // Bootstrap the root object
- exports.Object.installConstructors();
- });
- /*
- * Sozi - A presentation tool using the SVG standard
- *
- * Copyright (C) 2010-2013 Guillaume Savaton
- *
- * This program is dual licensed under the terms of the MIT license
- * or the GNU General Public License (GPL) version 3.
- * A copy of both licenses is provided in the doc/ folder of the
- * official release of Sozi.
- *
- * See http://sozi.baierouge.fr/wiki/en:license for details.
- */
- /**
- * @name sozi.actions
- * @namespace Callback functions for DOM event handlers
- * @depend namespace.js
- */
- namespace(this, "sozi.actions", function (exports, window) {
- /** @lends sozi.actions */
-
- "use strict";
-
- // Module aliases
- var player = namespace(window, "sozi.player");
- var display = namespace(window, "sozi.display");
-
- // The global document object
- var document = window.document;
-
- // Constants: mouse button numbers
- var DRAG_BUTTON = 0; // Left button
- var TOC_BUTTON = 1; // Middle button
-
- // Constants: increments for zooming and rotating,
- // threshold for dragging
- var SCALE_FACTOR = 1.05;
- var ROTATE_STEP = 5;
- var DRAG_THRESHOLD_PX = 5;
-
- /**
- * The status of the current drag operation.
- *
- * @type Boolean
- */
- var mouseDragged = false;
-
- /**
- * The X coordinate of the mouse on the latest "down" or "drag" event.
- *
- * @type Number
- */
- var mouseLastX = 0;
- /**
- * The Y coordinate of the mouse on the latest "down" or "drag" event.
- *
- * @type Number
- */
- var mouseLastY = 0;
-
- /**
- * Zooms the display in the given direction.
- *
- * <p>Only the sign of <code>direction</code> is used:</p>
- * <ul>
- * <li>zoom in when <code>direction > 0</code></li>
- * <li>zoom out when <code>direction <= 0</code></li>
- * </ul>
- *
- * <p>The scaling is centered around point (<code>x</code>, <code>y</code>).</p>
- *
- * @param {Number} direction The direction of the scaling operation
- * @param {Number} x The X coordinate of the scaling center
- * @param {Number} y The Y coordinate of the scaling center
- */
- function zoom(direction, x, y) {
- player.stop();
- display.viewPorts["player"].zoom(direction > 0 ? SCALE_FACTOR : 1 / SCALE_FACTOR, x, y);
- }
-
- /**
- * Rotate the display in the given direction.
- *
- * <p>Only the sign of <code>direction</code> is used:</p>
- * <ul>
- * <li>rotate anticlockwise when direction > 0</li>
- * <li>rotate clockwise when direction <= 0</li>
- * </ul>
- *
- * @param {Number} direction The direction of the rotation
- */
- function rotate(direction) {
- player.stop();
- display.viewPorts["player"].rotate(direction > 0 ? ROTATE_STEP : -ROTATE_STEP);
- }
-
- /**
- * Show/hide the frame list.
- *
- * <p>The presentation stops when the frame list is showed,
- * and restarts when the frame list is hidden.</p>
- */
- function toggleFrameList() {
- if (sozi.framelist.isVisible()) {
- sozi.framelist.hide();
- player.restart();
- } else {
- player.stop();
- sozi.framelist.show();
- }
- }
- function isPlayerEvent(evt) {
- return display.viewPorts["player"].contains(evt.clientX, evt.clientY);
- }
-
- /**
- * Event handler: mouse down.
- *
- * <p>When the left button is pressed, we register the current coordinates
- * in case the mouse will be dragged. Handler {@link sozi.actions-onMouseDrag} is set until
- * the button is released ({@link sozi.actions-onMouseUp}).</p>
- *
- * <p>When the middle button is pressed, the table of contents is shown or hidden.</p>
- *
- * @param {Event} evt The DOM event object
- */
- function onMouseDown(evt) {
- if (!isPlayerEvent(evt)) {
- return;
- }
- if (evt.button === DRAG_BUTTON) {
- document.documentElement.addEventListener("mousemove", onMouseDrag, false);
- mouseDragged = false;
- mouseLastX = evt.clientX;
- mouseLastY = evt.clientY;
- } else if (evt.button === TOC_BUTTON) {
- toggleFrameList();
- }
- evt.stopPropagation();
- evt.preventDefault();
- }
- /**
- * Event handler: mouse move.
- *
- * <p>If the left mouse button is down, then the mouse move is a drag action.
- * This method computes the displacement since the button was pressed or
- * since the last move, and updates the reference coordinates for the next move.</p>
- *
- * @param {Event} evt The DOM event object
- */
- function onMouseDrag(evt) {
- if (!isPlayerEvent(evt)) {
- return;
- }
- player.stop();
-
- // The drag action is confirmed when one of the mouse coordinates
- // has moved past the threshold
- if (!mouseDragged && (Math.abs(evt.clientX - mouseLastX) > DRAG_THRESHOLD_PX ||
- Math.abs(evt.clientY - mouseLastY) > DRAG_THRESHOLD_PX)) {
- mouseDragged = true;
- }
-
- if (mouseDragged) {
- sozi.events.fire("sozi.player.cleanup");
- display.viewPorts["player"].drag(evt.clientX - mouseLastX, evt.clientY - mouseLastY);
- mouseLastX = evt.clientX;
- mouseLastY = evt.clientY;
- }
-
- evt.stopPropagation();
- }
- /**
- * Event handler: mouse up.
- *
- * <p>Releasing the left button removes the {@link sozi.actions-onMouseDrag} handler.</p>
- *
- * @param {Event} evt The DOM event object
- */
- function onMouseUp(evt) {
- if (!isPlayerEvent(evt)) {
- return;
- }
- if (evt.button === DRAG_BUTTON) {
- document.documentElement.removeEventListener("mousemove", onMouseDrag, false);
- }
- evt.stopPropagation();
- evt.preventDefault();
- }
- /**
- * Event handler: context menu (i.e right click).
- *
- * <p>Right click goes one frame back.</p>
- *
- * <p>There is no "click" event for the right mouse button and the menu
- * can't be disabled in {@link sozi.actions-onMouseDown}.</p>
- *
- * @param {Event} evt The DOM event object
- */
- function onContextMenu(evt) {
- if (!isPlayerEvent(evt)) {
- return;
- }
- player.moveToPrevious();
- evt.stopPropagation();
- evt.preventDefault();
- }
- /**
- * Event handler: mouse click.
- *
- * <p>Left-click moves the presentation to the next frame.</p>
- *
- * <p>No "click" event is generated for the middle button in Firefox.
- * See {@link sozi.actions-onMouseDown} for middle click handling.</p>
- *
- * <p>Dragging the mouse produces a "click" event when the button is released.
- * If flag {@link sozi.actions-mouseDragged} was set by {@link sozi.actions-onMouseDrag},
- * then the click event is the result of a drag action.</p>
- *
- * @param {Event} evt The DOM event object
- */
- function onClick(evt) {
- if (!isPlayerEvent(evt)) {
- return;
- }
- if (!mouseDragged && evt.button !== TOC_BUTTON) {
- player.moveToNext();
- }
- evt.stopPropagation();
- evt.preventDefault();
- }
- /**
- * Event handler: mouse wheel.
- *
- * <p>Rolling the mouse wheel stops the presentation and zooms the current display.</p>
- *
- * FIXME shift key does not work in Opera
- *
- * @param {Event} evt The DOM event object
- */
- function onWheel(evt) {
- if (!isPlayerEvent(evt)) {
- return;
- }
-
- if (!evt) {
- evt = window.event;
- }
- var delta = 0;
- if (evt.wheelDelta) { // IE and Opera
- delta = evt.wheelDelta;
- }
- else if (evt.detail) { // Mozilla
- delta = -evt.detail;
- }
-
- if (delta !== 0) {
- if (evt.shiftKey) {
- rotate(delta);
- }
- else {
- zoom(delta, evt.clientX, evt.clientY);
- }
- }
-
- evt.stopPropagation();
- evt.preventDefault();
- }
- /**
- * Event handler: key press.
- *
- * <p>Keyboard handling is split into two methods:
- * {@link sozi.actions-onKeyPress} and {@link sozi.actions-onKeyDown}
- * in order to get the same behavior across browsers.</p>
- *
- * <p>This method handles character keys "+", "-", "=", "F" and "T".</p>
- *
- * @param {Event} evt The DOM event object
- */
- function onKeyPress(evt) {
- // Keys with modifiers are ignored
- if (evt.altKey || evt.ctrlKey || evt.metaKey) {
- return;
- }
- switch (evt.charCode || evt.which) {
- case 43: // +
- zoom(1, window.innerWidth / 2, window.innerHeight / 2);
- break;
- case 45: // -
- zoom(-1, window.innerWidth / 2, window.innerHeight / 2);
- break;
- case 61: // =
- player.moveToCurrent();
- break;
- case 70: // F
- case 102: // f
- player.showAll();
- break;
- case 84: // T
- case 116: // t
- toggleFrameList();
- break;
- case 82: // R
- rotate(-1);
- break;
- case 114: // r
- rotate(1);
- break;
- default:
- return;
- }
- evt.stopPropagation();
- evt.preventDefault();
- }
- /**
- * Event handler: key down.
- *
- * <p>Keyboard handling is split into two methods:
- * {@link sozi.actions-onKeyPress} and {@link sozi.actions-onKeyDown}
- * in order to get the same behavior across browsers.</p>
- *
- * <p>This method handles navigation keys (arrows, page up/down, home, end)
- * and the space and enter keys.</p>
- *
- * @param {Event} evt The DOM event object
- */
- function onKeyDown(evt) {
- // Keys with Alt/Ctrl/Meta modifiers are ignored
- if (evt.altKey || evt.ctrlKey || evt.metaKey) {
- return;
- }
- switch (evt.keyCode) {
- case 36: // Home
- if (evt.shiftKey) {
- player.jumpToFirst();
- }
- else {
- player.moveToFirst();
- }
- break;
- case 35: // End
- if (evt.shiftKey) {
- player.jumpToLast();
- }
- else {
- player.moveToLast();
- }
- break;
- case 38: // Arrow up
- case 33: // Page up
- case 37: // Arrow left
- if (evt.shiftKey) {
- player.jumpToPrevious();
- }
- else {
- player.moveToPrevious();
- }
- break;
- case 40: // Arrow down
- case 34: // Page down
- case 39: // Arrow right
- case 13: // Enter
- case 32: // Space
- if (evt.shiftKey) {
- player.jumpToNext();
- }
- else {
- player.moveToNext();
- }
- break;
- default:
- // Ignore other keys and propagate the event
- return;
- }
-
- // Stop event propagation for supported keys
- evt.stopPropagation();
-
- // In some versions of Chrome/Chromium, preventDefault() inhibits the "keypress" event
- evt.preventDefault();
- }
- /**
- * Dummy event handler: stop event propagation.
- *
- * @param {Event} evt The DOM event object
- */
- function stopEvent(evt) {
- evt.stopPropagation();
- }
- /**
- * Event handler: document load.
- *
- * <p>This function sets up all other event handlers for the player.</p>
- */
- function onDisplayReady() {
- // Prevent event propagation when clicking on a link
- // FIXME does not work in Firefox when the <a> is referenced through a <use>
- var links = document.getElementsByTagName("a");
- for (var i = 0; i < links.length; i += 1) {
- links[i].addEventListener("click", stopEvent, false);
- links[i].addEventListener("contextmenu", stopEvent, false);
- }
-
- // Mouse events are constrained to the player viewport
- // see isPlayerEvent()
- // TODO also use shift-click as an alternative for middle-click
- var svgRoot = document.documentElement;
- svgRoot.addEventListener("click", onClick, false);
- svgRoot.addEventListener("mousedown", onMouseDown, false);
- svgRoot.addEventListener("mouseup", onMouseUp, false);
- svgRoot.addEventListener("contextmenu", onContextMenu, false);
- svgRoot.addEventListener("DOMMouseScroll", onWheel, false); // Mozilla
- window.onmousewheel = onWheel;
- // Keyboard events are global to the SVG document
- svgRoot.addEventListener("keypress", onKeyPress, false);
- svgRoot.addEventListener("keydown", onKeyDown, false);
- }
- sozi.events.listen("sozi.display.ready", onDisplayReady); // @depend events.js
- });
- /*
- * Sozi - A presentation tool using the SVG standard
- *
- * Copyright (C) 2010-2013 Guillaume Savaton
- *
- * This program is dual licensed under the terms of the MIT license
- * or the GNU General Public License (GPL) version 3.
- * A copy of both licenses is provided in the doc/ folder of the
- * official release of Sozi.
- *
- * See http://sozi.baierouge.fr/wiki/en:license for details.
- */
- /**
- * @name sozi.animation
- * @namespace A general-purpose animation controller.
- * @depend namespace.js
- */
- namespace(this, "sozi.animation", function (exports, window) {
- /** @lends sozi.animation */
-
- "use strict";
-
- /**
- * The browser-specific function to request an animation frame.
- *
- * @function
- */
- var requestAnimationFrame =
- window.mozRequestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.msRequestAnimationFrame ||
- window.oRequestAnimationFrame;
- var getCurrentTime = function () {
- return window.performance && window.performance.now ?
- window.performance.now() :
- Date.now();
- };
- exports.setAnimationFrameHandlers = function (requestAnimationFrameFunction, getCurrentTimeFunction) {
- requestAnimationFrame = requestAnimationFrameFunction;
- getCurrentTime = getCurrentTimeFunction;
- };
- /**
- * The default time step.
- *
- * <p>For browsers that do not support animation frames.</p>
- *
- * @constant
- * @type Number
- */
- var TIME_STEP_MS = 40;
-
- /**
- * The handle provided by <code>setInterval()</code>.
- *
- * <p>For browsers that do not support animation frames.</p>
- */
- var timer;
-
- /**
- * The list of running animators.
- *
- * @type Array
- */
- var animatorList = [];
-
- /**
- * The main animation loop.
- *
- * <p>This function is called periodically and triggers the
- * animation steps in all running animators.</p>
- *
- * <p>If all animators are removed from the list of running animators,
- * then the periodic calling is disabled.</p>
- *
- * <p>This function can be called either through {@link sozi.animation-requestAnimationFrame}
- * if the browser supports it, or through <code>setInterval()</code>.</p>
- */
- function loop() {
- if (animatorList.length > 0) {
- // If there is at least one animator,
- // and if the browser provides animation frames,
- // schedule this function to be called again in the next frame.
- if (requestAnimationFrame) {
- requestAnimationFrame(loop);
- }
- // Step all animators
- animatorList.forEach(function (animator) {
- // TODO use timestamp argument:
- // browser compatibility issue with Date.now()
- // and performance.now() timestamps.
- animator.step(getCurrentTime());
- });
- }
- else {
- // If all animators have been removed,
- // and if this function is called periodically
- // through setInterval, disable the periodic calling.
- if (!requestAnimationFrame) {
- window.clearInterval(timer);
- }
- }
- }
-
- /**
- * Start the animation loop.
- *
- * <p>This function delegates the periodic update of all animators
- * to the {@link sozi.animation-loop} function, either through {@link sozi.animation-requestAnimationFrame}
- * if the browser supports it, or through <code>setInterval()</code>.</p>
- */
- function start() {
- if (requestAnimationFrame) {
- requestAnimationFrame(loop);
- }
- else {
- timer = window.setInterval(function () {
- loop(getCurrentTime());
- }, TIME_STEP_MS);
- }
- }
-
- /**
- * Add a new animator object to the list of running animators.
- *
- * <p>If the animator list was empty before calling this function,
- * then the animation loop is started.</p>
- *
- * @param {sozi.animation.Animator} animator The animator object to add.
- */
- function addAnimator(animator) {
- animatorList.push(animator);
- if (animatorList.length === 1) {
- start();
- }
- }
-
- /**
- * Remove the given animator from the list of running animators.
- *
- * @param {sozi.animation.Animator} animator The animator object to add.
- */
- function removeAnimator(animator) {
- animatorList.splice(animatorList.indexOf(animator), 1);
- }
-
- /**
- * @class
- *
- * An animator provides the logic for animating other objects.
- *
- * <p>The main purpose of an animator is to schedule the update
- * operations in the animated objects.</p>
- *
- * @memberOf sozi.animation
- * @name Animator
- * @depend proto.js
- */
- exports.Animator = sozi.proto.Object.subtype({
- /** @lends sozi.animation.Animator */
-
- /**
- * Construct a new animator.
- */
- construct: function () {
- /**
- * The animation duration, in milliseconds.
- * @type Number
- */
- this.durationMs = 0;
-
- /**
- * A "payload" object that can be used by {@link sozi.animation.Animator.onStep}
- * and {@link sozi.animation.Animator.onDone}.
- */
- this.data = null;
-
- /**
- * The start time of the animation.
- * @type Number
- */
- this.initialTime = 0;
-
- /**
- * The current state of this animator.
- * @type Boolean
- */
- this.started = false;
- },
- /**
- * Start the current animator.
- *
- * <p>The current animator is added to the list of running animators
- * and is put in the "started" state.
- * It will be removed from the list automatically when the given duration
- * has elapsed.</p>
- *
- * <p>Method {@link sozi.animation.Animator.onStep} is called once before starting the animation.</p>
- *
- * @param {Number} durationMs The animation duration, in milliseconds
- * @param data Some data that can be used in {@link sozi.animation.Animator.onStep}
- * and {@link sozi.animation.Animator.onDone}
- */
- start: function (durationMs, data) {
- this.durationMs = durationMs;
- this.data = data;
- this.initialTime = getCurrentTime();
- this.onStep(0);
- if (!this.started) {
- this.started = true;
- addAnimator(this);
- }
- },
- /**
- * Stop the current animator.
- *
- * <p>The current animator is removed from the list of running animators
- * and is put in the "stopped" state.</p>
- */
- stop: function () {
- if (this.started) {
- removeAnimator(this);
- this.started = false;
- }
- },
- /**
- * Perform one animation step.
- *
- * <p>This function is called automatically by the {@link sozi.animation-loop} function.
- * It calls {@link sozi.animation.Animator.onStep}.
- * If the animation duration has elapsed, {@link sozi.animation.Animator.onDone} is called.</p>
- *
- * @param {Number} currentTime The current time
- */
- step: function (currentTime) {
- var elapsedTime = currentTime - this.initialTime;
- if (elapsedTime >= this.durationMs) {
- this.stop();
- this.onStep(1);
- this.onDone();
- } else {
- this.onStep(elapsedTime / this.durationMs);
- }
- },
-
- /**
- * This method is called automatically on each animation step.
- *
- * <p>The default implementation does nothing. Override it in a
- * subclass or instance to provide your own implementation.<p>
- *
- * @param {Number} progress The elapsed fraction of the total duration (comprised between 0 and 1 included).
- */
- onStep: function (progress) {
- // Do nothing
- },
-
- /**
- * This method is called automatically when the animation ends.
- *
- * <p>The default implementation does nothing. Override it in a
- * subclass or instance to provide your own implementation.<p>
- */
- onDone: function () {
- // Do nothing
- }
- });
- /*
- * The acceleration profiles.
- *
- * Each profile is a function that operates in the interval [0, 1]
- * and produces a result in the same interval.
- *
- * These functions are meant to be called in {@link sozi.animation.Animator.onStep}
- * to transform the progress indicator according to the desired
- * acceleration effect.
- */
- exports.profiles = {
- "linear": function (x) {
- return x;
- },
- "accelerate": function (x) {
- return Math.pow(x, 3);
- },
- "strong-accelerate": function (x) {
- return Math.pow(x, 5);
- },
- "decelerate": function (x) {
- return 1 - Math.pow(1 - x, 3);
- },
- "strong-decelerate": function (x) {
- return 1 - Math.pow(1 - x, 5);
- },
- "accelerate-decelerate": function (x) {
- var xs = x <= 0.5 ? x : 1 - x,
- y = Math.pow(2 * xs, 3) / 2;
- return x <= 0.5 ? y : 1 - y;
- },
- "strong-accelerate-decelerate": function (x) {
- var xs = x <= 0.5 ? x : 1 - x,
- y = Math.pow(2 * xs, 5) / 2;
- return x <= 0.5 ? y : 1 - y;
- },
- "decelerate-accelerate": function (x) {
- var xs = x <= 0.5 ? x : 1 - x,
- y = (1 - Math.pow(1 - 2 * xs, 2)) / 2;
- return x <= 0.5 ? y : 1 - y;
- },
- "strong-decelerate-accelerate": function (x) {
- var xs = x <= 0.5 ? x : 1 - x,
- y = (1 - Math.pow(1 - 2 * xs, 3)) / 2;
- return x <= 0.5 ? y : 1 - y;
- },
-
- "immediate-beginning": function (x) {
- return 1;
- },
-
- "immediate-end": function (x) {
- return x === 1 ? 1 : 0;
- },
-
- "immediate-middle": function (x) {
- return x >= 0.5 ? 1 : 0;
- }
- };
- });
- /*
- * Sozi - A presentation tool using the SVG standard
- *
- * Copyright (C) 2010-2013 Guillaume Savaton
- *
- * This program is dual licensed under the terms of the MIT license
- * or the GNU General Public License (GPL) version 3.
- * A copy of both licenses is provided in the doc/ folder of the
- * official release of Sozi.
- *
- * See http://sozi.baierouge.fr/wiki/en:license for details.
- */
- /**
- * @name sozi.display
- * @namespace Display management.
- * @depend namespace.js
- */
- namespace(this, "sozi.display", function (exports, window) {
- "use strict";
-
- // Constant: the Sozi namespace
- var SVG_NS = "http://www.w3.org/2000/svg";
- var XLINK_NS = "http://www.w3.org/1999/xlink";
-
- // The global document object
- var document = window.document;
-
- // The initial bounding box of the whole document,
- // assigned in onDocumentReady()
- var initialBBox;
-
- var lastWindowWidth;
- var lastWindowHeight;
-
- exports.viewPorts = {};
-
- var primaryViewport;
- /**
- * @depend proto.js
- */
- exports.CameraState = sozi.proto.Object.subtype({
- construct : function () {
- // Center coordinates
- this.cx = this.cy = 0;
-
- // Dimensions
- this.width = this.height = 1;
-
- // Rotation angle, in degrees
- this.angle = 0;
-
- // Clipping
- this.clipped = true;
-
- // Transition zoom
- this.transitionZoomPercent = 0;
-
- // Transition profile
- this.transitionProfile = sozi.animation.profiles.linear;
-
- // Transition path
- this.transitionPath = null;
- },
- setCenter: function (cx, cy) {
- this.cx = cx;
- this.cy = cy;
- return this;
- },
-
- setSize: function (width, height) {
- this.width = width;
- this.height = height;
- return this;
- },
-
- setClipped: function (clipped) {
- this.clipped = clipped;
- return this;
- },
-
- /*
- * Set the angle of the current camera state.
- * The angle of the current state is normalized
- * in the interval [-180 ; 180]
- */
- setAngle: function (angle) {
- this.angle = (angle + 180) % 360 - 180;
- return this;
- },
-
- setRawAngle: function (angle) {
- this.angle = angle;
- return this;
- },
-
- setTransitionZoomPercent: function (zoomPercent) {
- this.transitionZoomPercent = zoomPercent;
- return this;
- },
-
- setTransitionProfile: function (profile) {
- this.transitionProfile = profile;
- return this;
- },
-
- setTransitionPath: function (svgPath) {
- this.transitionPath = svgPath;
- return this;
- },
-
- /*
- * Set the current camera's properties to the given SVG element.
- *
- * If the element is a rectangle, the properties of the frames are based
- * on the geometrical properties of the rectangle.
- * Otherwise, the properties of the frame are based on the bounding box
- * of the given element.
- *
- * Parameters:
- * - svgElement: an element from the SVG DOM
- */
- setAtElement: function (svgElement) {
- // Read the raw bounding box of the given SVG element
- var x, y, w, h;
- if (svgElement.nodeName === "rect") {
- x = svgElement.x.baseVal.value;
- y = svgElement.y.baseVal.value;
- w = svgElement.width.baseVal.value;
- h = svgElement.height.baseVal.value;
- } else {
- var b = svgElement.getBBox();
- x = b.x;
- y = b.y;
- w = b.width;
- h = b.height;
- }
- // Compute the raw coordinates of the center
- // of the given SVG element
- var c = document.documentElement.createSVGPoint();
- c.x = x + w / 2;
- c.y = y + h / 2;
-
- // Compute the coordinates of the center of the given SVG element
- // after its current transformation
- var matrix = svgElement.getCTM();
- c = c.matrixTransform(matrix);
- // Compute the scaling factor applied to the given SVG element
- var scale = Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b);
-
- // Update the camera to match the bounding box information of the
- // given SVG element after its current transformation
- return this.setCenter(c.x, c.y)
- .setSize(w * scale, h * scale)
- .setAngle(Math.atan2(matrix.b, matrix.a) * 180 / Math.PI);
- },
- setAtState: function (other) {
- return this.setCenter(other.cx, other.cy)
- .setSize(other.width, other.height)
- .setAngle(other.angle)
- .setClipped(other.clipped)
- .setTransitionZoomPercent(other.transitionZoomPercent)
- .setTransitionProfile(other.transitionProfile)
- .setTransitionPath(other.transitionPath);
- },
-
- interpolatableAttributes: ["width", "height", "angle"],
-
- interpolate: function (initialState, finalState, ratio, useTransitionPath, reverseTransitionPath) {
- var remaining = 1 - ratio;
- for (var i = 0; i < this.interpolatableAttributes.length; i += 1) {
- var attr = this.interpolatableAttributes[i];
- this[attr] = finalState[attr] * ratio + initialState[attr] * remaining;
- }
- var svgPath = reverseTransitionPath ? initialState.transitionPath : finalState.transitionPath;
- if (useTransitionPath && svgPath) {
- var pathLength = svgPath.getTotalLength();
-
- if (reverseTransitionPath) {
- var startPoint = svgPath.getPointAtLength(pathLength);
- var endPoint = svgPath.getPointAtLength(0);
- var currentPoint = svgPath.getPointAtLength(pathLength * remaining);
- }
- else {
- var startPoint = svgPath.getPointAtLength(0);
- var endPoint = svgPath.getPointAtLength(pathLength);
- var currentPoint = svgPath.getPointAtLength(pathLength * ratio);
- }
-
- this.cx = currentPoint.x + (finalState.cx - endPoint.x) * ratio + (initialState.cx - startPoint.x) * remaining;
- this.cy = currentPoint.y + (finalState.cy - endPoint.y) * ratio + (initialState.cy - startPoint.y) * remaining;
- }
- else {
- this.cx = finalState.cx * ratio + initialState.cx * remaining;
- this.cy = finalState.cy * ratio + initialState.cy * remaining;
- }
- }
- });
-
- exports.Camera = exports.CameraState.subtype({
- construct: function (viewPort, idLayer) {
- exports.CameraState.construct.call(this);
-
- this.viewPort = viewPort;
-
- // Clipping rectangle
- this.svgClipRect = document.createElementNS(SVG_NS, "rect");
-
- // Clipping path
- var svgClipPath = document.createElementNS(SVG_NS, "clipPath");
- svgClipPath.setAttribute("id", "sozi-clip-path-" + viewPort.id + "-" + idLayer);
- svgClipPath.appendChild(this.svgClipRect);
- viewPort.svgGroup.appendChild(svgClipPath);
- // The group that will support the clipping operation
- var svgClippedGroup = document.createElementNS(SVG_NS, "g");
- svgClippedGroup.setAttribute("clip-path", "url(#sozi-clip-path-" + viewPort.id + "-" + idLayer + ")");
- viewPort.svgGroup.appendChild(svgClippedGroup);
-
- if (viewPort.isPrimary) {
- // This group will support transformations
- // we keep the layer group clean since it can be referenced
- // from <use> elements
- this.svgLayer = document.createElementNS(SVG_NS, "g");
- this.svgLayer.appendChild(document.getElementById(idLayer));
- }
- else {
- // A <use> element referencing the target layer
- this.svgLayer = document.createElementNS(SVG_NS, "use");
- this.svgLayer.setAttributeNS(XLINK_NS, "href", "#" + idLayer);
- }
- svgClippedGroup.appendChild(this.svgLayer);
- },
-
- setAtState: function (other) {
- return exports.CameraState.setAtState.call(this, other).update();
- },
-
- getScale: function () {
- return Math.min(this.viewPort.width / this.width, this.viewPort.height / this.height);
- },
-
- rotate: function (angle) {
- return this.setAngle(this.angle + angle).update();
- },
- zoom: function (factor, x, y) {
- return this.setSize(this.width / factor, this.height / factor)
- .drag(
- (1 - factor) * (x - this.viewPort.width / 2),
- (1 - factor) * (y - this.viewPort.height / 2)
- );
- },
-
- drag: function (deltaX, deltaY) {
- var scale = this.getScale();
- var angleRad = this.angle * Math.PI / 180;
- var si = Math.sin(angleRad);
- var co = Math.cos(angleRad);
- return this.setCenter(
- this.cx - (deltaX * co - deltaY * si) / scale,
- this.cy - (deltaX * si + deltaY * co) / scale
- ).setClipped(false).update();
- },
- update: function () {
- var scale = this.getScale();
-
- // Compute the size and location of the frame on the screen
- var width = this.width * scale;
- var height = this.height * scale;
- var x = (this.viewPort.width - width) / 2;
- var y = (this.viewPort.height - height) / 2;
- // Adjust the location and size of the clipping rectangle and the frame rectangle
- this.svgClipRect.setAttribute("x", this.clipped ? x : 0);
- this.svgClipRect.setAttribute("y", this.clipped ? y : 0);
- this.svgClipRect.setAttribute("width", this.clipped ? width : this.viewPort.width);
- this.svgClipRect.setAttribute("height", this.clipped ? height : this.viewPort.height);
-
- // Compute and apply the geometrical transformation to the layer group
- var translateX = -this.cx + this.width / 2 + x / scale;
- var translateY = -this.cy + this.height / 2 + y / scale;
- this.svgLayer.setAttribute("transform",
- "scale(" + scale + ")" +
- "translate(" + translateX + "," + translateY + ")" +
- "rotate(" + (-this.angle) + ',' + this.cx + "," + this.cy + ")"
- );
-
- return this;
- }
- });
-
- /**
- * @depend proto.js
- */
- exports.ViewPort = sozi.proto.Object.subtype({
- construct: function (id, idLayerList, primary) {
- this.id = id;
- exports.viewPorts[id] = this;
-
- this.isPrimary = !!primary;
-
- if (this.isPrimary) {
- if (primaryViewport) {
- throw "Failed to create a primary viewport. A primary viewport already exists.";
- }
- else {
- primaryViewport = this;
- }
- }
-
- // TODO add a clip path for the viewport
- this.svgGroup = document.createElementNS(SVG_NS, "g");
- this.svgGroup.setAttribute("class", "sozi-viewport");
- this.svgGroup.setAttribute("id", "sozi-viewport-" + id);
- document.documentElement.appendChild(this.svgGroup);
-
- this.setLocation(0, 0).setSize(window.innerWidth, window.innerHeight);
-
- // Create a camera for each layer
- this.cameras = {};
- idLayerList.forEach(function (idLayer) {
- this.cameras[idLayer] = exports.Camera.instance(this, idLayer);
- }, this);
- },
-
- setSize: function (width, height) {
- this.width = width;
- this.height = height;
- return this;
- },
-
- setLocation: function (x, y) {
- this.x = x;
- this.y = y;
- return this;
- },
- contains: function (x, y) {
- return x >= this.x && x < this.x + this.width &&
- y >= this.y && y < this.y + this.height;
- },
-
- /*
- * Returns the geometrical properties of the SVG document
- *
- * Returns:
- * - The default size, translation and rotation for the document's bounding box
- */
- getDocumentState: function () {
- // This object defines the bounding box of the whole document
- var camera = exports.CameraState.instance()
- .setCenter(initialBBox.x + initialBBox.width / 2,
- initialBBox.y + initialBBox.height / 2)
- .setSize(initialBBox.width, initialBBox.height)
- .setClipped(false);
-
- // Copy the document's bounding box to all layers
- var result = {};
- for (var idLayer in this.cameras) {
- result[idLayer] = camera;
- }
- return result;
- },
- /*
- * Apply geometrical transformations to the image according to the current
- * geometrical attributes of this Display.
- *
- * This method is called automatically when the window is resized.
- */
- update: function () {
- this.svgGroup.setAttribute("transform", "translate(" + this.x + "," + this.y + ")");
- for (var idLayer in this.cameras) {
- this.cameras[idLayer].update();
- }
- return this;
- },
- /*
- * Transform the SVG document to show the given frame.
- *
- * Parameters:
- * - frame: the frame to show
- */
- showFrame: function (frame) {
- for (var idLayer in frame.states) {
- this.cameras[idLayer].setAtState(frame.states[idLayer]);
- }
- return this;
- },
- /*
- * Apply an additional translation to the SVG document based on onscreen coordinates.
- *
- * Parameters:
- * - deltaX: the horizontal displacement, in pixels
- * - deltaY: the vertical displacement, in pixels
- */
- drag: function (deltaX, deltaY) {
- for (var idLayer in this.cameras) {
- this.cameras[idLayer].drag(deltaX, deltaY);
- }
- return this;
- },
- /*
- * Zooms the display with the given factor.
- *
- * The zoom is centered around (x, y) with respect to the center of the display area.
- */
- zoom: function (factor, x, y) {
- for (var idLayer in this.cameras) {
- this.cameras[idLayer].zoom(factor, x, y);
- }
- return this;
- },
- /*
- * Rotate the display with the given angle.
- *
- * The rotation is centered around the center of the display area.
- */
- rotate: function (angle) {
- for (var idLayer in this.cameras) {
- this.cameras[idLayer].rotate(angle);
- }
- return this;
- },
-
- /**
- * The default handler for window resize events.
- *
- * @param widthRatio The horizontal resize ratio
- * @param heightRatio The vertical resize ratio
- */
- onWindowResize: function (widthRatio, heightRatio) {
- this.setLocation(this.x * widthRatio, this.y * heightRatio)
- .setSize(this.width * widthRatio, this.height * heightRatio)
- .update();
- }
- });
-
- /*
- * Initializes the current Display.
- *
- * This method prepares the DOM representation of the current SVG document.
- * All the image is embedded into a global "g" element on which transformations will be applied.
- * A clipping rectangle is added.
- *
- * This method must be called when the document is ready to be manipulated.
- */
- function onDocumentReady() {
- var svgRoot = document.documentElement; // TODO check SVG tag
-
- // Save the initial bounding box of the document
- // and force its dimensions to the browser window
- initialBBox = svgRoot.getBBox();
- lastWindowWidth = window.innerWidth;
- lastWindowHeight = window.innerHeight;
- svgRoot.setAttribute("width", lastWindowWidth);
- svgRoot.setAttribute("height", lastWindowHeight);
-
- sozi.events.fire("sozi.display.ready");
- }
- /*
- * Resizes the SVG document to fit the browser window.
- *
- * This method calls onWindowResize on all registered viewports.
- */
- function resize() {
- var svgRoot = document.documentElement;
- svgRoot.setAttribute("width", window.innerWidth);
- svgRoot.setAttribute("height", window.innerHeight);
-
- for (var vp in exports.viewPorts) {
- exports.viewPorts[vp].onWindowResize(window.innerWidth / lastWindowWidth, window.innerHeight / lastWindowHeight);
- }
- lastWindowWidth = window.innerWidth;
- lastWindowHeight = window.innerHeight;
- }
-
- sozi.events.listen("sozi.document.ready", onDocumentReady); // @depend events.js
- window.addEventListener("resize", resize, false);
- });
- /*
- * Sozi - A presentation tool using the SVG standard
- *
- * Copyright (C) 2010-2013 Guillaume Savaton
- *
- * This program is dual licensed under the terms of the MIT license
- * or the GNU General Public License (GPL) version 3.
- * A copy of both licenses is provided in the doc/ folder of the
- * official release of Sozi.
- *
- * See http://sozi.baierouge.fr/wiki/en:license for details.
- */
- /**
- * @name sozi.document
- * @namespace Document analysis.
- * @depend namespace.js
- */
- namespace(this, "sozi.document", function (exports, window) {
- "use strict";
-
- // An alias to the global document object
- var document = window.document;
-
- // Constant: the Sozi namespace
- var SOZI_NS = "http://sozi.baierouge.fr";
-
- // Constant: the default frame properties, if missing in the SVG document
- var DEFAULTS = {
- "title": "Untitled",
- "sequence": "0",
- "hide": "true",
- "clip": "true",
- "show-in-frame-list": "true",
- "timeout-enable": "false",
- "timeout-ms": "5000",
- "transition-duration-ms": "1000",
- "transition-zoom-percent": "0",
- "transition-profile": "linear",
- "transition-path-hide": "true"
- };
- var DRAWABLE_TAGS = [ "g", "image", "path", "rect", "circle",
- "ellipse", "line", "polyline", "polygon", "text", "clippath" ];
- // The definitions of all valid frames in the current document
- exports.frames = [];
-
- // The list of layer ids managed by Sozi
- exports.idLayerList = [];
-
- /*
- * Returns the value of an attribute of a given Sozi SVG element.
- *
- * If the attribute is empty or does not exist,
- * then a default value is returned (See DEFAULTS).
- */
- function readAttribute(soziElement, attr) {
- return soziElement.getAttributeNS(SOZI_NS, attr) || DEFAULTS[attr];
- }
- function readStateForLayer(frame, idLayer, soziElement) {
- var state = frame.states[idLayer] =
- frame.states[idLayer] || sozi.display.CameraState.instance();
-
- if (typeof state.transitionZoomPercent === "undefined" || soziElement.hasAttributeNS(SOZI_NS, "transition-zoom-percent")) {
- state.setTransitionZoomPercent(parseInt(readAttribute(soziElement, "transition-zoom-percent"), 10));
- }
- if (typeof state.transitionProfile === "undefined" || soziElement.hasAttributeNS(SOZI_NS, "transition-profile")) {
- state.setTransitionProfile(sozi.animation.profiles[readAttribute(soziElement, "transition-profile")]);
- }
-
- if (typeof state.transitionPath === "undefined" || soziElement.hasAttributeNS(SOZI_NS, "transition-path")) {
- var svgPath = document.getElementById(soziElement.getAttributeNS(SOZI_NS, "transition-path"));
- if (svgPath && svgPath.nodeName === "path") {
- state.setTransitionPath(svgPath);
- if (readAttribute(soziElement, "transition-path-hide") === "true") {
- svgPath.style.visibility = "hidden";
- }
- }
- }
-
- if (soziElement.hasAttributeNS(SOZI_NS, "refid")) {
- var svgElement = document.getElementById(soziElement.getAttributeNS(SOZI_NS, "refid"));
- if (svgElement) {
- state.setAtElement(svgElement);
- if (readAttribute(soziElement, "hide") === "true") {
- svgElement.style.visibility = "hidden";
- }
- }
- }
-
- if (soziElement.hasAttributeNS(SOZI_NS, "clip")) {
- state.setClipped(readAttribute(soziElement, "clip") === "true");
- }
- }
-
- /*
- * Builds the list of frames from the current document.
- *
- * This method collects all elements with tag "sozi:frame" and
- * retrieves their geometrical and animation attributes.
- * SVG elements that should be hidden during the presentation are hidden.
- *
- * The resulting list is available in frames, sorted by frame indices.
- */
- function readFrames() {
- // Collect all group ids referenced in <layer> elements
- var idLayerRefList = [];
- var soziLayerList = document.getElementsByTagNameNS(SOZI_NS, "layer");
- for (var i = 0; i < soziLayerList.length; i += 1) {
- var idLayer = soziLayerList[i].getAttributeNS(SOZI_NS, "group");
- if (idLayer && idLayerRefList.indexOf(idLayer) === -1) {
- idLayerRefList.push(idLayer);
- }
- }
- // Reorganize the document, grouping objects that do not belong
- // to a group referenced in <layer> elements
- var svgRoot = document.documentElement;
- var SVG_NS = "http://www.w3.org/2000/svg";
- // Create the first wrapper group
- var svgWrapper = document.createElementNS(SVG_NS, "g");
- // For each child of the root SVG element
- var svgElementList = Array.prototype.slice.call(svgRoot.childNodes);
- svgElementList.forEach(function (svgElement, index) {
- if (!svgElement.getAttribute) {
- // Remove text elements
- svgRoot.removeChild(svgElement);
- }
- else if (idLayerRefList.indexOf(svgElement.getAttribute("id")) !== -1) {
- // If the current element is a referenced layer ...
- if (svgWrapper.firstChild) {
- // ... and if there were other non-referenced elements before it,
- // append the wrapper group to the <defs> element
- svgWrapper.setAttribute("id", "sozi-wrapper-" + index);
- exports.idLayerList.push("sozi-wrapper-" + index);
- svgRoot.insertBefore(svgWrapper, svgElement);
-
- // Prepare a new wrapper element
- svgWrapper = document.createElementNS(SVG_NS, "g");
- }
-
- // ... append the current element to the <defs> element
- exports.idLayerList.push(svgElement.getAttribute("id"));
- }
- else if (DRAWABLE_TAGS.indexOf(svgElement.localName.toLowerCase()) !== -1) {
- // If the current element is not a referenced layer
- // and is drawable, move it to the current wrapper element
- svgRoot.removeChild(svgElement);
- svgWrapper.appendChild(svgElement);
- }
- });
- // Append last wrapper if needed
- if (svgWrapper.firstChild) {
- svgWrapper.setAttribute("id", "sozi-wrapper-" + svgElementList.length);
- exports.idLayerList.push("sozi-wrapper-" + svgElementList.length);
- svgRoot.appendChild(svgWrapper);
- }
-
- // Analyze <frame> elements sorted by sequence number
- var soziFrameList = Array.prototype.slice.call(document.getElementsByTagNameNS(SOZI_NS, "frame"));
- soziFrameList.sort(
- function (a, b) {
- var seqA = parseInt(readAttribute(a, "sequence"), 10);
- var seqB = parseInt(readAttribute(b, "sequence"), 10)
- return seqA - seqB;
- }
- );
-
- soziFrameList.forEach(function (soziFrame, indexFrame) {
- var newFrame = {
- id: soziFrame.getAttribute("id"),
- title: readAttribute(soziFrame, "title"),
- showInFrameList: readAttribute(soziFrame, "show-in-frame-list") === "true",
- sequence: parseInt(readAttribute(soziFrame, "sequence"), 10),
- timeoutEnable: readAttribute(soziFrame, "timeout-enable") === "true",
- timeoutMs: parseInt(readAttribute(soziFrame, "timeout-ms"), 10),
- transitionDurationMs: parseInt(readAttribute(soziFrame, "transition-duration-ms"), 10),
- states: {}
- };
- // Get the default properties for all layers, either from
- // the current <frame> element or from the corresponding
- // layer in the previous frame.
- // Those properties can later be overriden by <layer> elements
- exports.idLayerList.forEach(function (idLayer) {
- if (indexFrame === 0 || idLayer.search("sozi-wrapper-[0-9]+") !== -1) {
- // In the first frame, or in wrapper layers,
- // read layer attributes from the <frame> element
- readStateForLayer(newFrame, idLayer, soziFrame);
- }
- else {
- // After the first frame, in referenced layers,
- // copy attributes from the corresponding layer in the previous frame
- var currentState = newFrame.states[idLayer] = sozi.display.CameraState.instance();
- var previousState = exports.frames[exports.frames.length - 1].states[idLayer];
- currentState.setAtState(previousState);
- }
- });
- // Collect and analyze <layer> elements in the current <frame> element
- var soziLayerList = Array.prototype.slice.call(soziFrame.getElementsByTagNameNS(SOZI_NS, "layer"));
- soziLayerList.forEach(function (soziLayer) {
- var idLayer = soziLayer.getAttributeNS(SOZI_NS, "group");
- if (idLayer && exports.idLayerList.indexOf(idLayer) !== -1) {
- readStateForLayer(newFrame, idLayer, soziLayer);
- }
- });
-
- // If the <frame> element has at least one valid layer,
- // add it to the frame list
- for (var idLayer in newFrame.states) {
- if (newFrame.states.hasOwnProperty(idLayer)) {
- exports.frames.push(newFrame);
- break;
- }
- }
- });
- }
- /**
- * Return the frame with the given id.
- *
- * @return The index of the frame with the given id. -1 if not found.
- */
- exports.getFrameIndexForId = function (idFrame) {
- for (var indexFrame = 0; indexFrame < exports.frames.length; indexFrame += 1) {
- if (exports.frames[indexFrame].id === idFrame) {
- return indexFrame;
- }
- }
- return - 1;
- };
-
- /*
- * Event handler: document load.
- *
- * This function reads the frames from the document and fires
- * the "documentready" event.
- *
- * @depend events.js
- */
- function onLoad() {
- document.documentElement.removeAttribute("viewBox");
- readFrames();
- sozi.events.fire("sozi.document.ready");
- }
- window.addEventListener("load", onLoad, false);
- });
- /*
- * Sozi - A presentation tool using the SVG standard
- *
- * Copyright (C) 2010-2013 Guillaume Savaton
- *
- * This program is dual licensed under the terms of the MIT license
- * or the GNU General Public License (GPL) version 3.
- * A copy of both licenses is provided in the doc/ folder of the
- * official release of Sozi.
- *
- * See http://sozi.baierouge.fr/wiki/en:license for details.
- */
- /**
- * @name sozi.framelist
- * @namespace Show the frame list.
- * @depend namespace.js
- */
- namespace(this, "sozi.framelist", function (exports, window) {
- "use strict";
-
- // An alias to the global document object
- var document = window.document;
-
- // Constant: the margin around the text of the frame list
- var MARGIN = 5;
-
- // The SVG group that will contain the frame list
- var svgTocGroup;
-
- // The SVG group that will contain the frame titles
- var svgTitlesGroup;
-
- // The current height of the frame list,
- // computed during the initialization
- var tocHeight = 0;
-
- // The X coordinate of the frame list in its hidden state
- var translateXHidden;
-
- // The X coordinate of the frame list when it is completely visible
- var translateXVisible;
-
- // The initial X coordinate of the frame list before starting an animation.
- // This variable is set before showing/hiding the frame list.
- var translateXStart;
-
- // The final X coordinate of the frame list for the starting animation.
- // This variable is set before showing/hiding the frame list.
- var translateXEnd;
-
- // The current X coordinate of the frame list for the running animation.
- // This variable is updated on each animation step.
- var translateX;
-
- // The animator object that will manage animations of the frame list
- var animator;
-
- // Constant: the duration of the showing/hiding animation, in milliseconds
- var ANIMATION_TIME_MS = 300;
-
- // Constant: the acceleration profile of the showing/hiding animation
- var ANIMATION_PROFILE = "decelerate";
-
- // Constant: the SVG namespace
- var SVG_NS = "http://www.w3.org/2000/svg";
- function onMouseOut(evt) {
- var rel = evt.relatedTarget,
- svgRoot = document.documentElement;
- while (rel && rel !== svgTocGroup && rel !== svgRoot) {
- rel = rel.parentNode;
- }
- if (rel !== svgTocGroup) {
- exports.hide();
- sozi.player.restart();
- evt.stopPropagation();
- }
- }
- function onClickArrowUp(evt) {
- var ty = svgTitlesGroup.getCTM().f;
- if (ty <= -window.innerHeight / 2) {
- ty += window.innerHeight / 2;
- } else if (ty < 0) {
- ty = 0;
- }
- svgTitlesGroup.setAttribute("transform", "translate(0," + ty + ")");
- evt.stopPropagation();
- }
- function onClickArrowDown(evt) {
- var ty = svgTitlesGroup.getCTM().f;
- if (ty + tocHeight >= window.innerHeight * 3 / 2) {
- ty -= window.innerHeight / 2;
- } else if (ty + tocHeight > window.innerHeight + 2 * MARGIN) {
- ty = window.innerHeight - tocHeight - 4 * MARGIN;
- }
- svgTitlesGroup.setAttribute("transform", "translate(0," + ty + ")");
- evt.stopPropagation();
- }
- /*
- * Create a function that responds to clicks on frame list entries.
- */
- function makeClickHandler(index) {
- return function (evt) {
- sozi.player.previewFrame(index);
- evt.stopPropagation();
- };
- }
-
- /*
- * The default event handler, to prevent event propagation
- * through the frame list.
- */
- function defaultEventHandler(evt) {
- evt.stopPropagation();
- }
-
- /*
- * Adds a table of contents to the document.
- *
- * The table of contents is a rectangular region with the list of frame titles.
- * Clicking on a title moves the presentation to the corresponding frame.
- *
- * The table of contents is hidden by default.
- */
- function onPlayerReady() {
- svgTocGroup = document.createElementNS(SVG_NS, "g");
- svgTocGroup.setAttribute("id", "sozi-toc");
- document.documentElement.appendChild(svgTocGroup);
- svgTitlesGroup = document.createElementNS(SVG_NS, "g");
- svgTocGroup.appendChild(svgTitlesGroup);
-
- // The background rectangle of the frame list
- var tocBackground = document.createElementNS(SVG_NS, "rect");
- tocBackground.setAttribute("id", "sozi-toc-background");
- tocBackground.setAttribute("x", MARGIN);
- tocBackground.setAttribute("y", MARGIN);
- tocBackground.setAttribute("rx", MARGIN);
- tocBackground.setAttribute("ry", MARGIN);
- tocBackground.addEventListener("click", defaultEventHandler, false);
- tocBackground.addEventListener("mousedown", defaultEventHandler, false);
- tocBackground.addEventListener("mouseout", onMouseOut, false);
- svgTitlesGroup.appendChild(tocBackground);
- var tocWidth = 0;
- sozi.document.frames.forEach(function (frame, frameIndex) {
- if (frame.showInFrameList) {
- var text = document.createElementNS(SVG_NS, "text");
- text.appendChild(document.createTextNode(frame.title));
- text.setAttribute("id", "sozi-toc-" + frame.id);
- svgTitlesGroup.appendChild(text);
-
- if (frameIndex === sozi.player.currentFrameIndex) {
- text.setAttribute("class", "sozi-toc-current");
- }
-
- var textWidth = text.getBBox().width;
- tocHeight += text.getBBox().height;
- if (textWidth > tocWidth) {
- tocWidth = textWidth;
- }
-
- text.setAttribute("x", 2 * MARGIN);
- text.setAttribute("y", tocHeight + MARGIN);
- text.addEventListener("click", makeClickHandler(frameIndex), false);
- text.addEventListener("mousedown", defaultEventHandler, false);
- }
- });
- // The "up" button
- var tocUp = document.createElementNS(SVG_NS, "path");
- tocUp.setAttribute("class", "sozi-toc-arrow");
- tocUp.setAttribute("d", "M" + (tocWidth + 3 * MARGIN) + "," + (5 * MARGIN) +
- " l" + (4 * MARGIN) + ",0" +
- " l-" + (2 * MARGIN) + ",-" + (3 * MARGIN) +
- " z");
- tocUp.addEventListener("click", onClickArrowUp, false);
- tocUp.addEventListener("mousedown", defaultEventHandler, false);
- svgTocGroup.appendChild(tocUp);
- // The "down" button
- var tocDown = document.createElementNS(SVG_NS, "path");
- tocDown.setAttribute("class", "sozi-toc-arrow");
- tocDown.setAttribute("d", "M" + (tocWidth + 3 * MARGIN) + "," + (7 * MARGIN) +
- " l" + (4 * MARGIN) + ",0" +
- " l-" + (2 * MARGIN) + "," + (3 * MARGIN) +
- " z");
- tocDown.addEventListener("click", onClickArrowDown, false);
- tocDown.addEventListener("mousedown", defaultEventHandler, false);
- svgTocGroup.appendChild(tocDown);
- tocBackground.setAttribute("width", tocWidth + 7 * MARGIN);
- tocBackground.setAttribute("height", tocHeight + 2 * MARGIN);
-
- translateXHidden = -tocWidth - 9 * MARGIN;
- translateXVisible = 0;
- translateX = translateXEnd = translateXHidden;
-
- svgTocGroup.setAttribute("transform", "translate(" + translateXHidden + ",0)");
- animator = sozi.animation.Animator.instance().augment({
- onStep: function (progress) {
- var profileProgress = sozi.animation.profiles[ANIMATION_PROFILE](progress),
- remaining = 1 - profileProgress;
- translateX = translateXEnd * profileProgress + translateXStart * remaining;
- svgTocGroup.setAttribute("transform", "translate(" + translateX + ",0)");
- }
- });
- }
- /*
- * Highlight the current frame title in the frame list.
- *
- * This handler is called on each frame change,
- * even when the frame list is hidden.
- */
- function onFrameChange(index) {
- var currentElementList = Array.prototype.slice.call(document.getElementsByClassName("sozi-toc-current"));
- currentElementList.forEach(function (svgElement) {
- svgElement.removeAttribute("class");
- });
- var frame = sozi.document.frames[index];
- if (frame.showInFrameList) {
- document.getElementById("sozi-toc-" + frame.id).setAttribute("class", "sozi-toc-current");
- }
- }
-
- /*
- * Makes the table of contents visible.
- */
- exports.show = function () {
- // Bring frame list to front
- document.documentElement.appendChild(svgTocGroup);
-
- translateXStart = translateX;
- translateXEnd = translateXVisible;
- animator.start(ANIMATION_TIME_MS); // FIXME depends on current elapsed time
- };
- /*
- * Makes the table of contents invisible.
- */
- exports.hide = function () {
- translateXStart = translateX;
- translateXEnd = translateXHidden;
- animator.start(ANIMATION_TIME_MS); // FIXME depends on current elapsed time
- };
- /*
- * Returns true if the table of contents is visible, false otherwise.
- */
- exports.isVisible = function () {
- return translateXEnd === translateXVisible;
- };
- // @depend events.js
- sozi.events.listen("sozi.player.ready", onPlayerReady);
- sozi.events.listen("sozi.player.cleanup", exports.hide);
- sozi.events.listen("sozi.player.framechange", onFrameChange);
- });
- /*
- * Sozi - A presentation tool using the SVG standard
- *
- * Copyright (C) 2010-2013 Guillaume Savaton
- *
- * This program is dual licensed under the terms of the MIT license
- * or the GNU General Public License (GPL) version 3.
- * A copy of both licenses is provided in the doc/ folder of the
- * official release of Sozi.
- *
- * See http://sozi.baierouge.fr/wiki/en:license for details.
- */
- /**
- * @name sozi.framenumber
- * @namespace Show the frame number.
- * @depend namespace.js
- */
- namespace(this, "sozi.framenumber", function (exports, window) {
- "use strict";
-
- // An alias to the global document object
- var document = window.document;
-
- // The SVG group containing the frame number
- var svgGroup;
-
- // The SVG text element and its text node containing the frame number
- var svgText, svgTextNode;
-
- // The SVG circle enclosing the frame number
- var svgCircle;
-
- // Constant: the SVG namespace
- var SVG_NS = "http://www.w3.org/2000/svg";
-
- function adjust() {
- var textBBox = svgText.getBBox(),
- d = Math.max(textBBox.width, textBBox.height) * 0.75,
- t = d * 1.25;
- svgCircle.setAttribute("r", d);
- svgGroup.setAttribute("transform", "translate(" + t + "," + t + ")");
- }
-
- function onPlayerReady() {
- svgGroup = document.createElementNS(SVG_NS, "g");
- svgText = document.createElementNS(SVG_NS, "text");
- svgCircle = document.createElementNS(SVG_NS, "circle");
-
- svgGroup.setAttribute("id", "sozi-framenumber");
- svgCircle.setAttribute("cx", 0);
- svgCircle.setAttribute("cy", 0);
- svgGroup.appendChild(svgCircle);
-
- svgTextNode = document.createTextNode(sozi.player.currentFrameIndex + 1);
- svgText.setAttribute("text-anchor", "middle");
- svgText.setAttribute("dominant-baseline", "central");
- svgText.setAttribute("x", 0);
- svgText.setAttribute("y", 0);
- svgText.appendChild(svgTextNode);
- svgGroup.appendChild(svgText);
-
- document.documentElement.appendChild(svgGroup);
-
- adjust();
- }
- function onFrameChange(index) {
- svgTextNode.nodeValue = index + 1;
- }
-
- // @depend events.js
- sozi.events.listen("sozi.player.ready", onPlayerReady);
- sozi.events.listen("sozi.player.framechange", onFrameChange);
- });
- /*
- * Sozi - A presentation tool using the SVG standard
- *
- * Copyright (C) 2010-2013 Guillaume Savaton
- *
- * This program is dual licensed under the terms of the MIT license
- * or the GNU General Public License (GPL) version 3.
- * A copy of both licenses is provided in the doc/ folder of the
- * official release of Sozi.
- *
- * See http://sozi.baierouge.fr/wiki/en:license for details.
- */
- /**
- * @name sozi.links
- * @namespace Links fix for Webkit.
- * @depend namespace.js
- */
- namespace(this, "sozi.links", function (exports, window) {
- "use strict";
-
- var SVG_NS = "http://www.w3.org/2000/svg";
- var XLINK_NS = "http://www.w3.org/1999/xlink";
-
- function getClickHandler(index) {
- return function (evt) {
- sozi.player.moveToFrame(index);
- evt.preventDefault();
- evt.stopPropagation();
- };
- }
-
- /*
- * Event handler: document ready.
- *
- * This function adds an event listener to each internal link.
- * Clicking on a link that targets a frame of this document
- * will call sozi.player.moveToFrame().
- */
- function onDocumentReady() {
- var links = window.document.getElementsByTagNameNS(SVG_NS, "a");
- for (var i = 0; i < links.length; i += 1) {
- var href = links[i].getAttributeNS(XLINK_NS, "href");
- if (href && href[0] === "#") {
- links[i].addEventListener("click", getClickHandler(sozi.location.getFrameIndexForHash(href)), false);
- }
- }
- }
- sozi.events.listen("sozi.document.ready", onDocumentReady); // @depend events.js
- });
- /*
- * Sozi - A presentation tool using the SVG standard
- *
- * Copyright (C) 2010-2013 Guillaume Savaton
- *
- * This program is dual licensed under the terms of the MIT license
- * or the GNU General Public License (GPL) version 3.
- * A copy of both licenses is provided in the doc/ folder of the
- * official release of Sozi.
- *
- * See http://sozi.baierouge.fr/wiki/en:license for details.
- */
- /**
- * @name sozi.location
- * @namespace Manage the URL in the address bar of the browser window.
- * @depend namespace.js
- */
- namespace(this, "sozi.location", function (exports, window) {
- "use strict";
-
- var changedFromWithin = false;
- /*
- * Returns the frame index corresponding to the URL hash.
- *
- * This is a shortcut for sozi.location.getFrameIndexForHash(window.location.hash)
- */
- exports.getFrameIndex = function () {
- return exports.getFrameIndexForHash(window.location.hash);
- };
-
- /*
- * Returns the frame index corresponding to the given URL hash.
- *
- * The URL hash can be either a frame index or a frame id.
- * In the URL, the frame index starts a 1.
- * This method converts it into a 0-based index.
- *
- * If the URL hash is not a positive integer, then 0 is returned.
- * It the URL hash is an integer greater than the last frame index, then
- * the last frame index is returned.
- */
- exports.getFrameIndexForHash = function (hash) {
- var indexOrId = hash ? hash.slice(1) : "1";
- var index;
- if (/^[0-9]+$/.test(indexOrId)) {
- index = parseInt(indexOrId, 10) - 1;
- }
- else {
- index = sozi.document.getFrameIndexForId(indexOrId);
- }
-
- if (index < 0) {
- return 0;
- }
- else if (index >= sozi.document.frames.length) {
- return sozi.document.frames.length - 1;
- }
- else {
- return index;
- }
- };
- /*
- * Event handler: hash change.
- *
- * This function is called when the URL hash is changed.
- * If the hash was changed manually in the address bar, and if it corresponds to
- * a valid frame number, then the presentation moves to that frame.
- *
- * The hashchange event can be triggered externally, by the user modifying the URL,
- * or internally, by the script modifying window.location.hash.
- */
- function onHashChange() {
- var index = exports.getFrameIndex();
- if (!changedFromWithin) {
- sozi.player.moveToFrame(index);
- }
- changedFromWithin = false;
- }
-
- /*
- * Event handler: frame change.
- *
- * This function is called when the presentation has reached a new frame.
- * The URL hash is set to the current frame id.
- */
- function onFrameChange(index) {
- changedFromWithin = true;
- window.location.hash = "#" + sozi.document.frames[index].id;
- }
- window.addEventListener("hashchange", onHashChange, false);
- sozi.events.listen("sozi.player.framechange", onFrameChange); // @depend events.js
- });
- /*
- * Sozi - A presentation tool using the SVG standard
- *
- * Copyright (C) 2010-2013 Guillaume Savaton
- *
- * This program is dual licensed under the terms of the MIT license
- * or the GNU General Public License (GPL) version 3.
- * A copy of both licenses is provided in the doc/ folder of the
- * official release of Sozi.
- *
- * See http://sozi.baierouge.fr/wiki/en:license for details.
- */
- /**
- * @name sozi.player
- * @namespace Presentation player.
- * @depend namespace.js
- */
- namespace(this, "sozi.player", function (exports, window) {
- "use strict";
-
- var viewPort;
-
- // The animator object used to animate transitions
- var animator;
-
- // The handle returned by setTimeout() for frame timeout
- var nextFrameTimeout;
-
- // Constants: default animation properties
- // for out-of-sequence transitions
- var DEFAULT_DURATION_MS = 500;
- var DEFAULT_ZOOM_PERCENT = -10;
- var DEFAULT_PROFILE = "linear";
-
- // The source frame index for the current transition
- var sourceFrameIndex = 0;
-
- // The index of the visible frame
- exports.currentFrameIndex = 0;
-
- // The state of the presentation.
- // If false, no automatic transition will be fired.
- var playing = false;
-
- // The state of the current frame.
- // If true, an automatic transition will be fired after the current timeout.
- var waiting = false;
- /*
- * Starts waiting before moving to the next frame.
- *
- * It the current frame has a timeout set, this method
- * will register a timer to move to the next frame automatically
- * after the specified time.
- *
- * If the current frame is the last, the presentation will
- * move to the first frame.
- */
- function waitTimeout() {
- if (sozi.document.frames[exports.currentFrameIndex].timeoutEnable) {
- waiting = true;
- var index = (exports.currentFrameIndex + 1) % sozi.document.frames.length;
- nextFrameTimeout = window.setTimeout(function () {
- exports.moveToFrame(index);
- },
- sozi.document.frames[exports.currentFrameIndex].timeoutMs
- );
- }
- }
- /*
- * Starts the presentation from the given frame index (0-based).
- *
- * This method sets the "playing" flag, shows the desired frame
- * and calls waitTimeout.
- */
- exports.startFromIndex = function (index) {
- playing = true;
- waiting = false;
- sourceFrameIndex = index;
- exports.currentFrameIndex = index;
- viewPort.showFrame(sozi.document.frames[index]);
- waitTimeout();
- };
- exports.restart = function () {
- exports.startFromIndex(exports.currentFrameIndex);
- };
- /*
- * Stops the presentation.
- *
- * This method clears the "playing".
- * If the presentation was in "waiting" mode due to a timeout
- * in the current frame, then it stops waiting.
- * The current animation is stopped in its current state.
- */
- exports.stop = function () {
- animator.stop();
- if (waiting) {
- window.clearTimeout(nextFrameTimeout);
- waiting = false;
- }
- playing = false;
- sourceFrameIndex = exports.currentFrameIndex;
- };
- function getZoomData(zoomPercent, s0, s1) {
- var result = {
- ss: ((zoomPercent < 0) ? Math.max(s0, s1) : Math.min(s0, s1)) * (100 - zoomPercent) / 100,
- ts: 0.5,
- k: 0
- };
- if (zoomPercent !== 0) {
- var a = s0 - s1;
- var b = s0 - result.ss;
- var c = s1 - result.ss;
- if (a !== 0) {
- var d = Math.sqrt(b * c);
- var u = (b - d) / a;
- var v = (b + d) / a;
- result.ts = (u > 0 && u <= 1) ? u : v;
- }
- result.k = b / result.ts / result.ts;
- }
- return result;
- }
- /*
- * Jump to a frame with the given index (0-based).
- *
- * This method does not animate the transition from the current
- * state of the display to the desired frame.
- *
- * The presentation is stopped: if a timeout has been set for the
- * target frame, it will be ignored.
- *
- * The URL hash is set to the given frame index (1-based).
- */
- exports.jumpToFrame = function (index) {
- exports.stop();
- sozi.events.fire("sozi.player.cleanup");
- sourceFrameIndex = index;
- exports.currentFrameIndex = index;
- viewPort.showFrame(sozi.document.frames[index]);
- sozi.events.fire("sozi.player.framechange", index);
- };
- /*
- * Returns an associative array where keys are layer names
- * and values are objects in the form { initialState: finalState: profile: zoomWidth: zoomHeight:}
- */
- exports.getAnimationData = function (initialState, finalState, zoomPercent, profile, useTransitionPath, reverseTransitionPath) {
- var data = {};
-
- for (var idLayer in initialState) {
- data[idLayer] = {
- initialState: sozi.display.CameraState.instance(),
- finalState: sozi.display.CameraState.instance(),
- useTransitionPath: useTransitionPath,
- reverseTransitionPath: reverseTransitionPath
- };
-
- data[idLayer].profile = profile || finalState[idLayer].transitionProfile;
- data[idLayer].initialState.setAtState(initialState[idLayer]);
- // If the current layer is referenced in final state, copy the final properties
- // else, copy initial state to final state for the current layer.
- if (finalState.hasOwnProperty(idLayer)) {
- data[idLayer].finalState.setAtState(finalState[idLayer]);
- }
- else {
- data[idLayer].finalState.setAtState(initialState[idLayer]);
- }
- // Keep the smallest angle difference between initial state and final state
- // TODO this should be handled in the interpolation function
- if (data[idLayer].finalState.angle - data[idLayer].initialState.angle > 180) {
- data[idLayer].finalState.setRawAngle(data[idLayer].finalState.angle - 360);
- }
- else if (data[idLayer].finalState.angle - data[idLayer].initialState.angle < -180) {
- data[idLayer].initialState.setRawAngle(data[idLayer].initialState.angle - 360);
- }
- var zp = zoomPercent || finalState[idLayer].transitionZoomPercent;
-
- if (zp && finalState.hasOwnProperty(idLayer)) {
- data[idLayer].zoomWidth = getZoomData(zp,
- initialState[idLayer].width,
- finalState[idLayer].width);
- data[idLayer].zoomHeight = getZoomData(zp,
- initialState[idLayer].height,
- finalState[idLayer].height);
- }
- }
- return data;
- };
-
- exports.previewFrame = function (index) {
- exports.currentFrameIndex = index;
- animator.start(DEFAULT_DURATION_MS,
- exports.getAnimationData(viewPort.cameras, sozi.document.frames[index].states,
- DEFAULT_ZOOM_PERCENT, sozi.animation.profiles[DEFAULT_PROFILE]),
- false, false);
- sozi.events.fire("sozi.player.framechange", index);
- };
- /*
- * Moves to a frame with the given index (0-based).
- *
- * This method animates the transition from the current
- * state of the display to the desired frame.
- *
- * If the given frame index corresponds to the next frame in the list,
- * the transition properties of the next frame are used.
- * Otherwise, default transition properties are used.
- */
- exports.moveToFrame = function (index) {
- if (waiting) {
- window.clearTimeout(nextFrameTimeout);
- waiting = false;
- }
- var durationMs, zoomPercent, profile, useTransitionPath, reverseTransitionPath;
- if (index === (exports.currentFrameIndex - 1) % sozi.document.frames.length) {
- durationMs = sozi.document.frames[exports.currentFrameIndex].transitionDurationMs;
- zoomPercent = undefined; // Set for each layer
- profile = undefined; // Set for each layer
- useTransitionPath = true;
- reverseTransitionPath = true;
- }
- else if (index === (exports.currentFrameIndex + 1) % sozi.document.frames.length) {
- durationMs = sozi.document.frames[index].transitionDurationMs;
- zoomPercent = undefined; // Set for each layer
- profile = undefined; // Set for each layer
- useTransitionPath = true;
- reverseTransitionPath = false;
- }
- else {
- durationMs = DEFAULT_DURATION_MS;
- zoomPercent = DEFAULT_ZOOM_PERCENT;
- profile = sozi.animation.profiles[DEFAULT_PROFILE];
- useTransitionPath = false;
- reverseTransitionPath = false;
- }
- sozi.events.fire("sozi.player.cleanup");
- playing = true;
- exports.currentFrameIndex = index;
- animator.start(durationMs, exports.getAnimationData(
- viewPort.cameras, sozi.document.frames[index].states,
- zoomPercent, profile,
- useTransitionPath, reverseTransitionPath));
- sozi.events.fire("sozi.player.framechange", index);
- };
- /**
- * Jumps to the first frame of the presentation.
- */
- exports.jumpToFirst = function () {
- exports.jumpToFrame(0);
- };
-
- /**
- * Moves to the first frame of the presentation.
- */
- exports.moveToFirst = function () {
- exports.moveToFrame(0);
- };
- /**
- * Jumps to the previous frame.
- */
- exports.jumpToPrevious = function () {
- var index = exports.currentFrameIndex;
- if (!animator.started || sourceFrameIndex <= exports.currentFrameIndex) {
- index -= 1;
- }
- if (index >= 0) {
- exports.jumpToFrame(index);
- }
- };
- /*
- * Moves to the previous frame.
- */
- exports.moveToPrevious = function () {
- for (var index = exports.currentFrameIndex - 1; index >= 0; index -= 1) {
- var frame = sozi.document.frames[index];
- if (!frame.timeoutEnable || frame.timeoutMs !== 0) {
- exports.moveToFrame(index);
- break;
- }
- }
- };
- /**
- * Jumps to the next frame.
- */
- exports.jumpToNext = function () {
- var index = exports.currentFrameIndex;
- if (!animator.started || sourceFrameIndex >= exports.currentFrameIndex) {
- index += 1;
- }
- if (index < sozi.document.frames.length) {
- exports.jumpToFrame(index);
- }
- };
- /**
- * Moves to the next frame.
- */
- exports.moveToNext = function () {
- if (exports.currentFrameIndex < sozi.document.frames.length - 1 || sozi.document.frames[exports.currentFrameIndex].timeoutEnable) {
- exports.moveToFrame((exports.currentFrameIndex + 1) % sozi.document.frames.length);
- }
- };
- /**
- * Jumps to the last frame of the presentation.
- */
- exports.jumpToLast = function () {
- exports.jumpToFrame(sozi.document.frames.length - 1);
- };
- /**
- * Moves to the last frame of the presentation.
- */
- exports.moveToLast = function () {
- exports.moveToFrame(sozi.document.frames.length - 1);
- };
- /*
- * Restores the current frame.
- *
- * This method restores the display to fit the current frame,
- * e.g. after the display has been zoomed or dragged.
- */
- exports.moveToCurrent = function () {
- exports.moveToFrame(exports.currentFrameIndex);
- };
- /*
- * Shows all the document in the browser window.
- */
- exports.showAll = function () {
- exports.stop();
- sozi.events.fire("sozi.player.cleanup");
- animator.start(DEFAULT_DURATION_MS,
- exports.getAnimationData(viewPort.cameras, viewPort.getDocumentState(),
- DEFAULT_ZOOM_PERCENT, sozi.animation.profiles[DEFAULT_PROFILE],
- false, false
- )
- );
- };
- /*
- * Event handler: display ready.
- */
- function onDisplayReady() {
- viewPort = sozi.display.ViewPort.instance("player", sozi.document.idLayerList, true);
-
- exports.startFromIndex(sozi.location.getFrameIndex());
- // Hack to fix the blank screen bug in Chrome/Chromium
- // See https://github.com/senshu/Sozi/issues/109
- window.setTimeout(viewPort.bind(viewPort.update), 1);
-
- sozi.events.fire("sozi.player.ready");
- }
- // TODO move the zoom code to display.js
- exports.onAnimationStep = function (progress, data) {
- for (var idLayer in data) {
- var camera = viewPort.cameras[idLayer];
-
- camera.interpolate(
- data[idLayer].initialState,
- data[idLayer].finalState,
- data[idLayer].profile(progress),
- data[idLayer].useTransitionPath,
- data[idLayer].reverseTransitionPath
- );
- var ps;
- if (data[idLayer].zoomWidth && data[idLayer].zoomWidth.k !== 0) {
- ps = progress - data[idLayer].zoomWidth.ts;
- camera.width = data[idLayer].zoomWidth.k * ps * ps + data[idLayer].zoomWidth.ss;
- }
- if (data[idLayer].zoomHeight && data[idLayer].zoomHeight.k !== 0) {
- ps = progress - data[idLayer].zoomHeight.ts;
- camera.height = data[idLayer].zoomHeight.k * ps * ps + data[idLayer].zoomHeight.ss;
- }
- camera.setClipped(data[idLayer].finalState.clipped);
- }
- viewPort.update();
- };
-
- /**
- * @depend animation.js
- */
- animator = sozi.animation.Animator.instance().augment({
- /*
- * Event handler: animation step.
- *
- * This method is called periodically by animator after the animation
- * has been started, and until the animation time is elapsed.
- *
- * Parameter data provides the following information:
- * - initialState and finalState contain the geometrical properties of the display
- * at the start and end of the animation.
- * - profile is a reference to the speed profile function to use.
- * - zoomWidth and zoomHeight are the parameters of the zooming polynomial if the current
- * animation has a non-zero zooming effect.
- *
- * Parameter progress is a float number between 0 (start of the animation)
- * and 1 (end of the animation).
- */
- onStep: function (progress) {
- exports.onAnimationStep(progress, this.data);
- },
-
- /*
- * Event handler: animation done.
- *
- * This method is called by animator when the current animation is finished.
- *
- * If the animation was a transition in the normal course of the presentation,
- * then we call the waitTimeout method to process the timeout property of the current frame.
- */
- onDone: function () {
- for (var idLayer in this.data) {
- viewPort.cameras[idLayer].setAtState(this.data[idLayer].finalState);
- }
- viewPort.update();
- sourceFrameIndex = exports.currentFrameIndex;
- if (playing) {
- waitTimeout();
- }
- }
- });
- sozi.events.listen("sozi.display.ready", onDisplayReady); // @depend events.js
- });
- /*
- @depend framenumber.js
- @depend framelist.js
- @depend actions.js
- @depend player.js
- @depend display.js
- @depend document.js
- @depend location.js
- @depend links.js
- */
- </script>
- <style
- id="sozi-style"
- ns1:version="13.11-30213629">/*
- * Sozi - A presentation tool using the SVG standard
- *
- * Copyright (C) 2010-2013 Guillaume Savaton
- *
- * This program is dual licensed under the terms of the MIT license
- * or the GNU General Public License (GPL) version 3.
- * A copy of both licenses is provided in the doc/ folder of the
- * official release of Sozi.
- *
- * See http://sozi.baierouge.fr/wiki/en:license for details.
- */
- #sozi-toc text {
- fill: #eff;
- font-family: Verdana, sans-serif;
- font-size: 12pt;
- }
- #sozi-toc text:hover {
- fill: #0cf;
- cursor: pointer;
- }
- #sozi-toc text.sozi-toc-current {
- fill: #fa4;
- }
- #sozi-toc-background {
- stroke: #222;
- stroke-opacity: 0.1;
- stroke-width: 10;
- fill: #222;
- fill-opacity: 0.9;
- }
- .sozi-toc-arrow {
- fill: #eff;
- fill-opacity: 0.75;
- stroke: none;
- }
- .sozi-toc-arrow:hover {
- fill: #0cf;
- }
- #sozi-framenumber circle {
- stroke: #222;
- stroke-opacity: 0.1;
- stroke-width: 4;
- fill: #222;
- fill-opacity: 0.9;
- }
- #sozi-framenumber text {
- fill: #eff;
- font-family: Verdana, sans-serif;
- font-size: 12pt;
- }
- </style>
- </svg>
|