svg2pdf.src.js 124 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390
  1. /**
  2. * Modules in this bundle
  3. * @license
  4. *
  5. * svg2pdf.js:
  6. * license: MIT (http://opensource.org/licenses/MIT)
  7. * author: yFiles for HTML Support Team <yfileshtml@yworks.com>
  8. * homepage: https://github.com/yWorks/svg2pdf.js#readme
  9. * version: 1.3.1
  10. *
  11. * cssesc:
  12. * license: MIT (http://opensource.org/licenses/MIT)
  13. * author: Mathias Bynens
  14. * homepage: https://mths.be/cssesc
  15. * version: 2.0.0
  16. *
  17. * font-family:
  18. * license: MIT (http://opensource.org/licenses/MIT)
  19. * author: Taro Hanamura <m@hanamurataro.com>
  20. * homepage: https://github.com/hanamura/font-family
  21. * version: 0.2.0
  22. *
  23. * svgpath:
  24. * license: MIT (http://opensource.org/licenses/MIT)
  25. * homepage: https://github.com/fontello/svgpath#readme
  26. * version: 2.2.1
  27. *
  28. * This header is generated by licensify (https://github.com/twada/licensify)
  29. */
  30. (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.svg2pdf = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
  31. 'use strict';
  32. module.exports = require('./lib/svgpath');
  33. },{"./lib/svgpath":6}],2:[function(require,module,exports){
  34. // Convert an arc to a sequence of cubic bézier curves
  35. //
  36. 'use strict';
  37. var TAU = Math.PI * 2;
  38. /* eslint-disable space-infix-ops */
  39. // Calculate an angle between two vectors
  40. //
  41. function vector_angle(ux, uy, vx, vy) {
  42. var sign = (ux * vy - uy * vx < 0) ? -1 : 1;
  43. var umag = Math.sqrt(ux * ux + uy * uy);
  44. var vmag = Math.sqrt(ux * ux + uy * uy);
  45. var dot = ux * vx + uy * vy;
  46. var div = dot / (umag * vmag);
  47. // rounding errors, e.g. -1.0000000000000002 can screw up this
  48. if (div > 1.0) { div = 1.0; }
  49. if (div < -1.0) { div = -1.0; }
  50. return sign * Math.acos(div);
  51. }
  52. // Convert from endpoint to center parameterization,
  53. // see http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
  54. //
  55. // Return [cx, cy, theta1, delta_theta]
  56. //
  57. function get_arc_center(x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi) {
  58. // Step 1.
  59. //
  60. // Moving an ellipse so origin will be the middlepoint between our two
  61. // points. After that, rotate it to line up ellipse axes with coordinate
  62. // axes.
  63. //
  64. var x1p = cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2;
  65. var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2;
  66. var rx_sq = rx * rx;
  67. var ry_sq = ry * ry;
  68. var x1p_sq = x1p * x1p;
  69. var y1p_sq = y1p * y1p;
  70. // Step 2.
  71. //
  72. // Compute coordinates of the centre of this ellipse (cx', cy')
  73. // in the new coordinate system.
  74. //
  75. var radicant = (rx_sq * ry_sq) - (rx_sq * y1p_sq) - (ry_sq * x1p_sq);
  76. if (radicant < 0) {
  77. // due to rounding errors it might be e.g. -1.3877787807814457e-17
  78. radicant = 0;
  79. }
  80. radicant /= (rx_sq * y1p_sq) + (ry_sq * x1p_sq);
  81. radicant = Math.sqrt(radicant) * (fa === fs ? -1 : 1);
  82. var cxp = radicant * rx/ry * y1p;
  83. var cyp = radicant * -ry/rx * x1p;
  84. // Step 3.
  85. //
  86. // Transform back to get centre coordinates (cx, cy) in the original
  87. // coordinate system.
  88. //
  89. var cx = cos_phi*cxp - sin_phi*cyp + (x1+x2)/2;
  90. var cy = sin_phi*cxp + cos_phi*cyp + (y1+y2)/2;
  91. // Step 4.
  92. //
  93. // Compute angles (theta1, delta_theta).
  94. //
  95. var v1x = (x1p - cxp) / rx;
  96. var v1y = (y1p - cyp) / ry;
  97. var v2x = (-x1p - cxp) / rx;
  98. var v2y = (-y1p - cyp) / ry;
  99. var theta1 = vector_angle(1, 0, v1x, v1y);
  100. var delta_theta = vector_angle(v1x, v1y, v2x, v2y);
  101. if (fs === 0 && delta_theta > 0) {
  102. delta_theta -= TAU;
  103. }
  104. if (fs === 1 && delta_theta < 0) {
  105. delta_theta += TAU;
  106. }
  107. return [ cx, cy, theta1, delta_theta ];
  108. }
  109. //
  110. // Approximate one unit arc segment with bézier curves,
  111. // see http://math.stackexchange.com/questions/873224
  112. //
  113. function approximate_unit_arc(theta1, delta_theta) {
  114. var alpha = 4/3 * Math.tan(delta_theta/4);
  115. var x1 = Math.cos(theta1);
  116. var y1 = Math.sin(theta1);
  117. var x2 = Math.cos(theta1 + delta_theta);
  118. var y2 = Math.sin(theta1 + delta_theta);
  119. return [ x1, y1, x1 - y1*alpha, y1 + x1*alpha, x2 + y2*alpha, y2 - x2*alpha, x2, y2 ];
  120. }
  121. module.exports = function a2c(x1, y1, x2, y2, fa, fs, rx, ry, phi) {
  122. var sin_phi = Math.sin(phi * TAU / 360);
  123. var cos_phi = Math.cos(phi * TAU / 360);
  124. // Make sure radii are valid
  125. //
  126. var x1p = cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2;
  127. var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2;
  128. if (x1p === 0 && y1p === 0) {
  129. // we're asked to draw line to itself
  130. return [];
  131. }
  132. if (rx === 0 || ry === 0) {
  133. // one of the radii is zero
  134. return [];
  135. }
  136. // Compensate out-of-range radii
  137. //
  138. rx = Math.abs(rx);
  139. ry = Math.abs(ry);
  140. var lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);
  141. if (lambda > 1) {
  142. rx *= Math.sqrt(lambda);
  143. ry *= Math.sqrt(lambda);
  144. }
  145. // Get center parameters (cx, cy, theta1, delta_theta)
  146. //
  147. var cc = get_arc_center(x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi);
  148. var result = [];
  149. var theta1 = cc[2];
  150. var delta_theta = cc[3];
  151. // Split an arc to multiple segments, so each segment
  152. // will be less than τ/4 (= 90°)
  153. //
  154. var segments = Math.max(Math.ceil(Math.abs(delta_theta) / (TAU / 4)), 1);
  155. delta_theta /= segments;
  156. for (var i = 0; i < segments; i++) {
  157. result.push(approximate_unit_arc(theta1, delta_theta));
  158. theta1 += delta_theta;
  159. }
  160. // We have a bezier approximation of a unit circle,
  161. // now need to transform back to the original ellipse
  162. //
  163. return result.map(function (curve) {
  164. for (var i = 0; i < curve.length; i += 2) {
  165. var x = curve[i + 0];
  166. var y = curve[i + 1];
  167. // scale
  168. x *= rx;
  169. y *= ry;
  170. // rotate
  171. var xp = cos_phi*x - sin_phi*y;
  172. var yp = sin_phi*x + cos_phi*y;
  173. // translate
  174. curve[i + 0] = xp + cc[0];
  175. curve[i + 1] = yp + cc[1];
  176. }
  177. return curve;
  178. });
  179. };
  180. },{}],3:[function(require,module,exports){
  181. 'use strict';
  182. /* eslint-disable space-infix-ops */
  183. // The precision used to consider an ellipse as a circle
  184. //
  185. var epsilon = 0.0000000001;
  186. // To convert degree in radians
  187. //
  188. var torad = Math.PI / 180;
  189. // Class constructor :
  190. // an ellipse centred at 0 with radii rx,ry and x - axis - angle ax.
  191. //
  192. function Ellipse(rx, ry, ax) {
  193. if (!(this instanceof Ellipse)) { return new Ellipse(rx, ry, ax); }
  194. this.rx = rx;
  195. this.ry = ry;
  196. this.ax = ax;
  197. }
  198. // Apply a linear transform m to the ellipse
  199. // m is an array representing a matrix :
  200. // - -
  201. // | m[0] m[2] |
  202. // | m[1] m[3] |
  203. // - -
  204. //
  205. Ellipse.prototype.transform = function (m) {
  206. // We consider the current ellipse as image of the unit circle
  207. // by first scale(rx,ry) and then rotate(ax) ...
  208. // So we apply ma = m x rotate(ax) x scale(rx,ry) to the unit circle.
  209. var c = Math.cos(this.ax * torad), s = Math.sin(this.ax * torad);
  210. var ma = [
  211. this.rx * (m[0]*c + m[2]*s),
  212. this.rx * (m[1]*c + m[3]*s),
  213. this.ry * (-m[0]*s + m[2]*c),
  214. this.ry * (-m[1]*s + m[3]*c)
  215. ];
  216. // ma * transpose(ma) = [ J L ]
  217. // [ L K ]
  218. // L is calculated later (if the image is not a circle)
  219. var J = ma[0]*ma[0] + ma[2]*ma[2],
  220. K = ma[1]*ma[1] + ma[3]*ma[3];
  221. // the discriminant of the characteristic polynomial of ma * transpose(ma)
  222. var D = ((ma[0]-ma[3])*(ma[0]-ma[3]) + (ma[2]+ma[1])*(ma[2]+ma[1])) *
  223. ((ma[0]+ma[3])*(ma[0]+ma[3]) + (ma[2]-ma[1])*(ma[2]-ma[1]));
  224. // the "mean eigenvalue"
  225. var JK = (J + K) / 2;
  226. // check if the image is (almost) a circle
  227. if (D < epsilon * JK) {
  228. // if it is
  229. this.rx = this.ry = Math.sqrt(JK);
  230. this.ax = 0;
  231. return this;
  232. }
  233. // if it is not a circle
  234. var L = ma[0]*ma[1] + ma[2]*ma[3];
  235. D = Math.sqrt(D);
  236. // {l1,l2} = the two eigen values of ma * transpose(ma)
  237. var l1 = JK + D/2,
  238. l2 = JK - D/2;
  239. // the x - axis - rotation angle is the argument of the l1 - eigenvector
  240. this.ax = (Math.abs(L) < epsilon && Math.abs(l1 - K) < epsilon) ?
  241. 90
  242. :
  243. Math.atan(Math.abs(L) > Math.abs(l1 - K) ?
  244. (l1 - J) / L
  245. :
  246. L / (l1 - K)
  247. ) * 180 / Math.PI;
  248. // if ax > 0 => rx = sqrt(l1), ry = sqrt(l2), else exchange axes and ax += 90
  249. if (this.ax >= 0) {
  250. // if ax in [0,90]
  251. this.rx = Math.sqrt(l1);
  252. this.ry = Math.sqrt(l2);
  253. } else {
  254. // if ax in ]-90,0[ => exchange axes
  255. this.ax += 90;
  256. this.rx = Math.sqrt(l2);
  257. this.ry = Math.sqrt(l1);
  258. }
  259. return this;
  260. };
  261. // Check if the ellipse is (almost) degenerate, i.e. rx = 0 or ry = 0
  262. //
  263. Ellipse.prototype.isDegenerate = function () {
  264. return (this.rx < epsilon * this.ry || this.ry < epsilon * this.rx);
  265. };
  266. module.exports = Ellipse;
  267. },{}],4:[function(require,module,exports){
  268. 'use strict';
  269. // combine 2 matrixes
  270. // m1, m2 - [a, b, c, d, e, g]
  271. //
  272. function combine(m1, m2) {
  273. return [
  274. m1[0] * m2[0] + m1[2] * m2[1],
  275. m1[1] * m2[0] + m1[3] * m2[1],
  276. m1[0] * m2[2] + m1[2] * m2[3],
  277. m1[1] * m2[2] + m1[3] * m2[3],
  278. m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
  279. m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
  280. ];
  281. }
  282. function Matrix() {
  283. if (!(this instanceof Matrix)) { return new Matrix(); }
  284. this.queue = []; // list of matrixes to apply
  285. this.cache = null; // combined matrix cache
  286. }
  287. Matrix.prototype.matrix = function (m) {
  288. if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0) {
  289. return this;
  290. }
  291. this.cache = null;
  292. this.queue.push(m);
  293. return this;
  294. };
  295. Matrix.prototype.translate = function (tx, ty) {
  296. if (tx !== 0 || ty !== 0) {
  297. this.cache = null;
  298. this.queue.push([ 1, 0, 0, 1, tx, ty ]);
  299. }
  300. return this;
  301. };
  302. Matrix.prototype.scale = function (sx, sy) {
  303. if (sx !== 1 || sy !== 1) {
  304. this.cache = null;
  305. this.queue.push([ sx, 0, 0, sy, 0, 0 ]);
  306. }
  307. return this;
  308. };
  309. Matrix.prototype.rotate = function (angle, rx, ry) {
  310. var rad, cos, sin;
  311. if (angle !== 0) {
  312. this.translate(rx, ry);
  313. rad = angle * Math.PI / 180;
  314. cos = Math.cos(rad);
  315. sin = Math.sin(rad);
  316. this.queue.push([ cos, sin, -sin, cos, 0, 0 ]);
  317. this.cache = null;
  318. this.translate(-rx, -ry);
  319. }
  320. return this;
  321. };
  322. Matrix.prototype.skewX = function (angle) {
  323. if (angle !== 0) {
  324. this.cache = null;
  325. this.queue.push([ 1, 0, Math.tan(angle * Math.PI / 180), 1, 0, 0 ]);
  326. }
  327. return this;
  328. };
  329. Matrix.prototype.skewY = function (angle) {
  330. if (angle !== 0) {
  331. this.cache = null;
  332. this.queue.push([ 1, Math.tan(angle * Math.PI / 180), 0, 1, 0, 0 ]);
  333. }
  334. return this;
  335. };
  336. // Flatten queue
  337. //
  338. Matrix.prototype.toArray = function () {
  339. if (this.cache) {
  340. return this.cache;
  341. }
  342. if (!this.queue.length) {
  343. this.cache = [ 1, 0, 0, 1, 0, 0 ];
  344. return this.cache;
  345. }
  346. this.cache = this.queue[0];
  347. if (this.queue.length === 1) {
  348. return this.cache;
  349. }
  350. for (var i = 1; i < this.queue.length; i++) {
  351. this.cache = combine(this.cache, this.queue[i]);
  352. }
  353. return this.cache;
  354. };
  355. // Apply list of matrixes to (x,y) point.
  356. // If `isRelative` set, `translate` component of matrix will be skipped
  357. //
  358. Matrix.prototype.calc = function (x, y, isRelative) {
  359. var m;
  360. // Don't change point on empty transforms queue
  361. if (!this.queue.length) { return [ x, y ]; }
  362. // Calculate final matrix, if not exists
  363. //
  364. // NB. if you deside to apply transforms to point one-by-one,
  365. // they should be taken in reverse order
  366. if (!this.cache) {
  367. this.cache = this.toArray();
  368. }
  369. m = this.cache;
  370. // Apply matrix to point
  371. return [
  372. x * m[0] + y * m[2] + (isRelative ? 0 : m[4]),
  373. x * m[1] + y * m[3] + (isRelative ? 0 : m[5])
  374. ];
  375. };
  376. module.exports = Matrix;
  377. },{}],5:[function(require,module,exports){
  378. 'use strict';
  379. var paramCounts = { a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0 };
  380. var SPECIAL_SPACES = [
  381. 0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006,
  382. 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF
  383. ];
  384. function isSpace(ch) {
  385. return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029) || // Line terminators
  386. // White spaces
  387. (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
  388. (ch >= 0x1680 && SPECIAL_SPACES.indexOf(ch) >= 0);
  389. }
  390. function isCommand(code) {
  391. /*eslint-disable no-bitwise*/
  392. switch (code | 0x20) {
  393. case 0x6D/* m */:
  394. case 0x7A/* z */:
  395. case 0x6C/* l */:
  396. case 0x68/* h */:
  397. case 0x76/* v */:
  398. case 0x63/* c */:
  399. case 0x73/* s */:
  400. case 0x71/* q */:
  401. case 0x74/* t */:
  402. case 0x61/* a */:
  403. case 0x72/* r */:
  404. return true;
  405. }
  406. return false;
  407. }
  408. function isDigit(code) {
  409. return (code >= 48 && code <= 57); // 0..9
  410. }
  411. function isDigitStart(code) {
  412. return (code >= 48 && code <= 57) || /* 0..9 */
  413. code === 0x2B || /* + */
  414. code === 0x2D || /* - */
  415. code === 0x2E; /* . */
  416. }
  417. function State(path) {
  418. this.index = 0;
  419. this.path = path;
  420. this.max = path.length;
  421. this.result = [];
  422. this.param = 0.0;
  423. this.err = '';
  424. this.segmentStart = 0;
  425. this.data = [];
  426. }
  427. function skipSpaces(state) {
  428. while (state.index < state.max && isSpace(state.path.charCodeAt(state.index))) {
  429. state.index++;
  430. }
  431. }
  432. function scanParam(state) {
  433. var start = state.index,
  434. index = start,
  435. max = state.max,
  436. zeroFirst = false,
  437. hasCeiling = false,
  438. hasDecimal = false,
  439. hasDot = false,
  440. ch;
  441. if (index >= max) {
  442. state.err = 'SvgPath: missed param (at pos ' + index + ')';
  443. return;
  444. }
  445. ch = state.path.charCodeAt(index);
  446. if (ch === 0x2B/* + */ || ch === 0x2D/* - */) {
  447. index++;
  448. ch = (index < max) ? state.path.charCodeAt(index) : 0;
  449. }
  450. // This logic is shamelessly borrowed from Esprima
  451. // https://github.com/ariya/esprimas
  452. //
  453. if (!isDigit(ch) && ch !== 0x2E/* . */) {
  454. state.err = 'SvgPath: param should start with 0..9 or `.` (at pos ' + index + ')';
  455. return;
  456. }
  457. if (ch !== 0x2E/* . */) {
  458. zeroFirst = (ch === 0x30/* 0 */);
  459. index++;
  460. ch = (index < max) ? state.path.charCodeAt(index) : 0;
  461. if (zeroFirst && index < max) {
  462. // decimal number starts with '0' such as '09' is illegal.
  463. if (ch && isDigit(ch)) {
  464. state.err = 'SvgPath: numbers started with `0` such as `09` are ilegal (at pos ' + start + ')';
  465. return;
  466. }
  467. }
  468. while (index < max && isDigit(state.path.charCodeAt(index))) {
  469. index++;
  470. hasCeiling = true;
  471. }
  472. ch = (index < max) ? state.path.charCodeAt(index) : 0;
  473. }
  474. if (ch === 0x2E/* . */) {
  475. hasDot = true;
  476. index++;
  477. while (isDigit(state.path.charCodeAt(index))) {
  478. index++;
  479. hasDecimal = true;
  480. }
  481. ch = (index < max) ? state.path.charCodeAt(index) : 0;
  482. }
  483. if (ch === 0x65/* e */ || ch === 0x45/* E */) {
  484. if (hasDot && !hasCeiling && !hasDecimal) {
  485. state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
  486. return;
  487. }
  488. index++;
  489. ch = (index < max) ? state.path.charCodeAt(index) : 0;
  490. if (ch === 0x2B/* + */ || ch === 0x2D/* - */) {
  491. index++;
  492. }
  493. if (index < max && isDigit(state.path.charCodeAt(index))) {
  494. while (index < max && isDigit(state.path.charCodeAt(index))) {
  495. index++;
  496. }
  497. } else {
  498. state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
  499. return;
  500. }
  501. }
  502. state.index = index;
  503. state.param = parseFloat(state.path.slice(start, index)) + 0.0;
  504. }
  505. function finalizeSegment(state) {
  506. var cmd, cmdLC;
  507. // Process duplicated commands (without comand name)
  508. // This logic is shamelessly borrowed from Raphael
  509. // https://github.com/DmitryBaranovskiy/raphael/
  510. //
  511. cmd = state.path[state.segmentStart];
  512. cmdLC = cmd.toLowerCase();
  513. var params = state.data;
  514. if (cmdLC === 'm' && params.length > 2) {
  515. state.result.push([ cmd, params[0], params[1] ]);
  516. params = params.slice(2);
  517. cmdLC = 'l';
  518. cmd = (cmd === 'm') ? 'l' : 'L';
  519. }
  520. if (cmdLC === 'r') {
  521. state.result.push([ cmd ].concat(params));
  522. } else {
  523. while (params.length >= paramCounts[cmdLC]) {
  524. state.result.push([ cmd ].concat(params.splice(0, paramCounts[cmdLC])));
  525. if (!paramCounts[cmdLC]) {
  526. break;
  527. }
  528. }
  529. }
  530. }
  531. function scanSegment(state) {
  532. var max = state.max,
  533. cmdCode, comma_found, need_params, i;
  534. state.segmentStart = state.index;
  535. cmdCode = state.path.charCodeAt(state.index);
  536. if (!isCommand(cmdCode)) {
  537. state.err = 'SvgPath: bad command ' + state.path[state.index] + ' (at pos ' + state.index + ')';
  538. return;
  539. }
  540. need_params = paramCounts[state.path[state.index].toLowerCase()];
  541. state.index++;
  542. skipSpaces(state);
  543. state.data = [];
  544. if (!need_params) {
  545. // Z
  546. finalizeSegment(state);
  547. return;
  548. }
  549. comma_found = false;
  550. for (;;) {
  551. for (i = need_params; i > 0; i--) {
  552. scanParam(state);
  553. if (state.err.length) {
  554. return;
  555. }
  556. state.data.push(state.param);
  557. skipSpaces(state);
  558. comma_found = false;
  559. if (state.index < max && state.path.charCodeAt(state.index) === 0x2C/* , */) {
  560. state.index++;
  561. skipSpaces(state);
  562. comma_found = true;
  563. }
  564. }
  565. // after ',' param is mandatory
  566. if (comma_found) {
  567. continue;
  568. }
  569. if (state.index >= state.max) {
  570. break;
  571. }
  572. // Stop on next segment
  573. if (!isDigitStart(state.path.charCodeAt(state.index))) {
  574. break;
  575. }
  576. }
  577. finalizeSegment(state);
  578. }
  579. /* Returns array of segments:
  580. *
  581. * [
  582. * [ command, coord1, coord2, ... ]
  583. * ]
  584. */
  585. module.exports = function pathParse(svgPath) {
  586. var state = new State(svgPath);
  587. var max = state.max;
  588. skipSpaces(state);
  589. while (state.index < max && !state.err.length) {
  590. scanSegment(state);
  591. }
  592. if (state.err.length) {
  593. state.result = [];
  594. } else if (state.result.length) {
  595. if ('mM'.indexOf(state.result[0][0]) < 0) {
  596. state.err = 'SvgPath: string should start with `M` or `m`';
  597. state.result = [];
  598. } else {
  599. state.result[0][0] = 'M';
  600. }
  601. }
  602. return {
  603. err: state.err,
  604. segments: state.result
  605. };
  606. };
  607. },{}],6:[function(require,module,exports){
  608. // SVG Path transformations library
  609. //
  610. // Usage:
  611. //
  612. // SvgPath('...')
  613. // .translate(-150, -100)
  614. // .scale(0.5)
  615. // .translate(-150, -100)
  616. // .toFixed(1)
  617. // .toString()
  618. //
  619. 'use strict';
  620. var pathParse = require('./path_parse');
  621. var transformParse = require('./transform_parse');
  622. var matrix = require('./matrix');
  623. var a2c = require('./a2c');
  624. var ellipse = require('./ellipse');
  625. // Class constructor
  626. //
  627. function SvgPath(path) {
  628. if (!(this instanceof SvgPath)) { return new SvgPath(path); }
  629. var pstate = pathParse(path);
  630. // Array of path segments.
  631. // Each segment is array [command, param1, param2, ...]
  632. this.segments = pstate.segments;
  633. // Error message on parse error.
  634. this.err = pstate.err;
  635. // Transforms stack for lazy evaluation
  636. this.__stack = [];
  637. }
  638. SvgPath.prototype.__matrix = function (m) {
  639. var self = this, i;
  640. // Quick leave for empty matrix
  641. if (!m.queue.length) { return; }
  642. this.iterate(function (s, index, x, y) {
  643. var p, result, name, isRelative;
  644. switch (s[0]) {
  645. // Process 'assymetric' commands separately
  646. case 'v':
  647. p = m.calc(0, s[1], true);
  648. result = (p[0] === 0) ? [ 'v', p[1] ] : [ 'l', p[0], p[1] ];
  649. break;
  650. case 'V':
  651. p = m.calc(x, s[1], false);
  652. result = (p[0] === m.calc(x, y, false)[0]) ? [ 'V', p[1] ] : [ 'L', p[0], p[1] ];
  653. break;
  654. case 'h':
  655. p = m.calc(s[1], 0, true);
  656. result = (p[1] === 0) ? [ 'h', p[0] ] : [ 'l', p[0], p[1] ];
  657. break;
  658. case 'H':
  659. p = m.calc(s[1], y, false);
  660. result = (p[1] === m.calc(x, y, false)[1]) ? [ 'H', p[0] ] : [ 'L', p[0], p[1] ];
  661. break;
  662. case 'a':
  663. case 'A':
  664. // ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
  665. // Drop segment if arc is empty (end point === start point)
  666. /*if ((s[0] === 'A' && s[6] === x && s[7] === y) ||
  667. (s[0] === 'a' && s[6] === 0 && s[7] === 0)) {
  668. return [];
  669. }*/
  670. // Transform rx, ry and the x-axis-rotation
  671. var ma = m.toArray();
  672. var e = ellipse(s[1], s[2], s[3]).transform(ma);
  673. // flip sweep-flag if matrix is not orientation-preserving
  674. if (ma[0] * ma[3] - ma[1] * ma[2] < 0) {
  675. s[5] = s[5] ? '0' : '1';
  676. }
  677. // Transform end point as usual (without translation for relative notation)
  678. p = m.calc(s[6], s[7], s[0] === 'a');
  679. // Empty arcs can be ignored by renderer, but should not be dropped
  680. // to avoid collisions with `S A S` and so on. Replace with empty line.
  681. if ((s[0] === 'A' && s[6] === x && s[7] === y) ||
  682. (s[0] === 'a' && s[6] === 0 && s[7] === 0)) {
  683. result = [ s[0] === 'a' ? 'l' : 'L', p[0], p[1] ];
  684. break;
  685. }
  686. // if the resulting ellipse is (almost) a segment ...
  687. if (e.isDegenerate()) {
  688. // replace the arc by a line
  689. result = [ s[0] === 'a' ? 'l' : 'L', p[0], p[1] ];
  690. } else {
  691. // if it is a real ellipse
  692. // s[0], s[4] and s[5] are not modified
  693. result = [ s[0], e.rx, e.ry, e.ax, s[4], s[5], p[0], p[1] ];
  694. }
  695. break;
  696. case 'm':
  697. // Edge case. The very first `m` should be processed as absolute, if happens.
  698. // Make sense for coord shift transforms.
  699. isRelative = index > 0;
  700. p = m.calc(s[1], s[2], isRelative);
  701. result = [ 'm', p[0], p[1] ];
  702. break;
  703. default:
  704. name = s[0];
  705. result = [ name ];
  706. isRelative = (name.toLowerCase() === name);
  707. // Apply transformations to the segment
  708. for (i = 1; i < s.length; i += 2) {
  709. p = m.calc(s[i], s[i + 1], isRelative);
  710. result.push(p[0], p[1]);
  711. }
  712. }
  713. self.segments[index] = result;
  714. }, true);
  715. };
  716. // Apply stacked commands
  717. //
  718. SvgPath.prototype.__evaluateStack = function () {
  719. var m, i;
  720. if (!this.__stack.length) { return; }
  721. if (this.__stack.length === 1) {
  722. this.__matrix(this.__stack[0]);
  723. this.__stack = [];
  724. return;
  725. }
  726. m = matrix();
  727. i = this.__stack.length;
  728. while (--i >= 0) {
  729. m.matrix(this.__stack[i].toArray());
  730. }
  731. this.__matrix(m);
  732. this.__stack = [];
  733. };
  734. // Convert processed SVG Path back to string
  735. //
  736. SvgPath.prototype.toString = function () {
  737. var elements = [], skipCmd, cmd;
  738. this.__evaluateStack();
  739. for (var i = 0; i < this.segments.length; i++) {
  740. // remove repeating commands names
  741. cmd = this.segments[i][0];
  742. skipCmd = i > 0 && cmd !== 'm' && cmd !== 'M' && cmd === this.segments[i - 1][0];
  743. elements = elements.concat(skipCmd ? this.segments[i].slice(1) : this.segments[i]);
  744. }
  745. return elements.join(' ')
  746. // Optimizations: remove spaces around commands & before `-`
  747. //
  748. // We could also remove leading zeros for `0.5`-like values,
  749. // but their count is too small to spend time for.
  750. .replace(/ ?([achlmqrstvz]) ?/gi, '$1')
  751. .replace(/ \-/g, '-')
  752. // workaround for FontForge SVG importing bug
  753. .replace(/zm/g, 'z m');
  754. };
  755. // Translate path to (x [, y])
  756. //
  757. SvgPath.prototype.translate = function (x, y) {
  758. this.__stack.push(matrix().translate(x, y || 0));
  759. return this;
  760. };
  761. // Scale path to (sx [, sy])
  762. // sy = sx if not defined
  763. //
  764. SvgPath.prototype.scale = function (sx, sy) {
  765. this.__stack.push(matrix().scale(sx, (!sy && (sy !== 0)) ? sx : sy));
  766. return this;
  767. };
  768. // Rotate path around point (sx [, sy])
  769. // sy = sx if not defined
  770. //
  771. SvgPath.prototype.rotate = function (angle, rx, ry) {
  772. this.__stack.push(matrix().rotate(angle, rx || 0, ry || 0));
  773. return this;
  774. };
  775. // Skew path along the X axis by `degrees` angle
  776. //
  777. SvgPath.prototype.skewX = function (degrees) {
  778. this.__stack.push(matrix().skewX(degrees));
  779. return this;
  780. };
  781. // Skew path along the Y axis by `degrees` angle
  782. //
  783. SvgPath.prototype.skewY = function (degrees) {
  784. this.__stack.push(matrix().skewY(degrees));
  785. return this;
  786. };
  787. // Apply matrix transform (array of 6 elements)
  788. //
  789. SvgPath.prototype.matrix = function (m) {
  790. this.__stack.push(matrix().matrix(m));
  791. return this;
  792. };
  793. // Transform path according to "transform" attr of SVG spec
  794. //
  795. SvgPath.prototype.transform = function (transformString) {
  796. if (!transformString.trim()) {
  797. return this;
  798. }
  799. this.__stack.push(transformParse(transformString));
  800. return this;
  801. };
  802. // Round coords with given decimal precition.
  803. // 0 by default (to integers)
  804. //
  805. SvgPath.prototype.round = function (d) {
  806. var contourStartDeltaX = 0, contourStartDeltaY = 0, deltaX = 0, deltaY = 0, l;
  807. d = d || 0;
  808. this.__evaluateStack();
  809. this.segments.forEach(function (s) {
  810. var isRelative = (s[0].toLowerCase() === s[0]);
  811. switch (s[0]) {
  812. case 'H':
  813. case 'h':
  814. if (isRelative) { s[1] += deltaX; }
  815. deltaX = s[1] - s[1].toFixed(d);
  816. s[1] = +s[1].toFixed(d);
  817. return;
  818. case 'V':
  819. case 'v':
  820. if (isRelative) { s[1] += deltaY; }
  821. deltaY = s[1] - s[1].toFixed(d);
  822. s[1] = +s[1].toFixed(d);
  823. return;
  824. case 'Z':
  825. case 'z':
  826. deltaX = contourStartDeltaX;
  827. deltaY = contourStartDeltaY;
  828. return;
  829. case 'M':
  830. case 'm':
  831. if (isRelative) {
  832. s[1] += deltaX;
  833. s[2] += deltaY;
  834. }
  835. deltaX = s[1] - s[1].toFixed(d);
  836. deltaY = s[2] - s[2].toFixed(d);
  837. contourStartDeltaX = deltaX;
  838. contourStartDeltaY = deltaY;
  839. s[1] = +s[1].toFixed(d);
  840. s[2] = +s[2].toFixed(d);
  841. return;
  842. case 'A':
  843. case 'a':
  844. // [cmd, rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
  845. if (isRelative) {
  846. s[6] += deltaX;
  847. s[7] += deltaY;
  848. }
  849. deltaX = s[6] - s[6].toFixed(d);
  850. deltaY = s[7] - s[7].toFixed(d);
  851. s[1] = +s[1].toFixed(d);
  852. s[2] = +s[2].toFixed(d);
  853. s[3] = +s[3].toFixed(d + 2); // better precision for rotation
  854. s[6] = +s[6].toFixed(d);
  855. s[7] = +s[7].toFixed(d);
  856. return;
  857. default:
  858. // a c l q s t
  859. l = s.length;
  860. if (isRelative) {
  861. s[l - 2] += deltaX;
  862. s[l - 1] += deltaY;
  863. }
  864. deltaX = s[l - 2] - s[l - 2].toFixed(d);
  865. deltaY = s[l - 1] - s[l - 1].toFixed(d);
  866. s.forEach(function (val, i) {
  867. if (!i) { return; }
  868. s[i] = +s[i].toFixed(d);
  869. });
  870. return;
  871. }
  872. });
  873. return this;
  874. };
  875. // Apply iterator function to all segments. If function returns result,
  876. // current segment will be replaced to array of returned segments.
  877. // If empty array is returned, current regment will be deleted.
  878. //
  879. SvgPath.prototype.iterate = function (iterator, keepLazyStack) {
  880. var segments = this.segments,
  881. replacements = {},
  882. needReplace = false,
  883. lastX = 0,
  884. lastY = 0,
  885. countourStartX = 0,
  886. countourStartY = 0;
  887. var i, j, newSegments;
  888. if (!keepLazyStack) {
  889. this.__evaluateStack();
  890. }
  891. segments.forEach(function (s, index) {
  892. var res = iterator(s, index, lastX, lastY);
  893. if (Array.isArray(res)) {
  894. replacements[index] = res;
  895. needReplace = true;
  896. }
  897. var isRelative = (s[0] === s[0].toLowerCase());
  898. // calculate absolute X and Y
  899. switch (s[0]) {
  900. case 'm':
  901. case 'M':
  902. lastX = s[1] + (isRelative ? lastX : 0);
  903. lastY = s[2] + (isRelative ? lastY : 0);
  904. countourStartX = lastX;
  905. countourStartY = lastY;
  906. return;
  907. case 'h':
  908. case 'H':
  909. lastX = s[1] + (isRelative ? lastX : 0);
  910. return;
  911. case 'v':
  912. case 'V':
  913. lastY = s[1] + (isRelative ? lastY : 0);
  914. return;
  915. case 'z':
  916. case 'Z':
  917. // That make sence for multiple contours
  918. lastX = countourStartX;
  919. lastY = countourStartY;
  920. return;
  921. default:
  922. lastX = s[s.length - 2] + (isRelative ? lastX : 0);
  923. lastY = s[s.length - 1] + (isRelative ? lastY : 0);
  924. }
  925. });
  926. // Replace segments if iterator return results
  927. if (!needReplace) { return this; }
  928. newSegments = [];
  929. for (i = 0; i < segments.length; i++) {
  930. if (typeof replacements[i] !== 'undefined') {
  931. for (j = 0; j < replacements[i].length; j++) {
  932. newSegments.push(replacements[i][j]);
  933. }
  934. } else {
  935. newSegments.push(segments[i]);
  936. }
  937. }
  938. this.segments = newSegments;
  939. return this;
  940. };
  941. // Converts segments from relative to absolute
  942. //
  943. SvgPath.prototype.abs = function () {
  944. this.iterate(function (s, index, x, y) {
  945. var name = s[0],
  946. nameUC = name.toUpperCase(),
  947. i;
  948. // Skip absolute commands
  949. if (name === nameUC) { return; }
  950. s[0] = nameUC;
  951. switch (name) {
  952. case 'v':
  953. // v has shifted coords parity
  954. s[1] += y;
  955. return;
  956. case 'a':
  957. // ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
  958. // touch x, y only
  959. s[6] += x;
  960. s[7] += y;
  961. return;
  962. default:
  963. for (i = 1; i < s.length; i++) {
  964. s[i] += i % 2 ? x : y; // odd values are X, even - Y
  965. }
  966. }
  967. }, true);
  968. return this;
  969. };
  970. // Converts segments from absolute to relative
  971. //
  972. SvgPath.prototype.rel = function () {
  973. this.iterate(function (s, index, x, y) {
  974. var name = s[0],
  975. nameLC = name.toLowerCase(),
  976. i;
  977. // Skip relative commands
  978. if (name === nameLC) { return; }
  979. // Don't touch the first M to avoid potential confusions.
  980. if (index === 0 && name === 'M') { return; }
  981. s[0] = nameLC;
  982. switch (name) {
  983. case 'V':
  984. // V has shifted coords parity
  985. s[1] -= y;
  986. return;
  987. case 'A':
  988. // ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
  989. // touch x, y only
  990. s[6] -= x;
  991. s[7] -= y;
  992. return;
  993. default:
  994. for (i = 1; i < s.length; i++) {
  995. s[i] -= i % 2 ? x : y; // odd values are X, even - Y
  996. }
  997. }
  998. }, true);
  999. return this;
  1000. };
  1001. // Converts arcs to cubic bézier curves
  1002. //
  1003. SvgPath.prototype.unarc = function () {
  1004. this.iterate(function (s, index, x, y) {
  1005. var new_segments, nextX, nextY, result = [], name = s[0];
  1006. // Skip anything except arcs
  1007. if (name !== 'A' && name !== 'a') { return null; }
  1008. if (name === 'a') {
  1009. // convert relative arc coordinates to absolute
  1010. nextX = x + s[6];
  1011. nextY = y + s[7];
  1012. } else {
  1013. nextX = s[6];
  1014. nextY = s[7];
  1015. }
  1016. new_segments = a2c(x, y, nextX, nextY, s[4], s[5], s[1], s[2], s[3]);
  1017. // Degenerated arcs can be ignored by renderer, but should not be dropped
  1018. // to avoid collisions with `S A S` and so on. Replace with empty line.
  1019. if (new_segments.length === 0) {
  1020. return [ [ s[0] === 'a' ? 'l' : 'L', s[6], s[7] ] ];
  1021. }
  1022. new_segments.forEach(function (s) {
  1023. result.push([ 'C', s[2], s[3], s[4], s[5], s[6], s[7] ]);
  1024. });
  1025. return result;
  1026. });
  1027. return this;
  1028. };
  1029. // Converts smooth curves (with missed control point) to generic curves
  1030. //
  1031. SvgPath.prototype.unshort = function () {
  1032. var segments = this.segments;
  1033. var prevControlX, prevControlY, prevSegment;
  1034. var curControlX, curControlY;
  1035. // TODO: add lazy evaluation flag when relative commands supported
  1036. this.iterate(function (s, idx, x, y) {
  1037. var name = s[0], nameUC = name.toUpperCase(), isRelative;
  1038. // First command MUST be M|m, it's safe to skip.
  1039. // Protect from access to [-1] for sure.
  1040. if (!idx) { return; }
  1041. if (nameUC === 'T') { // quadratic curve
  1042. isRelative = (name === 't');
  1043. prevSegment = segments[idx - 1];
  1044. if (prevSegment[0] === 'Q') {
  1045. prevControlX = prevSegment[1] - x;
  1046. prevControlY = prevSegment[2] - y;
  1047. } else if (prevSegment[0] === 'q') {
  1048. prevControlX = prevSegment[1] - prevSegment[3];
  1049. prevControlY = prevSegment[2] - prevSegment[4];
  1050. } else {
  1051. prevControlX = 0;
  1052. prevControlY = 0;
  1053. }
  1054. curControlX = -prevControlX;
  1055. curControlY = -prevControlY;
  1056. if (!isRelative) {
  1057. curControlX += x;
  1058. curControlY += y;
  1059. }
  1060. segments[idx] = [
  1061. isRelative ? 'q' : 'Q',
  1062. curControlX, curControlY,
  1063. s[1], s[2]
  1064. ];
  1065. } else if (nameUC === 'S') { // cubic curve
  1066. isRelative = (name === 's');
  1067. prevSegment = segments[idx - 1];
  1068. if (prevSegment[0] === 'C') {
  1069. prevControlX = prevSegment[3] - x;
  1070. prevControlY = prevSegment[4] - y;
  1071. } else if (prevSegment[0] === 'c') {
  1072. prevControlX = prevSegment[3] - prevSegment[5];
  1073. prevControlY = prevSegment[4] - prevSegment[6];
  1074. } else {
  1075. prevControlX = 0;
  1076. prevControlY = 0;
  1077. }
  1078. curControlX = -prevControlX;
  1079. curControlY = -prevControlY;
  1080. if (!isRelative) {
  1081. curControlX += x;
  1082. curControlY += y;
  1083. }
  1084. segments[idx] = [
  1085. isRelative ? 'c' : 'C',
  1086. curControlX, curControlY,
  1087. s[1], s[2], s[3], s[4]
  1088. ];
  1089. }
  1090. });
  1091. return this;
  1092. };
  1093. module.exports = SvgPath;
  1094. },{"./a2c":2,"./ellipse":3,"./matrix":4,"./path_parse":5,"./transform_parse":7}],7:[function(require,module,exports){
  1095. 'use strict';
  1096. var Matrix = require('./matrix');
  1097. var operations = {
  1098. matrix: true,
  1099. scale: true,
  1100. rotate: true,
  1101. translate: true,
  1102. skewX: true,
  1103. skewY: true
  1104. };
  1105. var CMD_SPLIT_RE = /\s*(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*(.+?)\s*\)[\s,]*/;
  1106. var PARAMS_SPLIT_RE = /[\s,]+/;
  1107. module.exports = function transformParse(transformString) {
  1108. var matrix = new Matrix();
  1109. var cmd, params;
  1110. // Split value into ['', 'translate', '10 50', '', 'scale', '2', '', 'rotate', '-45', '']
  1111. transformString.split(CMD_SPLIT_RE).forEach(function (item) {
  1112. // Skip empty elements
  1113. if (!item.length) { return; }
  1114. // remember operation
  1115. if (typeof operations[item] !== 'undefined') {
  1116. cmd = item;
  1117. return;
  1118. }
  1119. // extract params & att operation to matrix
  1120. params = item.split(PARAMS_SPLIT_RE).map(function (i) {
  1121. return +i || 0;
  1122. });
  1123. // If params count is not correct - ignore command
  1124. switch (cmd) {
  1125. case 'matrix':
  1126. if (params.length === 6) {
  1127. matrix.matrix(params);
  1128. }
  1129. return;
  1130. case 'scale':
  1131. if (params.length === 1) {
  1132. matrix.scale(params[0], params[0]);
  1133. } else if (params.length === 2) {
  1134. matrix.scale(params[0], params[1]);
  1135. }
  1136. return;
  1137. case 'rotate':
  1138. if (params.length === 1) {
  1139. matrix.rotate(params[0], 0, 0);
  1140. } else if (params.length === 3) {
  1141. matrix.rotate(params[0], params[1], params[2]);
  1142. }
  1143. return;
  1144. case 'translate':
  1145. if (params.length === 1) {
  1146. matrix.translate(params[0], 0);
  1147. } else if (params.length === 2) {
  1148. matrix.translate(params[0], params[1]);
  1149. }
  1150. return;
  1151. case 'skewX':
  1152. if (params.length === 1) {
  1153. matrix.skewX(params[0]);
  1154. }
  1155. return;
  1156. case 'skewY':
  1157. if (params.length === 1) {
  1158. matrix.skewY(params[0]);
  1159. }
  1160. return;
  1161. }
  1162. });
  1163. return matrix;
  1164. };
  1165. },{"./matrix":4}],8:[function(require,module,exports){
  1166. /*! https://mths.be/cssesc v1.0.1 by @mathias */
  1167. 'use strict';
  1168. var object = {};
  1169. var hasOwnProperty = object.hasOwnProperty;
  1170. var merge = function merge(options, defaults) {
  1171. if (!options) {
  1172. return defaults;
  1173. }
  1174. var result = {};
  1175. for (var key in defaults) {
  1176. // `if (defaults.hasOwnProperty(key) { … }` is not needed here, since
  1177. // only recognized option names are used.
  1178. result[key] = hasOwnProperty.call(options, key) ? options[key] : defaults[key];
  1179. }
  1180. return result;
  1181. };
  1182. var regexAnySingleEscape = /[ -,\.\/;-@\[-\^`\{-~]/;
  1183. var regexSingleEscape = /[ -,\.\/;-@\[\]\^`\{-~]/;
  1184. var regexAlwaysEscape = /['"\\]/;
  1185. var regexExcessiveSpaces = /(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g;
  1186. // https://mathiasbynens.be/notes/css-escapes#css
  1187. var cssesc = function cssesc(string, options) {
  1188. options = merge(options, cssesc.options);
  1189. if (options.quotes != 'single' && options.quotes != 'double') {
  1190. options.quotes = 'single';
  1191. }
  1192. var quote = options.quotes == 'double' ? '"' : '\'';
  1193. var isIdentifier = options.isIdentifier;
  1194. var firstChar = string.charAt(0);
  1195. var output = '';
  1196. var counter = 0;
  1197. var length = string.length;
  1198. while (counter < length) {
  1199. var character = string.charAt(counter++);
  1200. var codePoint = character.charCodeAt();
  1201. var value = void 0;
  1202. // If it’s not a printable ASCII character…
  1203. if (codePoint < 0x20 || codePoint > 0x7E) {
  1204. if (codePoint >= 0xD800 && codePoint <= 0xDBFF && counter < length) {
  1205. // It’s a high surrogate, and there is a next character.
  1206. var extra = string.charCodeAt(counter++);
  1207. if ((extra & 0xFC00) == 0xDC00) {
  1208. // next character is low surrogate
  1209. codePoint = ((codePoint & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000;
  1210. } else {
  1211. // It’s an unmatched surrogate; only append this code unit, in case
  1212. // the next code unit is the high surrogate of a surrogate pair.
  1213. counter--;
  1214. }
  1215. }
  1216. value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
  1217. } else {
  1218. if (options.escapeEverything) {
  1219. if (regexAnySingleEscape.test(character)) {
  1220. value = '\\' + character;
  1221. } else {
  1222. value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
  1223. }
  1224. // Note: `:` could be escaped as `\:`, but that fails in IE < 8.
  1225. } else if (/[\t\n\f\r\x0B:]/.test(character)) {
  1226. if (!isIdentifier && character == ':') {
  1227. value = character;
  1228. } else {
  1229. value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
  1230. }
  1231. } else if (character == '\\' || !isIdentifier && (character == '"' && quote == character || character == '\'' && quote == character) || isIdentifier && regexSingleEscape.test(character)) {
  1232. value = '\\' + character;
  1233. } else {
  1234. value = character;
  1235. }
  1236. }
  1237. output += value;
  1238. }
  1239. if (isIdentifier) {
  1240. if (/^_/.test(output)) {
  1241. // Prevent IE6 from ignoring the rule altogether (in case this is for an
  1242. // identifier used as a selector)
  1243. output = '\\_' + output.slice(1);
  1244. } else if (/^-[-\d]/.test(output)) {
  1245. output = '\\-' + output.slice(1);
  1246. } else if (/\d/.test(firstChar)) {
  1247. output = '\\3' + firstChar + ' ' + output.slice(1);
  1248. }
  1249. }
  1250. // Remove spaces after `\HEX` escapes that are not followed by a hex digit,
  1251. // since they’re redundant. Note that this is only possible if the escape
  1252. // sequence isn’t preceded by an odd number of backslashes.
  1253. output = output.replace(regexExcessiveSpaces, function ($0, $1, $2) {
  1254. if ($1 && $1.length % 2) {
  1255. // It’s not safe to remove the space, so don’t.
  1256. return $0;
  1257. }
  1258. // Strip the space.
  1259. return ($1 || '') + $2;
  1260. });
  1261. if (!isIdentifier && options.wrap) {
  1262. return quote + output + quote;
  1263. }
  1264. return output;
  1265. };
  1266. // Expose default options (so they can be overridden globally).
  1267. cssesc.options = {
  1268. 'escapeEverything': false,
  1269. 'isIdentifier': false,
  1270. 'quotes': 'single',
  1271. 'wrap': false
  1272. };
  1273. cssesc.version = '1.0.1';
  1274. module.exports = cssesc;
  1275. },{}],9:[function(require,module,exports){
  1276. // parse
  1277. // =====
  1278. // states
  1279. // ------
  1280. var PLAIN = 0;
  1281. var STRINGS = 1;
  1282. var ESCAPING = 2;
  1283. var IDENTIFIER = 3;
  1284. var SEPARATING = 4;
  1285. // patterns
  1286. // --------
  1287. var identifierPattern = /[a-z0-9_-]/i;
  1288. var spacePattern = /[\s\t]/;
  1289. // ---
  1290. var parse = function(str) {
  1291. // vars
  1292. // ----
  1293. var starting = true;
  1294. var state = PLAIN;
  1295. var buffer = '';
  1296. var i = 0;
  1297. var quote;
  1298. var c;
  1299. // result
  1300. // ------
  1301. var names = [];
  1302. // parse
  1303. // -----
  1304. while (true) {
  1305. c = str[i];
  1306. if (state === PLAIN) {
  1307. if (!c && starting) {
  1308. break;
  1309. } else if (!c && !starting) {
  1310. throw new Error('Parse error');
  1311. } else if (c === '"' || c === "'") {
  1312. quote = c;
  1313. state = STRINGS;
  1314. starting = false;
  1315. } else if (spacePattern.test(c)) {
  1316. } else if (identifierPattern.test(c)) {
  1317. state = IDENTIFIER;
  1318. starting = false;
  1319. i--;
  1320. } else {
  1321. throw new Error('Parse error');
  1322. }
  1323. } else if (state === STRINGS) {
  1324. if (!c) {
  1325. throw new Error('Parse Error');
  1326. } else if (c === "\\") {
  1327. state = ESCAPING;
  1328. } else if (c === quote) {
  1329. names.push(buffer);
  1330. buffer = '';
  1331. state = SEPARATING;
  1332. } else {
  1333. buffer += c;
  1334. }
  1335. } else if (state === ESCAPING) {
  1336. if (c === quote || c === "\\") {
  1337. buffer += c;
  1338. state = STRINGS;
  1339. } else {
  1340. throw new Error('Parse error');
  1341. }
  1342. } else if (state === IDENTIFIER) {
  1343. if (!c) {
  1344. names.push(buffer);
  1345. break;
  1346. } else if (identifierPattern.test(c)) {
  1347. buffer += c;
  1348. } else if (c === ',') {
  1349. names.push(buffer);
  1350. buffer = '';
  1351. state = PLAIN;
  1352. } else if (spacePattern.test(c)) {
  1353. names.push(buffer);
  1354. buffer = '';
  1355. state = SEPARATING;
  1356. } else {
  1357. throw new Error('Parse error');
  1358. }
  1359. } else if (state === SEPARATING) {
  1360. if (!c) {
  1361. break;
  1362. } else if (c === ',') {
  1363. state = PLAIN;
  1364. } else if (spacePattern.test(c)) {
  1365. } else {
  1366. throw new Error('Parse error');
  1367. }
  1368. }
  1369. i++;
  1370. }
  1371. // result
  1372. // ------
  1373. return names;
  1374. };
  1375. // stringify
  1376. // =========
  1377. // pattern
  1378. // -------
  1379. var stringsPattern = /[^a-z0-9_-]/i;
  1380. // ---
  1381. var stringify = function(names, options) {
  1382. // quote
  1383. // -----
  1384. var quote = options && options.quote || '"';
  1385. if (quote !== '"' && quote !== "'") {
  1386. throw new Error('Quote must be `\'` or `"`');
  1387. }
  1388. var quotePattern = new RegExp(quote, 'g');
  1389. // stringify
  1390. // ---------
  1391. var safeNames = [];
  1392. for (var i = 0; i < names.length; ++i) {
  1393. var name = names[i];
  1394. if (stringsPattern.test(name)) {
  1395. name = name
  1396. .replace(/\\/g, "\\\\")
  1397. .replace(quotePattern, "\\" + quote);
  1398. name = quote + name + quote;
  1399. }
  1400. safeNames.push(name);
  1401. }
  1402. // result
  1403. // ------
  1404. return safeNames.join(', ');
  1405. };
  1406. // export
  1407. // ======
  1408. module.exports = {
  1409. parse: parse,
  1410. stringify: stringify,
  1411. };
  1412. },{}],10:[function(require,module,exports){
  1413. /**
  1414. * A class to parse color values
  1415. * @author Stoyan Stefanov <sstoo@gmail.com>
  1416. * @link http://www.phpied.com/rgb-color-parser-in-javascript/
  1417. * @license Use it if you like it
  1418. */
  1419. (function (global) {
  1420. function RGBColor(color_string)
  1421. {
  1422. this.ok = false;
  1423. // strip any leading #
  1424. if (color_string.charAt(0) == '#') { // remove # if any
  1425. color_string = color_string.substr(1,6);
  1426. }
  1427. color_string = color_string.replace(/ /g,'');
  1428. color_string = color_string.toLowerCase();
  1429. // before getting into regexps, try simple matches
  1430. // and overwrite the input
  1431. var simple_colors = {
  1432. aliceblue: 'f0f8ff',
  1433. antiquewhite: 'faebd7',
  1434. aqua: '00ffff',
  1435. aquamarine: '7fffd4',
  1436. azure: 'f0ffff',
  1437. beige: 'f5f5dc',
  1438. bisque: 'ffe4c4',
  1439. black: '000000',
  1440. blanchedalmond: 'ffebcd',
  1441. blue: '0000ff',
  1442. blueviolet: '8a2be2',
  1443. brown: 'a52a2a',
  1444. burlywood: 'deb887',
  1445. cadetblue: '5f9ea0',
  1446. chartreuse: '7fff00',
  1447. chocolate: 'd2691e',
  1448. coral: 'ff7f50',
  1449. cornflowerblue: '6495ed',
  1450. cornsilk: 'fff8dc',
  1451. crimson: 'dc143c',
  1452. cyan: '00ffff',
  1453. darkblue: '00008b',
  1454. darkcyan: '008b8b',
  1455. darkgoldenrod: 'b8860b',
  1456. darkgray: 'a9a9a9',
  1457. darkgreen: '006400',
  1458. darkkhaki: 'bdb76b',
  1459. darkmagenta: '8b008b',
  1460. darkolivegreen: '556b2f',
  1461. darkorange: 'ff8c00',
  1462. darkorchid: '9932cc',
  1463. darkred: '8b0000',
  1464. darksalmon: 'e9967a',
  1465. darkseagreen: '8fbc8f',
  1466. darkslateblue: '483d8b',
  1467. darkslategray: '2f4f4f',
  1468. darkturquoise: '00ced1',
  1469. darkviolet: '9400d3',
  1470. deeppink: 'ff1493',
  1471. deepskyblue: '00bfff',
  1472. dimgray: '696969',
  1473. dodgerblue: '1e90ff',
  1474. feldspar: 'd19275',
  1475. firebrick: 'b22222',
  1476. floralwhite: 'fffaf0',
  1477. forestgreen: '228b22',
  1478. fuchsia: 'ff00ff',
  1479. gainsboro: 'dcdcdc',
  1480. ghostwhite: 'f8f8ff',
  1481. gold: 'ffd700',
  1482. goldenrod: 'daa520',
  1483. gray: '808080',
  1484. green: '008000',
  1485. greenyellow: 'adff2f',
  1486. honeydew: 'f0fff0',
  1487. hotpink: 'ff69b4',
  1488. indianred : 'cd5c5c',
  1489. indigo : '4b0082',
  1490. ivory: 'fffff0',
  1491. khaki: 'f0e68c',
  1492. lavender: 'e6e6fa',
  1493. lavenderblush: 'fff0f5',
  1494. lawngreen: '7cfc00',
  1495. lemonchiffon: 'fffacd',
  1496. lightblue: 'add8e6',
  1497. lightcoral: 'f08080',
  1498. lightcyan: 'e0ffff',
  1499. lightgoldenrodyellow: 'fafad2',
  1500. lightgrey: 'd3d3d3',
  1501. lightgreen: '90ee90',
  1502. lightpink: 'ffb6c1',
  1503. lightsalmon: 'ffa07a',
  1504. lightseagreen: '20b2aa',
  1505. lightskyblue: '87cefa',
  1506. lightslateblue: '8470ff',
  1507. lightslategray: '778899',
  1508. lightsteelblue: 'b0c4de',
  1509. lightyellow: 'ffffe0',
  1510. lime: '00ff00',
  1511. limegreen: '32cd32',
  1512. linen: 'faf0e6',
  1513. magenta: 'ff00ff',
  1514. maroon: '800000',
  1515. mediumaquamarine: '66cdaa',
  1516. mediumblue: '0000cd',
  1517. mediumorchid: 'ba55d3',
  1518. mediumpurple: '9370d8',
  1519. mediumseagreen: '3cb371',
  1520. mediumslateblue: '7b68ee',
  1521. mediumspringgreen: '00fa9a',
  1522. mediumturquoise: '48d1cc',
  1523. mediumvioletred: 'c71585',
  1524. midnightblue: '191970',
  1525. mintcream: 'f5fffa',
  1526. mistyrose: 'ffe4e1',
  1527. moccasin: 'ffe4b5',
  1528. navajowhite: 'ffdead',
  1529. navy: '000080',
  1530. oldlace: 'fdf5e6',
  1531. olive: '808000',
  1532. olivedrab: '6b8e23',
  1533. orange: 'ffa500',
  1534. orangered: 'ff4500',
  1535. orchid: 'da70d6',
  1536. palegoldenrod: 'eee8aa',
  1537. palegreen: '98fb98',
  1538. paleturquoise: 'afeeee',
  1539. palevioletred: 'd87093',
  1540. papayawhip: 'ffefd5',
  1541. peachpuff: 'ffdab9',
  1542. peru: 'cd853f',
  1543. pink: 'ffc0cb',
  1544. plum: 'dda0dd',
  1545. powderblue: 'b0e0e6',
  1546. purple: '800080',
  1547. red: 'ff0000',
  1548. rosybrown: 'bc8f8f',
  1549. royalblue: '4169e1',
  1550. saddlebrown: '8b4513',
  1551. salmon: 'fa8072',
  1552. sandybrown: 'f4a460',
  1553. seagreen: '2e8b57',
  1554. seashell: 'fff5ee',
  1555. sienna: 'a0522d',
  1556. silver: 'c0c0c0',
  1557. skyblue: '87ceeb',
  1558. slateblue: '6a5acd',
  1559. slategray: '708090',
  1560. snow: 'fffafa',
  1561. springgreen: '00ff7f',
  1562. steelblue: '4682b4',
  1563. tan: 'd2b48c',
  1564. teal: '008080',
  1565. thistle: 'd8bfd8',
  1566. tomato: 'ff6347',
  1567. turquoise: '40e0d0',
  1568. violet: 'ee82ee',
  1569. violetred: 'd02090',
  1570. wheat: 'f5deb3',
  1571. white: 'ffffff',
  1572. whitesmoke: 'f5f5f5',
  1573. yellow: 'ffff00',
  1574. yellowgreen: '9acd32'
  1575. };
  1576. for (var key in simple_colors) {
  1577. if (color_string == key) {
  1578. color_string = simple_colors[key];
  1579. }
  1580. }
  1581. // emd of simple type-in colors
  1582. // array of color definition objects
  1583. var color_defs = [
  1584. {
  1585. re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
  1586. example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
  1587. process: function (bits){
  1588. return [
  1589. parseInt(bits[1]),
  1590. parseInt(bits[2]),
  1591. parseInt(bits[3])
  1592. ];
  1593. }
  1594. },
  1595. {
  1596. re: /^(\w{2})(\w{2})(\w{2})$/,
  1597. example: ['#00ff00', '336699'],
  1598. process: function (bits){
  1599. return [
  1600. parseInt(bits[1], 16),
  1601. parseInt(bits[2], 16),
  1602. parseInt(bits[3], 16)
  1603. ];
  1604. }
  1605. },
  1606. {
  1607. re: /^(\w{1})(\w{1})(\w{1})$/,
  1608. example: ['#fb0', 'f0f'],
  1609. process: function (bits){
  1610. return [
  1611. parseInt(bits[1] + bits[1], 16),
  1612. parseInt(bits[2] + bits[2], 16),
  1613. parseInt(bits[3] + bits[3], 16)
  1614. ];
  1615. }
  1616. }
  1617. ];
  1618. // search through the definitions to find a match
  1619. for (var i = 0; i < color_defs.length; i++) {
  1620. var re = color_defs[i].re;
  1621. var processor = color_defs[i].process;
  1622. var bits = re.exec(color_string);
  1623. if (bits) {
  1624. var channels = processor(bits);
  1625. this.r = channels[0];
  1626. this.g = channels[1];
  1627. this.b = channels[2];
  1628. this.ok = true;
  1629. }
  1630. }
  1631. // validate/cleanup values
  1632. this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);
  1633. this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g);
  1634. this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b);
  1635. // some getters
  1636. this.toRGB = function () {
  1637. return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
  1638. }
  1639. this.toHex = function () {
  1640. var r = this.r.toString(16);
  1641. var g = this.g.toString(16);
  1642. var b = this.b.toString(16);
  1643. if (r.length == 1) r = '0' + r;
  1644. if (g.length == 1) g = '0' + g;
  1645. if (b.length == 1) b = '0' + b;
  1646. return '#' + r + g + b;
  1647. }
  1648. // help
  1649. this.getHelpXML = function () {
  1650. var examples = new Array();
  1651. // add regexps
  1652. for (var i = 0; i < color_defs.length; i++) {
  1653. var example = color_defs[i].example;
  1654. for (var j = 0; j < example.length; j++) {
  1655. examples[examples.length] = example[j];
  1656. }
  1657. }
  1658. // add type-in colors
  1659. for (var sc in simple_colors) {
  1660. examples[examples.length] = sc;
  1661. }
  1662. var xml = document.createElement('ul');
  1663. xml.setAttribute('id', 'rgbcolor-examples');
  1664. for (var i = 0; i < examples.length; i++) {
  1665. try {
  1666. var list_item = document.createElement('li');
  1667. var list_color = new RGBColor(examples[i]);
  1668. var example_div = document.createElement('div');
  1669. example_div.style.cssText =
  1670. 'margin: 3px; '
  1671. + 'border: 1px solid black; '
  1672. + 'background:' + list_color.toHex() + '; '
  1673. + 'color:' + list_color.toHex()
  1674. ;
  1675. example_div.appendChild(document.createTextNode('test'));
  1676. var list_item_value = document.createTextNode(
  1677. ' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex()
  1678. );
  1679. list_item.appendChild(example_div);
  1680. list_item.appendChild(list_item_value);
  1681. xml.appendChild(list_item);
  1682. } catch(e){}
  1683. }
  1684. return xml;
  1685. }
  1686. }
  1687. if (typeof define === "function" && define.amd) {
  1688. define(function () {
  1689. return RGBColor;
  1690. });
  1691. } else if (typeof module !== "undefined" && module.exports) {
  1692. module.exports = RGBColor;
  1693. } else {
  1694. global.RGBColor = RGBColor;
  1695. }
  1696. return RGBColor;
  1697. })(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this);
  1698. },{}],11:[function(require,module,exports){
  1699. /*
  1700. The MIT License (MIT)
  1701. Copyright (c) 2015-2017 yWorks GmbH
  1702. Permission is hereby granted, free of charge, to any person obtaining a copy
  1703. of this software and associated documentation files (the "Software"), to deal
  1704. in the Software without restriction, including without limitation the rights
  1705. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  1706. copies of the Software, and to permit persons to whom the Software is
  1707. furnished to do so, subject to the following conditions:
  1708. The above copyright notice and this permission notice shall be included in all
  1709. copies or substantial portions of the Software.
  1710. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1711. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1712. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  1713. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  1714. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  1715. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  1716. SOFTWARE.
  1717. */
  1718. /**
  1719. * Renders an svg element to a jsPDF document.
  1720. * For accurate results a DOM document is required (mainly used for text size measurement and image format conversion)
  1721. * @param element {HTMLElement} The svg element, which will be cloned, so the original stays unchanged.
  1722. * @param pdf {jsPDF} The jsPDF object.
  1723. * @param options {object} An object that may contain render options. Currently supported are:
  1724. * scale: The global factor by which everything is scaled.
  1725. * xOffset, yOffset: Offsets that are added to every coordinate AFTER scaling (They are not
  1726. * influenced by the scale attribute).
  1727. */
  1728. (function (global) {
  1729. var RGBColor;
  1730. var SvgPath;
  1731. var FontFamily;
  1732. var cssEsc;
  1733. var _pdf; // jsPDF pdf-document
  1734. var cToQ = 2 / 3; // ratio to convert quadratic bezier curves to cubic ones
  1735. var iriReference = /url\(["']?#([^"']+)["']?\)/;
  1736. // groups: 1: mime-type (+ charset), 2: mime-type (w/o charset), 3: charset, 4: base64?, 5: body
  1737. var dataUrlRegex = /^\s*data:(([^/,;]+\/[^/,;]+)(?:;([^,;=]+=[^,;=]+))?)?(?:;(base64))?,(.*\s*)$/i;
  1738. var svgNamespaceURI = "http://www.w3.org/2000/svg";
  1739. // pathSegList is marked deprecated in chrome, so parse the d attribute manually if necessary
  1740. var getPathSegList = function (node) {
  1741. var d = node.getAttribute("d");
  1742. // Replace arcs before path segment list is handled
  1743. if (SvgPath) {
  1744. d = SvgPath(d).unshort().unarc().abs().toString();
  1745. node.setAttribute('d', d);
  1746. }
  1747. var pathSegList = node.pathSegList;
  1748. if (pathSegList) {
  1749. return pathSegList;
  1750. }
  1751. pathSegList = [];
  1752. var regex = /([a-df-zA-DF-Z])([^a-df-zA-DF-Z]*)/g,
  1753. match;
  1754. while (match = regex.exec(d)) {
  1755. var coords = parseFloats(match[2]);
  1756. var type = match[1];
  1757. var length = "zZ".indexOf(type) >= 0 ? 0 :
  1758. "hHvV".indexOf(type) >= 0 ? 1 :
  1759. "mMlLtT".indexOf(type) >= 0 ? 2 :
  1760. "sSqQ".indexOf(type) >= 0 ? 4 :
  1761. "aA".indexOf(type) >= 0 ? 7 :
  1762. "cC".indexOf(type) >= 0 ? 6 : -1;
  1763. var i = 0;
  1764. do {
  1765. var pathSeg = {pathSegTypeAsLetter: type};
  1766. switch (type) {
  1767. case "h":
  1768. case "H":
  1769. pathSeg.x = coords[i];
  1770. break;
  1771. case "v":
  1772. case "V":
  1773. pathSeg.y = coords[i];
  1774. break;
  1775. case "c":
  1776. case "C":
  1777. pathSeg.x1 = coords[i + length - 6];
  1778. pathSeg.y1 = coords[i + length - 5];
  1779. case "s":
  1780. case "S":
  1781. pathSeg.x2 = coords[i + length - 4];
  1782. pathSeg.y2 = coords[i + length - 3];
  1783. case "t":
  1784. case "T":
  1785. case "l":
  1786. case "L":
  1787. case "m":
  1788. case "M":
  1789. pathSeg.x = coords[i + length - 2];
  1790. pathSeg.y = coords[i + length - 1];
  1791. break;
  1792. case "q":
  1793. case "Q":
  1794. pathSeg.x1 = coords[i];
  1795. pathSeg.y1 = coords[i + 1];
  1796. pathSeg.x = coords[i + 2];
  1797. pathSeg.y = coords[i + 3];
  1798. break;
  1799. case "a":
  1800. case "A":
  1801. throw new Error("Cannot convert Arcs without SvgPath package");
  1802. }
  1803. pathSegList.push(pathSeg);
  1804. // "If a moveto is followed by multiple pairs of coordinates, the subsequent pairs are treated as implicit
  1805. // lineto commands"
  1806. if (type === "m") {
  1807. type = "l";
  1808. } else if (type === "M") {
  1809. type = "L";
  1810. }
  1811. i += length;
  1812. } while(i < coords.length);
  1813. }
  1814. pathSegList.getItem = function (i) {
  1815. return this[i]
  1816. };
  1817. pathSegList.numberOfItems = pathSegList.length;
  1818. return pathSegList;
  1819. };
  1820. // returns an attribute of a node, either from the node directly or from css
  1821. var getAttribute = function (node, propertyNode, propertyCss) {
  1822. propertyCss = propertyCss || propertyNode;
  1823. return node.getAttribute(propertyNode) || node.style && node.style[propertyCss];
  1824. };
  1825. /**
  1826. * @param {Element} node
  1827. * @param {string} tagsString
  1828. * @return {boolean}
  1829. */
  1830. var nodeIs = function (node, tagsString) {
  1831. return tagsString.split(",").indexOf(node.tagName.toLowerCase()) >= 0;
  1832. };
  1833. var forEachChild = function (node, fn) {
  1834. // copy list of children, as the original might be modified
  1835. var children = [];
  1836. for (var i = 0; i < node.childNodes.length; i++) {
  1837. var childNode = node.childNodes[i];
  1838. if (childNode.nodeName.charAt(0) !== "#")
  1839. children.push(childNode);
  1840. }
  1841. for (i = 0; i < children.length; i++) {
  1842. fn(i, children[i]);
  1843. }
  1844. };
  1845. var getAngle = function (from, to) {
  1846. return Math.atan2(to[1] - from[1], to[0] - from[0]);
  1847. };
  1848. function normalize(v) {
  1849. var length = Math.sqrt(v[0] * v[0] + v[1] * v[1]);
  1850. return [v[0] / length, v[1] / length];
  1851. }
  1852. function getDirectionVector(from, to) {
  1853. var v = [to[0] - from[0], to[1] - from[1]];
  1854. return normalize(v);
  1855. }
  1856. function addVectors(v1, v2) {
  1857. return [v1[0] + v2[0], v1[1] + v2[1]];
  1858. }
  1859. // mirrors p1 at p2
  1860. var mirrorPoint = function (p1, p2) {
  1861. var dx = p2[0] - p1[0];
  1862. var dy = p2[1] - p1[1];
  1863. return [p1[0] + 2 * dx, p1[1] + 2 * dy];
  1864. };
  1865. // transforms a cubic bezier control point to a quadratic one: returns from + (2/3) * (to - from)
  1866. var toCubic = function (from, to) {
  1867. return [cToQ * (to[0] - from[0]) + from[0], cToQ * (to[1] - from[1]) + from[1]];
  1868. };
  1869. // extracts a control point from a previous path segment (for t,T,s,S segments)
  1870. var getControlPointFromPrevious = function (i, from, list, prevX, prevY) {
  1871. var prev = list.getItem(i - 1);
  1872. var p2;
  1873. if (i > 0 && (prev.pathSegTypeAsLetter === "C" || prev.pathSegTypeAsLetter === "S")) {
  1874. p2 = mirrorPoint([prev.x2, prev.y2], from);
  1875. } else if (i > 0 && (prev.pathSegTypeAsLetter === "c" || prev.pathSegTypeAsLetter === "s")) {
  1876. p2 = mirrorPoint([prev.x2 + prevX, prev.y2 + prevY], from);
  1877. } else {
  1878. p2 = [from[0], from[1]];
  1879. }
  1880. return p2;
  1881. };
  1882. /**
  1883. * @param {Element} rootSvg
  1884. * @constructor
  1885. * @property {Object.<String,Element>} renderedElements
  1886. * @property {Element} rootSvg
  1887. */
  1888. function ReferencesHandler(rootSvg) {
  1889. this.renderedElements = {};
  1890. this.rootSvg = rootSvg;
  1891. }
  1892. /**
  1893. * @param {string} id
  1894. * @return {*}
  1895. */
  1896. ReferencesHandler.prototype.getRendered = function (id) {
  1897. if (this.renderedElements.hasOwnProperty(id)) {
  1898. return this.renderedElements[id];
  1899. }
  1900. var node = this.rootSvg.querySelector("#" + cssEsc(id, {isIdentifier: true}));
  1901. if (nodeIs(node, "lineargradient")) {
  1902. putGradient(node, "axial", [
  1903. node.getAttribute("x1") || 0,
  1904. node.getAttribute("y1") || 0,
  1905. node.getAttribute("x2") || 1,
  1906. node.getAttribute("y2") || 0
  1907. ]);
  1908. } else if (nodeIs(node, "radialgradient")) {
  1909. putGradient(node, "radial", [
  1910. node.getAttribute("fx") || node.getAttribute("cx") || 0.5,
  1911. node.getAttribute("fy") || node.getAttribute("cy") || 0.5,
  1912. 0,
  1913. node.getAttribute("cx") || 0.5,
  1914. node.getAttribute("cy") || 0.5,
  1915. node.getAttribute("r") || 0.5
  1916. ]);
  1917. } else if (nodeIs(node, "pattern")) {
  1918. pattern(node, this, AttributeState.default())
  1919. } else if (nodeIs(node, "marker")) {
  1920. // the transformations directly at the node are written to the pdf form object transformation matrix
  1921. var tfMatrix = computeNodeTransform(node);
  1922. var bBox = getUntransformedBBox(node);
  1923. _pdf.beginFormObject(bBox[0], bBox[1], bBox[2], bBox[3], tfMatrix);
  1924. renderChildren(node, _pdf.unitMatrix, this, false, false, AttributeState.default());
  1925. _pdf.endFormObject(node.getAttribute("id"));
  1926. } else if (!nodeIs(node, "clippath")) {
  1927. // all other nodes will be rendered as PDF form object
  1928. renderNode(node, _pdf.unitMatrix, this, true, false, AttributeState.default());
  1929. }
  1930. this.renderedElements[id] = node;
  1931. return node;
  1932. };
  1933. var AttributeState = function () {
  1934. this.xmlSpace = null;
  1935. this.color = null;
  1936. this.fill = null;
  1937. this.fillOpacity = 1.0;
  1938. // this.fillRule = null;
  1939. this.fontFamily = null;
  1940. this.fontSize = 16;
  1941. this.fontStyle = null;
  1942. // this.fontVariant = null;
  1943. this.fontWeight = null;
  1944. this.opacity = 1.0;
  1945. this.stroke = null;
  1946. this.strokeDasharray = null;
  1947. this.strokeDashoffset = null;
  1948. this.strokeLinecap = null;
  1949. this.strokeLinejoin = null;
  1950. this.strokeMiterlimit = 4.0;
  1951. this.strokeOpacity = 1.0;
  1952. this.strokeWidth = 1.0;
  1953. // this.textAlign = null;
  1954. this.textAnchor = null;
  1955. this.visibility = null;
  1956. };
  1957. AttributeState.default = function () {
  1958. var attributeState = new AttributeState();
  1959. attributeState.xmlSpace = "default";
  1960. attributeState.fill = new RGBColor("rgb(0, 0, 0)");
  1961. attributeState.fillOpacity = 1.0;
  1962. // attributeState.fillRule = "nonzero";
  1963. attributeState.fontFamily = "times";
  1964. attributeState.fontSize = 16;
  1965. attributeState.fontStyle = "normal";
  1966. // attributeState.fontVariant = "normal";
  1967. attributeState.fontWeight = "normal";
  1968. attributeState.opacity = 1.0;
  1969. attributeState.stroke = null;
  1970. attributeState.strokeDasharray = null;
  1971. attributeState.strokeDashoffset = null;
  1972. attributeState.strokeLinecap = "butt";
  1973. attributeState.strokeLinejoin = "miter";
  1974. attributeState.strokeMiterlimit = 4.0;
  1975. attributeState.strokeOpacity = 1.0;
  1976. attributeState.strokeWidth = 1.0;
  1977. // attributeState.textAlign = "start";
  1978. attributeState.textAnchor = "start";
  1979. attributeState.visibility = "visible";
  1980. return attributeState;
  1981. };
  1982. AttributeState.prototype.clone = function () {
  1983. var clone = new AttributeState();
  1984. clone.xmlSpace = this.xmlSpace;
  1985. clone.fill = this.fill;
  1986. clone.fillOpacity = this.fillOpacity;
  1987. // clone.fillRule = this.fillRule;
  1988. clone.fontFamily = this.fontFamily;
  1989. clone.fontSize = this.fontSize;
  1990. clone.fontStyle = this.fontStyle;
  1991. // clone.fontVariant = this.fontVariant;
  1992. clone.fontWeight = this.fontWeight;
  1993. clone.opacity = this.opacity;
  1994. clone.stroke = this.stroke;
  1995. clone.strokeDasharray = this.strokeDasharray;
  1996. clone.strokeDashoffset = this.strokeDashoffset;
  1997. clone.strokeLinecap = this.strokeLinecap;
  1998. clone.strokeLinejoin = this.strokeLinejoin;
  1999. clone.strokeMiterlimit = this.strokeMiterlimit;
  2000. clone.strokeOpacity = this.strokeOpacity;
  2001. clone.strokeWidth = this.strokeWidth;
  2002. // clone.textAlign = this.textAlign;
  2003. clone.textAnchor = this.textAnchor;
  2004. clone.visibility = this.visibility;
  2005. return clone;
  2006. };
  2007. /**
  2008. * @constructor
  2009. * @property {Marker[]} markers
  2010. */
  2011. function MarkerList() {
  2012. this.markers = [];
  2013. }
  2014. /**
  2015. * @param {Marker} marker
  2016. */
  2017. MarkerList.prototype.addMarker = function addMarker(marker) {
  2018. this.markers.push(marker);
  2019. };
  2020. MarkerList.prototype.draw = function (tfMatrix, refsHandler, attributeState) {
  2021. for (var i = 0; i < this.markers.length; i++) {
  2022. var marker = this.markers[i];
  2023. var tf;
  2024. var angle = marker.angle, anchor = marker.anchor;
  2025. var cos = Math.cos(angle);
  2026. var sin = Math.sin(angle);
  2027. // position at and rotate around anchor
  2028. tf = new _pdf.Matrix(cos, sin, -sin, cos, anchor[0], anchor[1]);
  2029. // scale with stroke-width
  2030. tf = _pdf.matrixMult(new _pdf.Matrix(attributeState.strokeWidth, 0, 0, attributeState.strokeWidth, 0, 0), tf);
  2031. tf = _pdf.matrixMult(tf, tfMatrix);
  2032. // as the marker is already scaled by the current line width we must not apply the line width twice!
  2033. _pdf.saveGraphicsState();
  2034. _pdf.setLineWidth(1.0);
  2035. refsHandler.getRendered(marker.id);
  2036. _pdf.doFormObject(marker.id, tf);
  2037. _pdf.restoreGraphicsState();
  2038. }
  2039. };
  2040. /**
  2041. * @param {string} id
  2042. * @param {[number,number]} anchor
  2043. * @param {number} angle
  2044. */
  2045. function Marker(id, anchor, angle) {
  2046. this.id = id;
  2047. this.anchor = anchor;
  2048. this.angle = angle;
  2049. }
  2050. function removeNewlines(str) {
  2051. return str.replace(/[\n\r]/g, "");
  2052. }
  2053. function replaceTabsBySpace(str) {
  2054. return str.replace(/[\t]/g, " ");
  2055. }
  2056. function consolidateSpaces(str) {
  2057. return str.replace(/ +/g, " ");
  2058. }
  2059. function trimLeft(str) {
  2060. return str.replace(/^\s+/,"");
  2061. }
  2062. function trimRight(str) {
  2063. return str.replace(/\s+$/,"");
  2064. }
  2065. function computeViewBoxTransform(node, viewBox, eX, eY, eWidth, eHeight) {
  2066. var vbX = viewBox[0];
  2067. var vbY = viewBox[1];
  2068. var vbWidth = viewBox[2];
  2069. var vbHeight = viewBox[3];
  2070. var scaleX = eWidth / vbWidth;
  2071. var scaleY = eHeight / vbHeight;
  2072. var align, meetOrSlice;
  2073. var preserveAspectRatio = node.getAttribute("preserveAspectRatio");
  2074. if (preserveAspectRatio) {
  2075. var alignAndMeetOrSlice = preserveAspectRatio.split(" ");
  2076. if (alignAndMeetOrSlice[0] === "defer") {
  2077. alignAndMeetOrSlice = alignAndMeetOrSlice.slice(1);
  2078. }
  2079. align = alignAndMeetOrSlice[0];
  2080. meetOrSlice = alignAndMeetOrSlice[1] || "meet";
  2081. } else {
  2082. align = "xMidYMid";
  2083. meetOrSlice = "meet"
  2084. }
  2085. if (align !== "none") {
  2086. if (meetOrSlice === "meet") {
  2087. // uniform scaling with min scale
  2088. scaleX = scaleY = Math.min(scaleX, scaleY);
  2089. } else if (meetOrSlice === "slice") {
  2090. // uniform scaling with max scale
  2091. scaleX = scaleY = Math.max(scaleX, scaleY);
  2092. }
  2093. }
  2094. var translateX = eX - (vbX * scaleX);
  2095. var translateY = eY - (vbY * scaleY);
  2096. if (align.indexOf("xMid") >= 0) {
  2097. translateX += (eWidth - vbWidth * scaleX) / 2;
  2098. } else if (align.indexOf("xMax") >= 0) {
  2099. translateX += eWidth - vbWidth * scaleX;
  2100. }
  2101. if (align.indexOf("yMid") >= 0) {
  2102. translateY += (eHeight - vbHeight * scaleY) / 2;
  2103. } else if (align.indexOf("yMax") >= 0) {
  2104. translateY += (eHeight - vbHeight * scaleY);
  2105. }
  2106. var translate = new _pdf.Matrix(1, 0, 0, 1, translateX, translateY);
  2107. var scale = new _pdf.Matrix(scaleX, 0, 0, scaleY, 0, 0);
  2108. return _pdf.matrixMult(scale, translate);
  2109. }
  2110. // computes the transform directly applied at the node (such as viewbox scaling and the "transform" atrribute)
  2111. // x,y,cx,cy,r,... are omitted
  2112. var computeNodeTransform = function (node) {
  2113. var viewBox, x, y;
  2114. var nodeTransform = _pdf.unitMatrix;
  2115. if (nodeIs(node, "svg,g")) {
  2116. x = parseFloat(node.getAttribute("x")) || 0;
  2117. y = parseFloat(node.getAttribute("y")) || 0;
  2118. viewBox = node.getAttribute("viewBox");
  2119. if (viewBox) {
  2120. var box = parseFloats(viewBox);
  2121. var width = parseFloat(node.getAttribute("width")) || box[2];
  2122. var height = parseFloat(node.getAttribute("height")) || box[3];
  2123. nodeTransform = computeViewBoxTransform(node, box, x, y, width, height)
  2124. } else {
  2125. nodeTransform = new _pdf.Matrix(1, 0, 0, 1, x, y);
  2126. }
  2127. } else if (nodeIs(node, "marker")) {
  2128. x = parseFloat(node.getAttribute("refX")) || 0;
  2129. y = parseFloat(node.getAttribute("refY")) || 0;
  2130. viewBox = node.getAttribute("viewBox");
  2131. if (viewBox) {
  2132. var bounds = parseFloats(viewBox);
  2133. bounds[0] = bounds[1] = 0; // for some reason vbX anc vbY seem to be ignored for markers
  2134. nodeTransform = computeViewBoxTransform(node,
  2135. bounds,
  2136. 0,
  2137. 0,
  2138. parseFloat(node.getAttribute("markerWidth")) || 3,
  2139. parseFloat(node.getAttribute("markerHeight")) || 3
  2140. );
  2141. nodeTransform = _pdf.matrixMult(new _pdf.Matrix(1, 0, 0, 1, -x, -y), nodeTransform);
  2142. } else {
  2143. nodeTransform = new _pdf.Matrix(1, 0, 0, 1, -x, -y);
  2144. }
  2145. }
  2146. var transformString = node.getAttribute("transform");
  2147. if (!transformString)
  2148. return nodeTransform;
  2149. else
  2150. return _pdf.matrixMult(nodeTransform, parseTransform(transformString));
  2151. };
  2152. // parses the "points" string used by polygons and returns an array of points
  2153. var parsePointsString = function (string) {
  2154. var floats = parseFloats(string);
  2155. var result = [];
  2156. for (var i = 0; i < floats.length - 1; i += 2) {
  2157. var x = floats[i];
  2158. var y = floats[i + 1];
  2159. result.push([x, y]);
  2160. }
  2161. return result;
  2162. };
  2163. // parses the "transform" string
  2164. var parseTransform = function (transformString) {
  2165. if (!transformString)
  2166. return _pdf.unitMatrix;
  2167. var mRegex = /^\s*matrix\(([^\)]+)\)\s*/,
  2168. tRegex = /^\s*translate\(([^\)]+)\)\s*/,
  2169. rRegex = /^\s*rotate\(([^\)]+)\)\s*/,
  2170. sRegex = /^\s*scale\(([^\)]+)\)\s*/,
  2171. sXRegex = /^\s*skewX\(([^\)]+)\)\s*/,
  2172. sYRegex = /^\s*skewY\(([^\)]+)\)\s*/;
  2173. var resultMatrix = _pdf.unitMatrix, m;
  2174. while (transformString.length > 0) {
  2175. var match = mRegex.exec(transformString);
  2176. if (match) {
  2177. m = parseFloats(match[1]);
  2178. resultMatrix = _pdf.matrixMult(new _pdf.Matrix(m[0], m[1], m[2], m[3], m[4], m[5]), resultMatrix);
  2179. transformString = transformString.substr(match[0].length);
  2180. }
  2181. match = rRegex.exec(transformString);
  2182. if (match) {
  2183. m = parseFloats(match[1]);
  2184. var a = Math.PI * m[0] / 180;
  2185. resultMatrix = _pdf.matrixMult(new _pdf.Matrix(Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0), resultMatrix);
  2186. if (m[1] && m[2]) {
  2187. var t1 = new _pdf.Matrix(1, 0, 0, 1, m[1], m[2]);
  2188. var t2 = new _pdf.Matrix(1, 0, 0, 1, -m[1], -m[2]);
  2189. resultMatrix = _pdf.matrixMult(t2, _pdf.matrixMult(resultMatrix, t1));
  2190. }
  2191. transformString = transformString.substr(match[0].length);
  2192. }
  2193. match = tRegex.exec(transformString);
  2194. if (match) {
  2195. m = parseFloats(match[1]);
  2196. resultMatrix = _pdf.matrixMult(new _pdf.Matrix(1, 0, 0, 1, m[0], m[1] || 0), resultMatrix);
  2197. transformString = transformString.substr(match[0].length);
  2198. }
  2199. match = sRegex.exec(transformString);
  2200. if (match) {
  2201. m = parseFloats(match[1]);
  2202. if (!m[1])
  2203. m[1] = m[0];
  2204. resultMatrix = _pdf.matrixMult(new _pdf.Matrix(m[0], 0, 0, m[1], 0, 0), resultMatrix);
  2205. transformString = transformString.substr(match[0].length);
  2206. }
  2207. match = sXRegex.exec(transformString);
  2208. if (match) {
  2209. m = parseFloat(match[1]);
  2210. resultMatrix = _pdf.matrixMult(new _pdf.Matrix(1, 0, Math.tan(m), 1, 0, 0), resultMatrix);
  2211. transformString = transformString.substr(match[0].length);
  2212. }
  2213. match = sYRegex.exec(transformString);
  2214. if (match) {
  2215. m = parseFloat(match[1]);
  2216. resultMatrix = _pdf.matrixMult(new _pdf.Matrix(1, Math.tan(m), 0, 1, 0, 0), resultMatrix);
  2217. transformString = transformString.substr(match[0].length);
  2218. }
  2219. }
  2220. return resultMatrix;
  2221. };
  2222. // parses a comma, sign and/or whitespace separated string of floats and returns the single floats in an array
  2223. var parseFloats = function (str) {
  2224. var floats = [], match,
  2225. regex = /[+-]?(?:(?:\d+\.?\d*)|(?:\d*\.?\d+))(?:[eE][+-]?\d+)?/g;
  2226. while(match = regex.exec(str)) {
  2227. floats.push(parseFloat(match[0]));
  2228. }
  2229. return floats;
  2230. };
  2231. // extends RGBColor by rgba colors as RGBColor is not capable of it
  2232. var parseColor = function (colorString) {
  2233. if (colorString === "transparent") {
  2234. var transparent = new RGBColor("rgb(0,0,0)");
  2235. transparent.a = 0;
  2236. return transparent
  2237. }
  2238. var match = /\s*rgba\(((?:[^,\)]*,){3}[^,\)]*)\)\s*/.exec(colorString);
  2239. if (match) {
  2240. var floats = parseFloats(match[1]);
  2241. var color = new RGBColor("rgb(" + floats.slice(0,3).join(",") + ")");
  2242. color.a = floats[3];
  2243. return color;
  2244. } else {
  2245. return new RGBColor(colorString);
  2246. }
  2247. };
  2248. // multiplies a vector with a matrix: vec' = vec * matrix
  2249. var multVecMatrix = function (vec, matrix) {
  2250. var x = vec[0];
  2251. var y = vec[1];
  2252. return [
  2253. matrix.a * x + matrix.c * y + matrix.e,
  2254. matrix.b * x + matrix.d * y + matrix.f
  2255. ];
  2256. };
  2257. // returns the untransformed bounding box [x, y, width, height] of an svg element (quite expensive for path and polygon objects, as
  2258. // the whole points/d-string has to be processed)
  2259. var getUntransformedBBox = function (node) {
  2260. if (getAttribute(node, "display") === "none") {
  2261. return [0, 0, 0, 0];
  2262. }
  2263. var i, minX, minY, maxX, maxY, viewBox, vb, boundingBox;
  2264. var pf = parseFloat;
  2265. if (nodeIs(node, "polygon,polyline")) {
  2266. var points = parsePointsString(node.getAttribute("points"));
  2267. minX = Number.POSITIVE_INFINITY;
  2268. minY = Number.POSITIVE_INFINITY;
  2269. maxX = Number.NEGATIVE_INFINITY;
  2270. maxY = Number.NEGATIVE_INFINITY;
  2271. for (i = 0; i < points.length; i++) {
  2272. var point = points[i];
  2273. minX = Math.min(minX, point[0]);
  2274. maxX = Math.max(maxX, point[0]);
  2275. minY = Math.min(minY, point[1]);
  2276. maxY = Math.max(maxY, point[1]);
  2277. }
  2278. boundingBox = [
  2279. minX,
  2280. minY,
  2281. maxX - minX,
  2282. maxY - minY
  2283. ];
  2284. } else if (nodeIs(node, "path")) {
  2285. var list = getPathSegList(node);
  2286. minX = Number.POSITIVE_INFINITY;
  2287. minY = Number.POSITIVE_INFINITY;
  2288. maxX = Number.NEGATIVE_INFINITY;
  2289. maxY = Number.NEGATIVE_INFINITY;
  2290. var x = 0, y = 0;
  2291. var prevX, prevY, newX, newY;
  2292. var p2, p3, to;
  2293. for (i = 0; i < list.numberOfItems; i++) {
  2294. var seg = list.getItem(i);
  2295. var cmd = seg.pathSegTypeAsLetter;
  2296. switch (cmd) {
  2297. case "H":
  2298. newX = seg.x;
  2299. newY = y;
  2300. break;
  2301. case "h":
  2302. newX = seg.x + x;
  2303. newY = y;
  2304. break;
  2305. case "V":
  2306. newX = x;
  2307. newY = seg.y;
  2308. break;
  2309. case "v":
  2310. newX = x;
  2311. newY = seg.y + y;
  2312. break;
  2313. case "C":
  2314. p2 = [seg.x1, seg.y1];
  2315. p3 = [seg.x2, seg.y2];
  2316. to = [seg.x, seg.y];
  2317. break;
  2318. case "c":
  2319. p2 = [seg.x1 + x, seg.y1 + y];
  2320. p3 = [seg.x2 + x, seg.y2 + y];
  2321. to = [seg.x + x, seg.y + y];
  2322. break;
  2323. case "S":
  2324. p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
  2325. p3 = [seg.x2, seg.y2];
  2326. to = [seg.x, seg.y];
  2327. break;
  2328. case "s":
  2329. p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
  2330. p3 = [seg.x2 + x, seg.y2 + y];
  2331. to = [seg.x + x, seg.y + y];
  2332. break;
  2333. case "Q":
  2334. pf = [seg.x1, seg.y1];
  2335. p2 = toCubic([x, y], pf);
  2336. p3 = toCubic([seg.x, seg.y], pf);
  2337. to = [seg.x, seg.y];
  2338. break;
  2339. case "q":
  2340. pf = [seg.x1 + x, seg.y1 + y];
  2341. p2 = toCubic([x, y], pf);
  2342. p3 = toCubic([x + seg.x, y + seg.y], pf);
  2343. to = [seg.x + x, seg.y + y];
  2344. break;
  2345. case "T":
  2346. p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
  2347. p2 = toCubic([x, y], pf);
  2348. p3 = toCubic([seg.x, seg.y], pf);
  2349. to = [seg.x, seg.y];
  2350. break;
  2351. case "t":
  2352. pf = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
  2353. p2 = toCubic([x, y], pf);
  2354. p3 = toCubic([x + seg.x, y + seg.y], pf);
  2355. to = [seg.x + x, seg.y + y];
  2356. break;
  2357. // TODO: A,a
  2358. }
  2359. if ("sScCqQtT".indexOf(cmd) >= 0) {
  2360. prevX = x;
  2361. prevY = y;
  2362. }
  2363. if ("MLCSQT".indexOf(cmd) >= 0) {
  2364. x = seg.x;
  2365. y = seg.y;
  2366. } else if ("mlcsqt".indexOf(cmd) >= 0) {
  2367. x = seg.x + x;
  2368. y = seg.y + y;
  2369. } else if ("zZ".indexOf(cmd) < 0) {
  2370. x = newX;
  2371. y = newY;
  2372. }
  2373. if ("CSQTcsqt".indexOf(cmd) >= 0) {
  2374. minX = Math.min(minX, x, p2[0], p3[0], to[0]);
  2375. maxX = Math.max(maxX, x, p2[0], p3[0], to[0]);
  2376. minY = Math.min(minY, y, p2[1], p3[1], to[1]);
  2377. maxY = Math.max(maxY, y, p2[1], p3[1], to[1]);
  2378. } else {
  2379. minX = Math.min(minX, x);
  2380. maxX = Math.max(maxX, x);
  2381. minY = Math.min(minY, y);
  2382. maxY = Math.max(maxY, y);
  2383. }
  2384. }
  2385. boundingBox = [
  2386. minX,
  2387. minY,
  2388. maxX - minX,
  2389. maxY - minY
  2390. ];
  2391. } else if (nodeIs(node, "svg")) {
  2392. viewBox = node.getAttribute("viewBox");
  2393. if (viewBox) {
  2394. vb = parseFloats(viewBox);
  2395. }
  2396. return [
  2397. pf(node.getAttribute("x")) || (vb && vb[0]) || 0,
  2398. pf(node.getAttribute("y")) || (vb && vb[1]) || 0,
  2399. pf(node.getAttribute("width")) || (vb && vb[2]) || 0,
  2400. pf(node.getAttribute("height")) || (vb && vb[3]) || 0
  2401. ];
  2402. } else if (nodeIs(node, "g,clippath")) {
  2403. boundingBox = [0, 0, 0, 0];
  2404. forEachChild(node, function (i, node) {
  2405. var nodeBox = getUntransformedBBox(node);
  2406. boundingBox = [
  2407. Math.min(boundingBox[0], nodeBox[0]),
  2408. Math.min(boundingBox[1], nodeBox[1]),
  2409. Math.max(boundingBox[0] + boundingBox[2], nodeBox[0] + nodeBox[2]) - Math.min(boundingBox[0], nodeBox[0]),
  2410. Math.max(boundingBox[1] + boundingBox[3], nodeBox[1] + nodeBox[3]) - Math.min(boundingBox[1], nodeBox[1])
  2411. ];
  2412. });
  2413. } else if (nodeIs(node, "marker")) {
  2414. viewBox = node.getAttribute("viewBox");
  2415. if (viewBox) {
  2416. vb = parseFloats(viewBox);
  2417. }
  2418. return [
  2419. (vb && vb[0]) || 0,
  2420. (vb && vb[1]) || 0,
  2421. (vb && vb[2]) || pf(node.getAttribute("marker-width")) || 0,
  2422. (vb && vb[3]) || pf(node.getAttribute("marker-height")) || 0
  2423. ];
  2424. } else if (nodeIs(node, "pattern")) {
  2425. return [
  2426. pf(node.getAttribute("x")) || 0,
  2427. pf(node.getAttribute("y")) || 0,
  2428. pf(node.getAttribute("width")) || 0,
  2429. pf(node.getAttribute("height")) || 0
  2430. ]
  2431. } else {
  2432. // TODO: check if there are other possible coordinate attributes
  2433. var x1 = pf(node.getAttribute("x1")) || pf(node.getAttribute("x")) || pf((node.getAttribute("cx")) - pf(node.getAttribute("r"))) || 0;
  2434. var x2 = pf(node.getAttribute("x2")) || (x1 + pf(node.getAttribute("width"))) || (pf(node.getAttribute("cx")) + pf(node.getAttribute("r"))) || 0;
  2435. var y1 = pf(node.getAttribute("y1")) || pf(node.getAttribute("y")) || (pf(node.getAttribute("cy")) - pf(node.getAttribute("r"))) || 0;
  2436. var y2 = pf(node.getAttribute("y2")) || (y1 + pf(node.getAttribute("height"))) || (pf(node.getAttribute("cy")) + pf(node.getAttribute("r"))) || 0;
  2437. boundingBox = [
  2438. Math.min(x1, x2),
  2439. Math.min(y1, y2),
  2440. Math.max(x1, x2) - Math.min(x1, x2),
  2441. Math.max(y1, y2) - Math.min(y1, y2)
  2442. ];
  2443. }
  2444. if (!nodeIs(node, "marker,svg,g")) {
  2445. // add line-width
  2446. var lineWidth = getAttribute(node, "stroke-width") || 1;
  2447. var miterLimit = getAttribute(node, "stroke-miterlimit");
  2448. // miterLength / lineWidth = 1 / sin(phi / 2)
  2449. miterLimit && (lineWidth *= 0.5 / (Math.sin(Math.PI / 12)));
  2450. return [
  2451. boundingBox[0] - lineWidth,
  2452. boundingBox[1] - lineWidth,
  2453. boundingBox[2] + 2 * lineWidth,
  2454. boundingBox[3] + 2 * lineWidth
  2455. ];
  2456. }
  2457. return boundingBox;
  2458. };
  2459. // transforms a bounding box and returns a new rect that contains it
  2460. var transformBBox = function (box, matrix) {
  2461. var bl = multVecMatrix([box[0], box[1]], matrix);
  2462. var br = multVecMatrix([box[0] + box[2], box[1]], matrix);
  2463. var tl = multVecMatrix([box[0], box[1] + box[3]], matrix);
  2464. var tr = multVecMatrix([box[0] + box[2], box[1] + box[3]], matrix);
  2465. var bottom = Math.min(bl[1], br[1], tl[1], tr[1]);
  2466. var left = Math.min(bl[0], br[0], tl[0], tr[0]);
  2467. var top = Math.max(bl[1], br[1], tl[1], tr[1]);
  2468. var right = Math.max(bl[0], br[0], tl[0], tr[0]);
  2469. return [
  2470. left,
  2471. bottom,
  2472. right - left,
  2473. top - bottom
  2474. ]
  2475. };
  2476. // draws a polygon
  2477. var polygon = function (node, refsHandler, attributeState, closed) {
  2478. if (!node.hasAttribute("points") || node.getAttribute("points") === "") {
  2479. return;
  2480. }
  2481. var points = parsePointsString(node.getAttribute("points"));
  2482. var lines = [{op: "m", c: points[0]}];
  2483. var i, angle;
  2484. for (i = 1; i < points.length; i++) {
  2485. lines.push({op: "l", c: points[i]});
  2486. }
  2487. if (closed) {
  2488. lines.push({op: "h"});
  2489. }
  2490. _pdf.path(lines);
  2491. var markerEnd = node.getAttribute("marker-end"),
  2492. markerStart = node.getAttribute("marker-start"),
  2493. markerMid = node.getAttribute("marker-mid");
  2494. if (markerStart || markerMid || markerEnd) {
  2495. var length = lines.length;
  2496. var markers = new MarkerList();
  2497. if (markerStart) {
  2498. markerStart = iriReference.exec(markerStart)[1];
  2499. angle = addVectors(getDirectionVector(lines[0].c, lines[1].c), getDirectionVector(lines[length - 2].c, lines[0].c));
  2500. markers.addMarker(new Marker(markerStart, lines[0].c, Math.atan2(angle[1], angle[0])));
  2501. }
  2502. if (markerMid) {
  2503. markerMid = iriReference.exec(markerMid)[1];
  2504. var prevAngle = getDirectionVector(lines[0].c, lines[1].c), curAngle;
  2505. for (i = 1; i < lines.length - 2; i++) {
  2506. curAngle = getDirectionVector(lines[i].c, lines[i + 1].c);
  2507. angle = addVectors(prevAngle, curAngle);
  2508. markers.addMarker(new Marker(markerMid, lines[i].c, Math.atan2(angle[1], angle[0])));
  2509. prevAngle = curAngle;
  2510. }
  2511. curAngle = getDirectionVector(lines[length - 2].c, lines[0].c);
  2512. angle = addVectors(prevAngle, curAngle);
  2513. markers.addMarker(new Marker(markerMid, lines[length - 2].c, Math.atan2(angle[1], angle[0])));
  2514. }
  2515. if (markerEnd) {
  2516. markerEnd = iriReference.exec(markerEnd)[1];
  2517. angle = addVectors(getDirectionVector(lines[0].c, lines[1].c), getDirectionVector(lines[length - 2].c, lines[0].c));
  2518. markers.addMarker(new Marker(markerEnd, lines[0].c, Math.atan2(angle[1], angle[0])));
  2519. }
  2520. markers.draw(_pdf.unitMatrix, refsHandler, attributeState);
  2521. }
  2522. };
  2523. // draws an image
  2524. var image = function (node) {
  2525. var width = parseFloat(node.getAttribute("width")),
  2526. height = parseFloat(node.getAttribute("height")),
  2527. x = parseFloat(node.getAttribute("x") || 0),
  2528. y = parseFloat(node.getAttribute("y") || 0);
  2529. var imageUrl = node.getAttribute("xlink:href") || node.getAttribute("href");
  2530. var dataUrl = imageUrl.match(dataUrlRegex);
  2531. if (dataUrl && dataUrl[2] === "image/svg+xml") {
  2532. var svgText = dataUrl[5];
  2533. if (dataUrl[4] === "base64") {
  2534. svgText = atob(svgText);
  2535. } else {
  2536. svgText = decodeURIComponent(svgText);
  2537. }
  2538. var parser = new DOMParser();
  2539. var svgElement = parser.parseFromString(svgText, "image/svg+xml").firstElementChild;
  2540. // unless preserveAspectRatio starts with "defer", the preserveAspectRatio attribute of the svg is ignored
  2541. var preserveAspectRatio = node.getAttribute("preserveAspectRatio");
  2542. if (!preserveAspectRatio
  2543. || preserveAspectRatio.indexOf("defer") < 0
  2544. || !svgElement.getAttribute("preserveAspectRatio")) {
  2545. svgElement.setAttribute("preserveAspectRatio", preserveAspectRatio);
  2546. }
  2547. svgElement.setAttribute("x", String(x));
  2548. svgElement.setAttribute("y", String(y));
  2549. svgElement.setAttribute("width", String(width));
  2550. svgElement.setAttribute("height", String(height));
  2551. renderNode(svgElement, _pdf.unitMatrix, {}, false, false, AttributeState.default());
  2552. return;
  2553. }
  2554. try {
  2555. _pdf.addImage(
  2556. imageUrl,
  2557. "", // will be ignored anyways if imageUrl is a data url
  2558. x,
  2559. y,
  2560. width,
  2561. height
  2562. );
  2563. } catch (e) {
  2564. (typeof console === "object"
  2565. && console.warn
  2566. && console.warn('svg2pdfjs: Images with external resource link are not supported! ("' + imageUrl + '")'));
  2567. }
  2568. };
  2569. // draws a path
  2570. var path = function (node, tfMatrix, refsHandler, withinClipPath, attributeState) {
  2571. var list = getPathSegList(node);
  2572. var markerEnd = node.getAttribute("marker-end"),
  2573. markerStart = node.getAttribute("marker-start"),
  2574. markerMid = node.getAttribute("marker-mid");
  2575. markerEnd && (markerEnd = iriReference.exec(markerEnd)[1]);
  2576. markerStart && (markerStart = iriReference.exec(markerStart)[1]);
  2577. markerMid && (markerMid = iriReference.exec(markerMid)[1]);
  2578. var getLinesFromPath = function () {
  2579. var x = 0, y = 0;
  2580. var x0 = x, y0 = y;
  2581. var prevX, prevY, newX, newY;
  2582. var to, p, p2, p3;
  2583. var lines = [];
  2584. var markers = new MarkerList();
  2585. var op;
  2586. var prevAngle = [0, 0], curAngle;
  2587. for (var i = 0; i < list.numberOfItems; i++) {
  2588. var seg = list.getItem(i);
  2589. var cmd = seg.pathSegTypeAsLetter;
  2590. switch (cmd) {
  2591. case "M":
  2592. x0 = x;
  2593. y0 = y;
  2594. to = [seg.x, seg.y];
  2595. op = "m";
  2596. break;
  2597. case "m":
  2598. x0 = x;
  2599. y0 = y;
  2600. to = [seg.x + x, seg.y + y];
  2601. op = "m";
  2602. break;
  2603. case "L":
  2604. to = [seg.x, seg.y];
  2605. op = "l";
  2606. break;
  2607. case "l":
  2608. to = [seg.x + x, seg.y + y];
  2609. op = "l";
  2610. break;
  2611. case "H":
  2612. to = [seg.x, y];
  2613. op = "l";
  2614. newX = seg.x;
  2615. newY = y;
  2616. break;
  2617. case "h":
  2618. to = [seg.x + x, y];
  2619. op = "l";
  2620. newX = seg.x + x;
  2621. newY = y;
  2622. break;
  2623. case "V":
  2624. to = [x, seg.y];
  2625. op = "l";
  2626. newX = x;
  2627. newY = seg.y;
  2628. break;
  2629. case "v":
  2630. to = [x, seg.y + y];
  2631. op = "l";
  2632. newX = x;
  2633. newY = seg.y + y;
  2634. break;
  2635. case "C":
  2636. p2 = [seg.x1, seg.y1];
  2637. p3 = [seg.x2, seg.y2];
  2638. to = [seg.x, seg.y];
  2639. break;
  2640. case "c":
  2641. p2 = [seg.x1 + x, seg.y1 + y];
  2642. p3 = [seg.x2 + x, seg.y2 + y];
  2643. to = [seg.x + x, seg.y + y];
  2644. break;
  2645. case "S":
  2646. p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
  2647. p3 = [seg.x2, seg.y2];
  2648. to = [seg.x, seg.y];
  2649. break;
  2650. case "s":
  2651. p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
  2652. p3 = [seg.x2 + x, seg.y2 + y];
  2653. to = [seg.x + x, seg.y + y];
  2654. break;
  2655. case "Q":
  2656. p = [seg.x1, seg.y1];
  2657. p2 = toCubic([x, y], p);
  2658. p3 = toCubic([seg.x, seg.y], p);
  2659. to = [seg.x, seg.y];
  2660. break;
  2661. case "q":
  2662. p = [seg.x1 + x, seg.y1 + y];
  2663. p2 = toCubic([x, y], p);
  2664. p3 = toCubic([x + seg.x, y + seg.y], p);
  2665. to = [seg.x + x, seg.y + y];
  2666. break;
  2667. case "T":
  2668. p = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
  2669. p2 = toCubic([x, y], p);
  2670. p3 = toCubic([seg.x, seg.y], p);
  2671. to = [seg.x, seg.y];
  2672. break;
  2673. case "t":
  2674. p = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
  2675. p2 = toCubic([x, y], p);
  2676. p3 = toCubic([x + seg.x, y + seg.y], p);
  2677. to = [seg.x + x, seg.y + y];
  2678. break;
  2679. // TODO: A,a
  2680. case "Z":
  2681. case "z":
  2682. x = x0;
  2683. y = y0;
  2684. lines.push({op: "h"});
  2685. break;
  2686. }
  2687. var hasStartMarker = markerStart
  2688. && (i === 1
  2689. || ("mM".indexOf(cmd) < 0 && "mM".indexOf(list.getItem(i - 1).pathSegTypeAsLetter) >= 0));
  2690. var hasEndMarker = markerEnd
  2691. && (i === list.numberOfItems - 1
  2692. || ("mM".indexOf(cmd) < 0 && "mM".indexOf(list.getItem(i + 1).pathSegTypeAsLetter) >= 0));
  2693. var hasMidMarker = markerMid
  2694. && i > 0
  2695. && !(i === 1 && "mM".indexOf(list.getItem(i - 1).pathSegTypeAsLetter) >= 0);
  2696. if ("sScCqQtT".indexOf(cmd) >= 0) {
  2697. hasStartMarker && markers.addMarker(new Marker(markerStart, [x, y], getAngle([x, y], p2)));
  2698. hasEndMarker && markers.addMarker(new Marker(markerEnd, to, getAngle(p3, to)));
  2699. if (hasMidMarker) {
  2700. curAngle = getDirectionVector([x, y], p2);
  2701. curAngle = "mM".indexOf(list.getItem(i - 1).pathSegTypeAsLetter) >= 0 ?
  2702. curAngle : normalize(addVectors(prevAngle, curAngle));
  2703. markers.addMarker(new Marker(markerMid, [x, y], Math.atan2(curAngle[1], curAngle[0])));
  2704. }
  2705. prevAngle = getDirectionVector(p3, to);
  2706. prevX = x;
  2707. prevY = y;
  2708. if (withinClipPath) {
  2709. p2 = multVecMatrix(p2, tfMatrix);
  2710. p3 = multVecMatrix(p3, tfMatrix);
  2711. to = multVecMatrix(to, tfMatrix);
  2712. }
  2713. lines.push({
  2714. op: "c", c: [
  2715. p2[0], p2[1],
  2716. p3[0], p3[1],
  2717. to[0], to[1]
  2718. ]
  2719. });
  2720. } else if ("lLhHvVmM".indexOf(cmd) >= 0) {
  2721. curAngle = getDirectionVector([x, y], to);
  2722. hasStartMarker && markers.addMarker(new Marker(markerStart, [x, y], Math.atan2(curAngle[1], curAngle[0])));
  2723. hasEndMarker && markers.addMarker(new Marker(markerEnd, to, Math.atan2(curAngle[1], curAngle[0])));
  2724. if (hasMidMarker) {
  2725. var angle = "mM".indexOf(cmd) >= 0 ?
  2726. prevAngle : "mM".indexOf(list.getItem(i - 1).pathSegTypeAsLetter) >= 0 ?
  2727. curAngle : normalize(addVectors(prevAngle, curAngle));
  2728. markers.addMarker(new Marker(markerMid, [x, y], Math.atan2(angle[1], angle[0])));
  2729. }
  2730. prevAngle = curAngle;
  2731. if (withinClipPath) {
  2732. to = multVecMatrix(to, tfMatrix);
  2733. }
  2734. lines.push({op: op, c: to});
  2735. }
  2736. if ("MLCSQT".indexOf(cmd) >= 0) {
  2737. x = seg.x;
  2738. y = seg.y;
  2739. } else if ("mlcsqt".indexOf(cmd) >= 0) {
  2740. x = seg.x + x;
  2741. y = seg.y + y;
  2742. } else if ("zZ".indexOf(cmd) < 0) {
  2743. x = newX;
  2744. y = newY;
  2745. }
  2746. }
  2747. return {lines: lines, markers: markers};
  2748. };
  2749. var lines = getLinesFromPath();
  2750. if (lines.lines.length > 0) {
  2751. _pdf.path(lines.lines);
  2752. }
  2753. if (markerEnd || markerStart || markerMid) {
  2754. lines.markers.draw(_pdf.unitMatrix, refsHandler, attributeState);
  2755. }
  2756. };
  2757. // draws the element referenced by a use node, makes use of pdf's XObjects/FormObjects so nodes are only written once
  2758. // to the pdf document. This highly reduces the file size and computation time.
  2759. var use = function (node, tfMatrix, refsHandler) {
  2760. var url = (node.getAttribute("href") || node.getAttribute("xlink:href"));
  2761. // just in case someone has the idea to use empty use-tags, wtf???
  2762. if (!url)
  2763. return;
  2764. // get the size of the referenced form object (to apply the correct scaling)
  2765. var id = url.substring(1);
  2766. refsHandler.getRendered(id);
  2767. var formObject = _pdf.getFormObject(id);
  2768. // scale and position it right
  2769. var x = node.getAttribute("x") || 0;
  2770. var y = node.getAttribute("y") || 0;
  2771. var width = node.getAttribute("width") || formObject.width;
  2772. var height = node.getAttribute("height") || formObject.height;
  2773. var t = new _pdf.Matrix(width / formObject.width || 0, 0, 0, height / formObject.height || 0, x, y);
  2774. t = _pdf.matrixMult(t, tfMatrix);
  2775. _pdf.doFormObject(id, t);
  2776. };
  2777. // draws a line
  2778. var line = function (node, refsHandler, attributeState) {
  2779. var p1 = [parseFloat(node.getAttribute('x1') || 0), parseFloat(node.getAttribute('y1') || 0)];
  2780. var p2 = [parseFloat(node.getAttribute('x2') || 0), parseFloat(node.getAttribute('y2') || 0)];
  2781. if (attributeState.stroke !== null){
  2782. _pdf.line(p1[0], p1[1], p2[0], p2[1]);
  2783. }
  2784. var markerStart = node.getAttribute("marker-start"),
  2785. markerEnd = node.getAttribute("marker-end");
  2786. if (markerStart || markerEnd) {
  2787. var markers = new MarkerList();
  2788. var angle = getAngle(p1, p2);
  2789. if (markerStart) {
  2790. markers.addMarker(new Marker(iriReference.exec(markerStart)[1], p1, angle));
  2791. }
  2792. if (markerEnd) {
  2793. markers.addMarker(new Marker(iriReference.exec(markerEnd)[1], p2, angle));
  2794. }
  2795. markers.draw(_pdf.unitMatrix, refsHandler, attributeState);
  2796. }
  2797. };
  2798. // draws a rect
  2799. var rect = function (node) {
  2800. _pdf.roundedRect(
  2801. parseFloat(node.getAttribute('x')) || 0,
  2802. parseFloat(node.getAttribute('y')) || 0,
  2803. parseFloat(node.getAttribute('width')),
  2804. parseFloat(node.getAttribute('height')),
  2805. parseFloat(node.getAttribute('rx')) || 0,
  2806. parseFloat(node.getAttribute('ry')) || 0
  2807. );
  2808. };
  2809. // draws an ellipse
  2810. var ellipse = function (node) {
  2811. _pdf.ellipse(
  2812. parseFloat(node.getAttribute('cx')) || 0,
  2813. parseFloat(node.getAttribute('cy')) || 0,
  2814. parseFloat(node.getAttribute('rx')),
  2815. parseFloat(node.getAttribute('ry'))
  2816. );
  2817. };
  2818. // draws a circle
  2819. var circle = function (node) {
  2820. var radius = parseFloat(node.getAttribute('r')) || 0;
  2821. _pdf.ellipse(
  2822. parseFloat(node.getAttribute('cx')) || 0,
  2823. parseFloat(node.getAttribute('cy')) || 0,
  2824. radius,
  2825. radius
  2826. );
  2827. };
  2828. // applies text transformations to a text node
  2829. var transformText = function (node, text) {
  2830. var textTransform = getAttribute(node, "text-transform");
  2831. switch (textTransform) {
  2832. case "uppercase": return text.toUpperCase();
  2833. case "lowercase": return text.toLowerCase();
  2834. default: return text;
  2835. // TODO: capitalize, full-width
  2836. }
  2837. };
  2838. /**
  2839. * Canvas text measuring is a lot faster than svg measuring. However, it is inaccurate for some fonts. So test each
  2840. * font once and decide if canvas is accurate enough.
  2841. * @param {string} text
  2842. * @param {string} fontFamily
  2843. * @returns {function(string, string, string, string, string)}
  2844. */
  2845. var getMeasureFunction = (function getMeasureFunction() {
  2846. /**
  2847. * @param {string} text
  2848. * @param {string} fontFamily
  2849. * @param {string} fontSize
  2850. * @param {string} fontStyle
  2851. * @param {string} fontWeight
  2852. */
  2853. function canvasTextMeasure(text, fontFamily, fontSize, fontStyle, fontWeight) {
  2854. var canvas = document.createElement("canvas");
  2855. var context = canvas.getContext("2d");
  2856. context.font = [fontStyle, fontWeight, fontSize, fontFamily].join(" ");
  2857. return context.measureText(text).width;
  2858. }
  2859. /**
  2860. * @param {string} text
  2861. * @param {string} fontFamily
  2862. * @param {string} fontSize
  2863. * @param {string} fontStyle
  2864. * @param {string} fontWeight
  2865. */
  2866. function svgTextMeasure(text, fontFamily, fontSize, fontStyle, fontWeight) {
  2867. var textNode = document.createElementNS(svgNamespaceURI, "text");
  2868. textNode.setAttribute("font-family", fontFamily);
  2869. textNode.setAttribute("font-size", fontSize);
  2870. textNode.setAttribute("font-style", fontStyle);
  2871. textNode.setAttribute("font-weight", fontWeight);
  2872. textNode.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space", "preserve");
  2873. textNode.appendChild(document.createTextNode(text));
  2874. var svg = document.createElementNS(svgNamespaceURI, "svg");
  2875. svg.appendChild(textNode);
  2876. svg.setAttribute("visibility", "hidden");
  2877. document.body.appendChild(svg);
  2878. var width = textNode.getBBox().width;
  2879. document.body.removeChild(svg);
  2880. return width;
  2881. }
  2882. var testString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789!\"$%&/()=?'\\+*-_.:,;^}][{#~|<>";
  2883. var epsilon = 0.1;
  2884. var measureMethods = {};
  2885. return function getMeasureFunction(fontFamily) {
  2886. var method = measureMethods[fontFamily];
  2887. if (!method) {
  2888. var fontSize = "16px";
  2889. var fontStyle = "normal";
  2890. var fontWeight = "normal";
  2891. var canvasWidth = canvasTextMeasure(testString, fontFamily, fontSize, fontStyle, fontWeight);
  2892. var svgWidth = svgTextMeasure(testString, fontFamily, fontSize, fontStyle, fontWeight);
  2893. method = Math.abs(canvasWidth - svgWidth) < epsilon ? canvasTextMeasure : svgTextMeasure;
  2894. measureMethods[fontFamily] = method;
  2895. }
  2896. return method;
  2897. }
  2898. })();
  2899. /**
  2900. * @param {string} text
  2901. * @param {AttributeState} attributeState
  2902. * @returns {number}
  2903. */
  2904. function measureTextWidth(text, attributeState) {
  2905. if (text.length === 0) {
  2906. return 0;
  2907. }
  2908. var fontFamily = attributeState.fontFamily;
  2909. var measure = getMeasureFunction(fontFamily);
  2910. return measure(text, attributeState.fontFamily, attributeState.fontSize + "px", attributeState.fontStyle, attributeState.fontWeight);
  2911. }
  2912. /**
  2913. * @param {string} text
  2914. * @param {AttributeState} attributeState
  2915. * @returns {number}
  2916. */
  2917. function getTextOffset(text, attributeState) {
  2918. var textAnchor = attributeState.textAnchor;
  2919. if (textAnchor === "start") {
  2920. return 0;
  2921. }
  2922. var width = measureTextWidth(text, attributeState);
  2923. var xOffset = 0;
  2924. switch (textAnchor) {
  2925. case "end":
  2926. xOffset = width;
  2927. break;
  2928. case "middle":
  2929. xOffset = width / 2;
  2930. break;
  2931. }
  2932. return xOffset;
  2933. }
  2934. /**
  2935. * @param {string} textAnchor
  2936. * @param {number} originX
  2937. * @param {number} originY
  2938. * @constructor
  2939. */
  2940. function TextChunk(textAnchor, originX, originY) {
  2941. this.texts = [];
  2942. this.textNodes = [];
  2943. this.textAnchor = textAnchor;
  2944. this.originX = originX;
  2945. this.originY = originY;
  2946. }
  2947. /**
  2948. * @param {SVGElement} tSpan
  2949. * @param {string} text
  2950. */
  2951. TextChunk.prototype.add = function(tSpan, text) {
  2952. this.texts.push(text);
  2953. this.textNodes.push(tSpan);
  2954. };
  2955. /**
  2956. * Outputs the chunk to pdf.
  2957. * @param {jsPDF.Matrix} transform
  2958. * @param {AttributeState} attributeState
  2959. * @returns {[number, number]} The last current text position.
  2960. */
  2961. TextChunk.prototype.put = function (transform, attributeState) {
  2962. var i, textNode;
  2963. var xs = [], ys = [], attributeStates = [];
  2964. var currentTextX = this.originX, currentTextY = this.originY;
  2965. var minX = currentTextX, maxX = currentTextX;
  2966. for (i = 0; i < this.textNodes.length; i++) {
  2967. textNode = this.textNodes[i];
  2968. var x = currentTextX;
  2969. var y = currentTextY;
  2970. if (textNode.nodeName === "#text") {
  2971. textNodeAttributeState = attributeState
  2972. } else {
  2973. var textNodeAttributeState = attributeState.clone();
  2974. var tSpanColor = getAttribute(textNode, "fill");
  2975. setTextProperties(textNode, tSpanColor && new RGBColor(tSpanColor), textNodeAttributeState);
  2976. var tSpanDx = textNode.getAttribute("dx");
  2977. if (tSpanDx !== null) {
  2978. x += toPixels(tSpanDx, textNodeAttributeState.fontSize);
  2979. }
  2980. var tSpanDy = textNode.getAttribute("dy");
  2981. if (tSpanDy !== null) {
  2982. y += toPixels(tSpanDy, textNodeAttributeState.fontSize);
  2983. }
  2984. }
  2985. attributeStates[i] = textNodeAttributeState;
  2986. xs[i] = x;
  2987. ys[i] = y;
  2988. currentTextX = x + measureTextWidth(this.texts[i], textNodeAttributeState);
  2989. currentTextY = y;
  2990. minX = Math.min(minX, x);
  2991. maxX = Math.max(maxX, currentTextX);
  2992. }
  2993. var textOffset;
  2994. switch (this.textAnchor) {
  2995. case "start": textOffset = 0; break;
  2996. case "middle": textOffset = (maxX - minX) / 2; break;
  2997. case "end": textOffset = maxX - minX; break;
  2998. }
  2999. for (i = 0; i < this.textNodes.length; i++) {
  3000. textNode = this.textNodes[i];
  3001. if (textNode.nodeName !== "#text") {
  3002. var tSpanVisibility = getAttribute(textNode, "visibility") || attributeState.visibility;
  3003. if (tSpanVisibility === "hidden") {
  3004. continue;
  3005. }
  3006. }
  3007. _pdf.saveGraphicsState();
  3008. putTextProperties(attributeStates[i], attributeState);
  3009. _pdf.text(xs[i] - textOffset, ys[i], this.texts[i], void 0, transform);
  3010. _pdf.restoreGraphicsState();
  3011. }
  3012. return [currentTextX, currentTextY];
  3013. };
  3014. /**
  3015. * Convert em, px and bare number attributes to pixel values
  3016. * @param {string} value
  3017. * @param {number} pdfFontSize
  3018. */
  3019. function toPixels(value, pdfFontSize) {
  3020. var match;
  3021. // em
  3022. match = value && value.toString().match(/^([\-0-9.]+)em$/);
  3023. if (match) {
  3024. return parseFloat(match[1]) * pdfFontSize;
  3025. }
  3026. // pixels
  3027. match = value && value.toString().match(/^([\-0-9.]+)(px|)$/);
  3028. if (match) {
  3029. return parseFloat(match[1]);
  3030. }
  3031. return 0;
  3032. }
  3033. function transformXmlSpace(trimmedText, attributeState) {
  3034. trimmedText = removeNewlines(trimmedText);
  3035. trimmedText = replaceTabsBySpace(trimmedText);
  3036. if (attributeState.xmlSpace === "default") {
  3037. trimmedText = trimmedText.trim();
  3038. trimmedText = consolidateSpaces(trimmedText);
  3039. }
  3040. return trimmedText;
  3041. }
  3042. /**
  3043. * Draws a text element and its tspan children.
  3044. * @param {SVGElement} node
  3045. * @param {jsPDF.Matrix} tfMatrix
  3046. * @param {boolean} hasFillColor
  3047. * @param {RGBColor} fillRGB
  3048. * @param {AttributeState} attributeState
  3049. */
  3050. var text = function (node, tfMatrix, hasFillColor, fillRGB, attributeState) {
  3051. _pdf.saveGraphicsState();
  3052. var dx, dy, xOffset = 0;
  3053. var pdfFontSize = _pdf.getFontSize();
  3054. var textX = toPixels(node.getAttribute('x'), pdfFontSize);
  3055. var textY = toPixels(node.getAttribute('y'), pdfFontSize);
  3056. dx = toPixels(node.getAttribute("dx"), pdfFontSize);
  3057. dy = toPixels(node.getAttribute("dy"), pdfFontSize);
  3058. var visibility = attributeState.visibility;
  3059. // when there are no tspans draw the text directly
  3060. var tSpanCount = node.childElementCount;
  3061. if (tSpanCount === 0) {
  3062. var trimmedText = transformXmlSpace(node.textContent, attributeState);
  3063. var transformedText = transformText(node, trimmedText);
  3064. xOffset = getTextOffset(transformedText, attributeState);
  3065. if (visibility === "visible") {
  3066. _pdf.text(
  3067. textX + dx - xOffset,
  3068. textY + dy,
  3069. transformedText,
  3070. void 0,
  3071. tfMatrix
  3072. );
  3073. }
  3074. } else {
  3075. // otherwise loop over tspans and position each relative to the previous one
  3076. var currentTextSegment = new TextChunk(attributeState.textAnchor, textX + dx, textY + dy);
  3077. for (var i = 0; i < node.childNodes.length; i++) {
  3078. var textNode = node.childNodes[i];
  3079. if (!textNode.textContent) {
  3080. continue;
  3081. }
  3082. var xmlSpace = attributeState.xmlSpace;
  3083. if (textNode.nodeName === "#text") {
  3084. } else if (nodeIs(textNode, "tspan")) {
  3085. var tSpan = textNode;
  3086. var lastPositions;
  3087. var tSpanAbsX = tSpan.getAttribute("x");
  3088. if (tSpanAbsX !== null) {
  3089. var x = toPixels(tSpanAbsX, pdfFontSize);
  3090. lastPositions = currentTextSegment.put(tfMatrix, attributeState);
  3091. currentTextSegment = new TextChunk(tSpan.getAttribute("text-anchor") || attributeState.textAnchor, x, lastPositions[1]);
  3092. }
  3093. var tSpanAbsY = tSpan.getAttribute("y");
  3094. if (tSpanAbsY !== null) {
  3095. var y = toPixels(tSpanAbsY, pdfFontSize);
  3096. lastPositions = currentTextSegment.put(tfMatrix, attributeState);
  3097. currentTextSegment = new TextChunk(tSpan.getAttribute("text-anchor") || attributeState.textAnchor, lastPositions[0], y);
  3098. }
  3099. var tSpanXmlSpace = tSpan.getAttribute("xml:space");
  3100. if (tSpanXmlSpace) {
  3101. xmlSpace = tSpanXmlSpace;
  3102. }
  3103. }
  3104. trimmedText = textNode.textContent;
  3105. trimmedText = removeNewlines(trimmedText);
  3106. trimmedText = replaceTabsBySpace(trimmedText);
  3107. if (xmlSpace === "default") {
  3108. if (i === 0) {
  3109. trimmedText = trimLeft(trimmedText);
  3110. }
  3111. if (i === tSpanCount - 1) {
  3112. trimmedText = trimRight(trimmedText);
  3113. }
  3114. trimmedText = consolidateSpaces(trimmedText);
  3115. }
  3116. transformedText = transformText(node, trimmedText);
  3117. currentTextSegment.add(textNode, transformedText);
  3118. }
  3119. currentTextSegment.put(tfMatrix, attributeState);
  3120. }
  3121. _pdf.restoreGraphicsState();
  3122. };
  3123. // renders all children of a node
  3124. var renderChildren = function (node, tfMatrix, refsHandler, withinDefs, withinClipPath, attributeState) {
  3125. forEachChild(node, function (i, node) {
  3126. renderNode(node, tfMatrix, refsHandler, withinDefs, withinClipPath, attributeState);
  3127. });
  3128. };
  3129. // adds a gradient to defs and the pdf document for later use, type is either "axial" or "radial"
  3130. // opacity is only supported rudimentary by averaging over all stops
  3131. // transforms are applied on use
  3132. var putGradient = function (node, type, coords) {
  3133. var colors = [];
  3134. var opacitySum = 0;
  3135. var hasOpacity = false;
  3136. var gState;
  3137. forEachChild(node, function (i, element) {
  3138. // since opacity gradients are hard to realize, average the opacity over the control points
  3139. if (element.tagName.toLowerCase() === "stop") {
  3140. var color = new RGBColor(getAttribute(element, "stop-color"));
  3141. colors.push({
  3142. offset: parseFloat(element.getAttribute("offset")),
  3143. color: [color.r, color.g, color.b]
  3144. });
  3145. var opacity = getAttribute(element, "stop-opacity");
  3146. if (opacity && opacity != 1) {
  3147. opacitySum += parseFloat(opacity);
  3148. hasOpacity = true;
  3149. }
  3150. }
  3151. });
  3152. if (hasOpacity) {
  3153. gState = new _pdf.GState({opacity: opacitySum / colors.length});
  3154. }
  3155. var pattern = new _pdf.ShadingPattern(type, coords, colors, gState);
  3156. var id = node.getAttribute("id");
  3157. _pdf.addShadingPattern(id, pattern);
  3158. };
  3159. var pattern = function (node, refsHandler, attributeState) {
  3160. var id = node.getAttribute("id");
  3161. // the transformations directly at the node are written to the pattern transformation matrix
  3162. var bBox = getUntransformedBBox(node);
  3163. var pattern = new _pdf.TilingPattern([bBox[0], bBox[1], bBox[0] + bBox[2], bBox[1] + bBox[3]], bBox[2], bBox[3],
  3164. null, _pdf.unitMatrix /* this parameter is ignored !*/);
  3165. _pdf.beginTilingPattern(pattern);
  3166. // continue without transformation
  3167. renderChildren(node, _pdf.unitMatrix, refsHandler, false, false, attributeState);
  3168. _pdf.endTilingPattern(id, pattern);
  3169. };
  3170. var fontAliases = {
  3171. "sans-serif": "helvetica",
  3172. "verdana": "helvetica",
  3173. "arial": "helvetica",
  3174. "fixed": "courier",
  3175. "monospace": "courier",
  3176. "terminal": "courier",
  3177. "serif": "times",
  3178. "cursive": "times",
  3179. "fantasy": "times"
  3180. };
  3181. /**
  3182. * @param {AttributeState} attributeState
  3183. * @param {string[]} fontFamilies
  3184. * @return {string}
  3185. */
  3186. function findFirstAvailableFontFamily(attributeState, fontFamilies) {
  3187. var fontType = "";
  3188. if (attributeState.fontWeight === "bold") {
  3189. fontType = "bold";
  3190. }
  3191. if (attributeState.fontStyle === "italic") {
  3192. fontType += "italic";
  3193. }
  3194. if (fontType === "") {
  3195. fontType = "normal";
  3196. }
  3197. var availableFonts = _pdf.getFontList();
  3198. var firstAvailable = "";
  3199. var fontIsAvailable = fontFamilies.some(function (font) {
  3200. var availableStyles = availableFonts[font];
  3201. if (availableStyles && availableStyles.indexOf(fontType) >= 0) {
  3202. firstAvailable = font;
  3203. return true;
  3204. }
  3205. font = font.toLowerCase();
  3206. if (fontAliases.hasOwnProperty(font)) {
  3207. firstAvailable = font;
  3208. return true;
  3209. }
  3210. return false;
  3211. });
  3212. if (!fontIsAvailable) {
  3213. firstAvailable = "times";
  3214. }
  3215. return firstAvailable;
  3216. }
  3217. function setTextProperties(node, fillRGB, attributeState) {
  3218. if (fillRGB && fillRGB.ok) {
  3219. attributeState.fill = fillRGB;
  3220. }
  3221. var fontWeight = getAttribute(node, "font-weight");
  3222. if (fontWeight) {
  3223. attributeState.fontWeight = fontWeight;
  3224. }
  3225. var fontStyle = getAttribute(node, "font-style");
  3226. if (fontStyle) {
  3227. attributeState.fontStyle = fontStyle;
  3228. }
  3229. var fontFamily = getAttribute(node, "font-family");
  3230. if (fontFamily) {
  3231. var fontFamilies = FontFamily.parse(fontFamily);
  3232. attributeState.fontFamily = findFirstAvailableFontFamily(attributeState, fontFamilies);
  3233. }
  3234. var fontSize = getAttribute(node, "font-size");
  3235. if (fontSize) {
  3236. attributeState.fontSize = parseFloat(fontSize);
  3237. }
  3238. var textAnchor = getAttribute(node, "text-anchor");
  3239. if (textAnchor) {
  3240. attributeState.textAnchor = textAnchor;
  3241. }
  3242. }
  3243. /**
  3244. * @param {AttributeState} attributeState
  3245. * @param {AttributeState} parentAttributeState
  3246. */
  3247. function putTextProperties(attributeState, parentAttributeState) {
  3248. if (attributeState.fontFamily !== parentAttributeState.fontFamily) {
  3249. if (fontAliases.hasOwnProperty(attributeState.fontFamily)) {
  3250. _pdf.setFont(fontAliases[attributeState.fontFamily]);
  3251. } else {
  3252. _pdf.setFont(attributeState.fontFamily);
  3253. }
  3254. }
  3255. if (attributeState.fill !== parentAttributeState.fill && attributeState.fill.ok) {
  3256. var fillRGB = attributeState.fill;
  3257. _pdf.setTextColor(fillRGB.r, fillRGB.g, fillRGB.b);
  3258. }
  3259. if (attributeState.fontWeight !== parentAttributeState.fontWeight
  3260. || attributeState.fontStyle !== parentAttributeState.fontStyle) {
  3261. var fontType = "";
  3262. if (attributeState.fontWeight === "bold") {
  3263. fontType = "bold";
  3264. }
  3265. if (attributeState.fontStyle === "italic") {
  3266. fontType += "italic";
  3267. }
  3268. if (fontType === "") {
  3269. fontType = "normal";
  3270. }
  3271. _pdf.setFontType(fontType);
  3272. }
  3273. if (attributeState.fontSize !== parentAttributeState.fontSize) {
  3274. _pdf.setFontSize(attributeState.fontSize);
  3275. }
  3276. }
  3277. /**
  3278. * Renders a svg node.
  3279. * @param node The svg element
  3280. * @param contextTransform The current transformation matrix
  3281. * @param refsHandler The handler that will render references on demand
  3282. * @param withinDefs True iff we are top-level within a defs node, so the target can be switched to an pdf form object
  3283. * @param {boolean} withinClipPath
  3284. * @param {AttributeState} attributeState Keeps track of parent attributes that are inherited automatically
  3285. */
  3286. var renderNode = function (node, contextTransform, refsHandler, withinDefs, withinClipPath, attributeState) {
  3287. var parentAttributeState = attributeState;
  3288. attributeState = attributeState.clone();
  3289. if (nodeIs(node, "defs,clippath,pattern,lineargradient,radialgradient,marker")) {
  3290. // we will only render them on demand
  3291. return;
  3292. }
  3293. if (getAttribute(node, "display") === "none") {
  3294. return;
  3295. }
  3296. var visibility = attributeState.visibility = getAttribute(node, "visibility") || attributeState.visibility;
  3297. if (visibility === "hidden" && !nodeIs(node, "svg,g,marker,a,pattern,defs,text")) {
  3298. return;
  3299. }
  3300. var tfMatrix,
  3301. hasFillColor = false,
  3302. fillRGB = null,
  3303. fill = "inherit",
  3304. stroke = "inherit",
  3305. patternOrGradient = undefined,
  3306. bBox;
  3307. //
  3308. // Decide about the render target and set the correct transformation
  3309. //
  3310. // if we are within a defs node, start a new pdf form object and draw this node and all children on that instead
  3311. // of the top-level page
  3312. var targetIsFormObject = withinDefs && !nodeIs(node, "lineargradient,radialgradient,pattern,clippath");
  3313. if (targetIsFormObject) {
  3314. // the transformations directly at the node are written to the pdf form object transformation matrix
  3315. tfMatrix = computeNodeTransform(node);
  3316. bBox = getUntransformedBBox(node);
  3317. _pdf.beginFormObject(bBox[0], bBox[1], bBox[2], bBox[3], tfMatrix);
  3318. // continue without transformation and set withinDefs to false to prevent child nodes from starting new form objects
  3319. tfMatrix = _pdf.unitMatrix;
  3320. withinDefs = false;
  3321. } else {
  3322. tfMatrix = _pdf.matrixMult(computeNodeTransform(node), contextTransform);
  3323. if (!withinClipPath) {
  3324. _pdf.saveGraphicsState();
  3325. }
  3326. }
  3327. var hasClipPath = node.hasAttribute("clip-path") && node.getAttribute("clip-path") !== "none";
  3328. if (hasClipPath) {
  3329. var clipPathId = iriReference.exec(node.getAttribute("clip-path"));
  3330. var clipPathNode = refsHandler.getRendered(clipPathId[1]);
  3331. var clipPathMatrix = tfMatrix;
  3332. if (clipPathNode.hasAttribute("clipPathUnits")
  3333. && clipPathNode.getAttribute("clipPathUnits").toLowerCase() === "objectboundingbox") {
  3334. bBox = getUntransformedBBox(node);
  3335. clipPathMatrix = _pdf.matrixMult(new _pdf.Matrix(bBox[2], 0, 0, bBox[3], bBox[0], bBox[1]), clipPathMatrix);
  3336. }
  3337. // here, browsers show different results for a "transform" attribute on the clipPath element itself:
  3338. // IE/Edge considers it, Chrome and Firefox ignore it. However, the specification lists "transform" as a valid
  3339. // attribute for clipPath elements, although not explicitly explaining its behavior. This implementation follows
  3340. // IE/Edge and considers the "transform" attribute as additional transformation within the coordinate system
  3341. // established by the "clipPathUnits" attribute.
  3342. clipPathMatrix = _pdf.matrixMult(computeNodeTransform(clipPathNode), clipPathMatrix);
  3343. _pdf.saveGraphicsState();
  3344. _pdf.setCurrentTransformationMatrix(clipPathMatrix);
  3345. renderChildren(clipPathNode, _pdf.unitMatrix, refsHandler, false, true, attributeState);
  3346. _pdf.clip().discardPath();
  3347. // as we cannot use restoreGraphicsState() to reset the transform (this would reset the clipping path, as well),
  3348. // we must append the inverse instead
  3349. _pdf.setCurrentTransformationMatrix(clipPathMatrix.inversed());
  3350. }
  3351. //
  3352. // extract fill and stroke mode
  3353. //
  3354. // fill mode
  3355. if (nodeIs(node, "g,path,rect,text,ellipse,line,circle,polygon,polyline")) {
  3356. function setDefaultColor() {
  3357. fillRGB = new RGBColor("rgb(0, 0, 0)");
  3358. hasFillColor = true;
  3359. fill = true;
  3360. }
  3361. var fillColor = getAttribute(node, "fill");
  3362. if (fillColor) {
  3363. var url = iriReference.exec(fillColor);
  3364. if (url) {
  3365. // probably a gradient or pattern (or something unsupported)
  3366. var fillUrl = url[1];
  3367. var fillNode = refsHandler.getRendered(fillUrl);
  3368. if (fillNode && nodeIs(fillNode, "lineargradient,radialgradient")) {
  3369. // matrix to convert between gradient space and user space
  3370. // for "userSpaceOnUse" this is the current transformation: tfMatrix
  3371. // for "objectBoundingBox" or default, the gradient gets scaled and transformed to the bounding box
  3372. var gradientUnitsMatrix;
  3373. if (!fillNode.hasAttribute("gradientUnits")
  3374. || fillNode.getAttribute("gradientUnits").toLowerCase() === "objectboundingbox") {
  3375. bBox || (bBox = getUntransformedBBox(node));
  3376. gradientUnitsMatrix = new _pdf.Matrix(bBox[2], 0, 0, bBox[3], bBox[0], bBox[1]);
  3377. } else {
  3378. gradientUnitsMatrix = _pdf.unitMatrix;
  3379. }
  3380. // matrix that is applied to the gradient before any other transformations
  3381. var gradientTransform = parseTransform(fillNode.getAttribute("gradientTransform"));
  3382. patternOrGradient = {
  3383. key: fillUrl,
  3384. matrix: _pdf.matrixMult(gradientTransform, gradientUnitsMatrix)
  3385. };
  3386. fill = true;
  3387. } else if (fillNode && nodeIs(fillNode, "pattern")) {
  3388. var fillBBox, y, width, height, x;
  3389. patternOrGradient = { key: fillUrl };
  3390. var patternUnitsMatrix = _pdf.unitMatrix;
  3391. if (!fillNode.hasAttribute("patternUnits")
  3392. || fillNode.getAttribute("patternUnits").toLowerCase() === "objectboundingbox") {
  3393. bBox || (bBox = getUntransformedBBox(node));
  3394. patternUnitsMatrix = new _pdf.Matrix(1, 0, 0, 1, bBox[0], bBox[1]);
  3395. // TODO: slightly inaccurate (rounding errors? line width bBoxes?)
  3396. fillBBox = getUntransformedBBox(fillNode);
  3397. x = fillBBox[0] * bBox[0];
  3398. y = fillBBox[1] * bBox[1];
  3399. width = fillBBox[2] * bBox[2];
  3400. height = fillBBox[3] * bBox[3];
  3401. patternOrGradient.boundingBox = [x, y, x + width, y + height];
  3402. patternOrGradient.xStep = width;
  3403. patternOrGradient.yStep = height;
  3404. }
  3405. var patternContentUnitsMatrix = _pdf.unitMatrix;
  3406. if (fillNode.hasAttribute("patternContentUnits")
  3407. && fillNode.getAttribute("patternContentUnits").toLowerCase() === "objectboundingbox") {
  3408. bBox || (bBox = getUntransformedBBox(node));
  3409. patternContentUnitsMatrix = new _pdf.Matrix(bBox[2], 0, 0, bBox[3], 0, 0);
  3410. fillBBox = patternOrGradient.boundingBox || getUntransformedBBox(fillNode);
  3411. x = fillBBox[0] / bBox[0];
  3412. y = fillBBox[1] / bBox[1];
  3413. width = fillBBox[2] / bBox[2];
  3414. height = fillBBox[3] / bBox[3];
  3415. patternOrGradient.boundingBox = [x, y, x + width, y + height];
  3416. patternOrGradient.xStep = width;
  3417. patternOrGradient.yStep = height;
  3418. }
  3419. var patternTransformMatrix = _pdf.unitMatrix;
  3420. if (fillNode.hasAttribute("patternTransform")) {
  3421. patternTransformMatrix = parseTransform(fillNode.getAttribute("patternTransform"));
  3422. }
  3423. var matrix = patternContentUnitsMatrix;
  3424. matrix = _pdf.matrixMult(matrix, patternUnitsMatrix);
  3425. matrix = _pdf.matrixMult(matrix, patternTransformMatrix);
  3426. matrix = _pdf.matrixMult(matrix, tfMatrix);
  3427. patternOrGradient.matrix = matrix;
  3428. fill = true;
  3429. } else {
  3430. // unsupported fill argument -> fill black
  3431. setDefaultColor();
  3432. }
  3433. } else {
  3434. // plain color
  3435. fillRGB = parseColor(fillColor);
  3436. if (fillRGB.ok) {
  3437. hasFillColor = true;
  3438. fill = true;
  3439. } else {
  3440. fill = false;
  3441. }
  3442. }
  3443. }
  3444. // opacity is realized via a pdf graphics state
  3445. var fillOpacity = 1.0, strokeOpacity = 1.0;
  3446. var nodeFillOpacity = getAttribute(node, "fill-opacity");
  3447. if (nodeFillOpacity) {
  3448. fillOpacity *= parseFloat(nodeFillOpacity);
  3449. }
  3450. if (fillRGB && typeof fillRGB.a === "number") {
  3451. fillOpacity *= fillRGB.a;
  3452. }
  3453. var nodeStrokeOpacity = getAttribute(node, "stroke-opacity");
  3454. if (nodeStrokeOpacity) {
  3455. strokeOpacity *= parseFloat(nodeStrokeOpacity);
  3456. }
  3457. if (strokeRGB && typeof strokeRGB.a === "number") {
  3458. strokeOpacity *= strokeRGB.a;
  3459. }
  3460. var nodeOpacity = getAttribute(node, "opacity");
  3461. if (nodeOpacity) {
  3462. var opacity = parseFloat(nodeOpacity);
  3463. strokeOpacity *= opacity;
  3464. fillOpacity *= opacity;
  3465. }
  3466. var hasFillOpacity = fillOpacity < 1.0;
  3467. var hasStrokeOpacity = strokeOpacity < 1.0;
  3468. if (hasFillOpacity || hasStrokeOpacity) {
  3469. var gState = {};
  3470. hasFillOpacity && (gState["opacity"] = fillOpacity);
  3471. hasStrokeOpacity && (gState["stroke-opacity"] = strokeOpacity);
  3472. _pdf.setGState(new _pdf.GState(gState));
  3473. }
  3474. }
  3475. if (nodeIs(node, "g,path,rect,ellipse,line,circle,polygon,polyline")) {
  3476. // text has no fill color, so don't apply it until here
  3477. if (hasFillColor) {
  3478. attributeState.fill = fillRGB;
  3479. _pdf.setFillColor(fillRGB.r, fillRGB.g, fillRGB.b);
  3480. }
  3481. // stroke mode
  3482. var strokeColor = getAttribute(node, "stroke");
  3483. if (strokeColor) {
  3484. var strokeWidth = getAttribute(node, "stroke-width");
  3485. if (strokeWidth !== void 0 && strokeWidth !== "") {
  3486. strokeWidth = Math.abs(parseFloat(strokeWidth));
  3487. attributeState.strokeWidth = strokeWidth;
  3488. _pdf.setLineWidth(strokeWidth);
  3489. } else {
  3490. // needed for inherited zero width strokes
  3491. strokeWidth = attributeState.strokeWidth
  3492. }
  3493. var strokeRGB = new RGBColor(strokeColor);
  3494. if (strokeRGB.ok) {
  3495. attributeState.stroke = strokeRGB;
  3496. _pdf.setDrawColor(strokeRGB.r, strokeRGB.g, strokeRGB.b);
  3497. // pdf spec states: "A line width of 0 denotes the thinnest line that can be rendered at device resolution:
  3498. // 1 device pixel wide". SVG, however, does not draw zero width lines.
  3499. stroke = strokeWidth !== 0;
  3500. }
  3501. var lineCap = getAttribute(node, "stroke-linecap");
  3502. if (lineCap) {
  3503. _pdf.setLineCap(attributeState.strokeLinecap = lineCap);
  3504. }
  3505. var lineJoin = getAttribute(node, "stroke-linejoin");
  3506. if (lineJoin) {
  3507. _pdf.setLineJoin(attributeState.strokeLinejoin = lineJoin);
  3508. }
  3509. var dashArray = getAttribute(node, "stroke-dasharray");
  3510. if (dashArray) {
  3511. dashArray = parseFloats(dashArray);
  3512. var dashOffset = parseInt(getAttribute(node, "stroke-dashoffset")) || 0;
  3513. attributeState.strokeDasharray = dashArray;
  3514. attributeState.strokeDashoffset = dashOffset;
  3515. _pdf.setLineDashPattern(dashArray, dashOffset);
  3516. }
  3517. var miterLimit = getAttribute(node, "stroke-miterlimit");
  3518. if (miterLimit !== void 0 && miterLimit !== "") {
  3519. _pdf.setLineMiterLimit(attributeState.strokeMiterlimit = parseFloat(miterLimit));
  3520. }
  3521. }
  3522. }
  3523. // inherit fill and stroke mode if not specified at this node
  3524. if (fill === "inherit") {
  3525. fill = attributeState.fill !== null;
  3526. }
  3527. if (stroke === "inherit") {
  3528. stroke = attributeState.stroke !== null;
  3529. }
  3530. var xmlSpace = node.getAttribute("xml:space");
  3531. if (xmlSpace) {
  3532. attributeState.xmlSpace = xmlSpace;
  3533. }
  3534. setTextProperties(node, fillRGB, attributeState);
  3535. putTextProperties(attributeState, parentAttributeState);
  3536. // do the actual drawing
  3537. switch (node.tagName.toLowerCase()) {
  3538. case 'svg':
  3539. case 'g':
  3540. case 'a':
  3541. renderChildren(node, tfMatrix, refsHandler, withinDefs, false, attributeState);
  3542. break;
  3543. case 'use':
  3544. use(node, tfMatrix, refsHandler);
  3545. break;
  3546. case 'line':
  3547. if (!withinClipPath) {
  3548. _pdf.setCurrentTransformationMatrix(tfMatrix);
  3549. line(node, refsHandler, attributeState);
  3550. }
  3551. break;
  3552. case 'rect':
  3553. if (!withinClipPath) {
  3554. _pdf.setCurrentTransformationMatrix(tfMatrix);
  3555. }
  3556. rect(node);
  3557. break;
  3558. case 'ellipse':
  3559. if (!withinClipPath) {
  3560. _pdf.setCurrentTransformationMatrix(tfMatrix);
  3561. }
  3562. ellipse(node);
  3563. break;
  3564. case 'circle':
  3565. if (!withinClipPath) {
  3566. _pdf.setCurrentTransformationMatrix(tfMatrix);
  3567. }
  3568. circle(node);
  3569. break;
  3570. case 'text':
  3571. text(node, tfMatrix, hasFillColor, fillRGB, attributeState);
  3572. break;
  3573. case 'path':
  3574. if (!withinClipPath) {
  3575. _pdf.setCurrentTransformationMatrix(tfMatrix);
  3576. }
  3577. path(node, tfMatrix, refsHandler, withinClipPath, attributeState);
  3578. break;
  3579. case 'polygon':
  3580. case 'polyline':
  3581. if (!withinClipPath) {
  3582. _pdf.setCurrentTransformationMatrix(tfMatrix);
  3583. }
  3584. polygon(node, refsHandler, attributeState, node.tagName.toLowerCase() === "polygon");
  3585. break;
  3586. case 'image':
  3587. _pdf.setCurrentTransformationMatrix(tfMatrix);
  3588. image(node);
  3589. break;
  3590. }
  3591. if (nodeIs(node, "path,rect,ellipse,circle,polygon,polyline") && !withinClipPath) {
  3592. if (fill && stroke) {
  3593. _pdf.fillStroke(patternOrGradient);
  3594. } else if (fill) {
  3595. _pdf.fill(patternOrGradient);
  3596. } else if (stroke) {
  3597. _pdf.stroke();
  3598. } else {
  3599. _pdf.discardPath();
  3600. }
  3601. }
  3602. // close either the formObject or the graphics context
  3603. if (targetIsFormObject) {
  3604. _pdf.endFormObject(node.getAttribute("id"));
  3605. } else if (!withinClipPath) {
  3606. _pdf.restoreGraphicsState();
  3607. }
  3608. if (hasClipPath) {
  3609. _pdf.restoreGraphicsState();
  3610. }
  3611. };
  3612. // the actual svgToPdf function (see above)
  3613. var svg2pdf = function (element, pdf, options) {
  3614. _pdf = pdf;
  3615. var k = options.scale || 1.0,
  3616. xOffset = options.xOffset || 0.0,
  3617. yOffset = options.yOffset || 0.0;
  3618. _pdf.advancedAPI(function () {
  3619. // set offsets and scale everything by k
  3620. _pdf.saveGraphicsState();
  3621. _pdf.setCurrentTransformationMatrix(new _pdf.Matrix(k, 0, 0, k, xOffset, yOffset));
  3622. // set default values that differ from pdf defaults
  3623. var attributeState = AttributeState.default();
  3624. _pdf.setLineWidth(attributeState.strokeWidth);
  3625. var fill = attributeState.fill;
  3626. _pdf.setFillColor(fill.r, fill.g, fill.b);
  3627. _pdf.setFont(attributeState.fontFamily);
  3628. _pdf.setFontSize(attributeState.fontSize);
  3629. var refsHandler = new ReferencesHandler(element);
  3630. renderNode(element.cloneNode(true), _pdf.unitMatrix, refsHandler, false, false, attributeState);
  3631. _pdf.restoreGraphicsState();
  3632. });
  3633. return _pdf;
  3634. };
  3635. if (typeof define === "function" && define.amd) {
  3636. define(["./rgbcolor", "SvgPath", "font-family", "cssesc"], function (rgbcolor, svgpath, fontFamily, cssesc) {
  3637. RGBColor = rgbcolor;
  3638. SvgPath = svgpath;
  3639. FontFamily = fontFamily;
  3640. cssEsc = cssesc;
  3641. return svg2pdf;
  3642. });
  3643. } else if (typeof module !== "undefined" && module.exports) {
  3644. RGBColor = require("./rgbcolor.js");
  3645. SvgPath = require("SvgPath");
  3646. FontFamily = require("font-family");
  3647. cssEsc = require("cssesc");
  3648. module.exports = svg2pdf;
  3649. } else {
  3650. SvgPath = global.SvgPath;
  3651. RGBColor = global.RGBColor;
  3652. FontFamily = global.FontFamily;
  3653. cssEsc = global.cssesc;
  3654. global.svg2pdf = svg2pdf;
  3655. // for compatibility reasons
  3656. global.svgElementToPdf = svg2pdf;
  3657. }
  3658. return svg2pdf;
  3659. }(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this));
  3660. },{"./rgbcolor.js":10,"SvgPath":1,"cssesc":8,"font-family":9}]},{},[11])(11)
  3661. });
  3662. //# sourceMappingURL=svg2pdf.js.map