PPT.vue 166 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082
  1. <!--
  2. * @Author: LiZhiWei
  3. * @Date: 2025-04-10 14:38:27
  4. * @LastEditors: LiZhiWei
  5. * @LastEditTime: 2025-04-29 10:25:59
  6. * @Description:
  7. -->
  8. <template>
  9. <div id="pptx-container" ref="pptxContainer" class="pptx-container"></div>
  10. </template>
  11. <script setup>
  12. import { ref, watch, onMounted } from "vue"
  13. const props = defineProps({
  14. pptxJson: Object,
  15. })
  16. const pptxContainer = ref(null)
  17. // 渲染幻灯片
  18. const renderSlides = () => {
  19. console.log("props.pptxJson", props.pptxJson)
  20. if (!pptxContainer.value || !props.pptxJson) return
  21. pptxContainer.value.innerHTML = ""
  22. const { size, slides } = props.pptxJson
  23. slides.forEach((slide, index) => {
  24. const slideElement = createSlideElement(size.width, size.height)
  25. applySlideBackground(slideElement, slide.fill)
  26. if (slide.layoutElements && Array.isArray(slide.layoutElements)) {
  27. processElements(slide.layoutElements, index + 1)
  28. slide.layoutElements.forEach((element) => {
  29. const el = createElementByType(element)
  30. if (!el) return
  31. slideElement.appendChild(el)
  32. })
  33. }
  34. // 渲染幻灯片元素
  35. if (slide.elements && Array.isArray(slide.elements)) {
  36. processElements(slide.elements, index + 1)
  37. slide.elements.forEach((element) => {
  38. const el = createElementByType(element)
  39. if (!el) return
  40. slideElement.appendChild(el)
  41. })
  42. }
  43. // 添加幻灯片到容器
  44. pptxContainer.value.appendChild(slideElement)
  45. })
  46. // 为所有p标签应用样式
  47. const pTags = pptxContainer.value.querySelectorAll("p")
  48. pTags.forEach((p) => {
  49. p.style.margin = "0px"
  50. p.style.padding = "0px"
  51. p.style.wordBreak = "break-word"
  52. p.style.lineHeight = "1"
  53. })
  54. const ulTags = pptxContainer.value.querySelectorAll("ul")
  55. ulTags.forEach((ul) => {
  56. ul.style.wordBreak = "break-word"
  57. ul.style.lineHeight = "1"
  58. ul.style.padding = "auto 0px"
  59. ul.style.margin = "0px"
  60. })
  61. const olTags = pptxContainer.value.querySelectorAll("ol")
  62. olTags.forEach((ol) => {
  63. ol.style.margin = "0px"
  64. ol.style.padding = "auto 0px"
  65. ol.style.wordBreak = "break-word"
  66. ol.style.lineHeight = "1"
  67. })
  68. }
  69. // 创建幻灯片元素
  70. const createSlideElement = (width, height) => {
  71. const slideElement = document.createElement("div")
  72. slideElement.className = "slide"
  73. slideElement.style.position = "relative"
  74. slideElement.style.width = width + "px"
  75. slideElement.style.height = height + "px"
  76. slideElement.style.border = "1px solid #ccc"
  77. slideElement.style.margin = "0px auto"
  78. slideElement.style.marginBottom = "20px"
  79. slideElement.style.overflow = "hidden"
  80. return slideElement
  81. }
  82. // 应用幻灯片背景
  83. const applySlideBackground = (slideElement, fill) => {
  84. if (!fill) return
  85. if (fill.type === "gradient") {
  86. const { colors, path, rot } = fill.value
  87. if (colors && colors.length >= 2) {
  88. const gradientType = path === "rect" ? "linear" : "radial"
  89. const gradientAngle =
  90. gradientType === "linear" ? (90 - (rot || 0)) % 360 : rot || 0
  91. let gradientString = `${gradientType}-gradient(`
  92. if (gradientType === "linear") {
  93. gradientString += `${gradientAngle}deg, `
  94. }
  95. colors.forEach((color, i) => {
  96. gradientString += `${color.color} ${color.pos}${
  97. i < colors.length - 1 ? ", " : ""
  98. }`
  99. })
  100. gradientString += ")"
  101. slideElement.style.background = gradientString
  102. }
  103. } else if (fill.type === "color") {
  104. slideElement.style.backgroundColor = fill.value || "#FFFFFF"
  105. } else if (fill.type === "image" && fill.value.picBase64) {
  106. // 设置背景图片
  107. slideElement.style.backgroundImage = `url(${fill.value.picBase64})`
  108. slideElement.style.backgroundSize = "cover"
  109. slideElement.style.backgroundPosition = "center"
  110. slideElement.style.backgroundRepeat = "no-repeat"
  111. // 如果有背景图片的混合模式
  112. if (fill.value.blendMode) {
  113. slideElement.style.backgroundBlendMode = fill.value.blendMode
  114. }
  115. // 如果有透明度设置
  116. if (fill.value.opacity !== undefined) {
  117. slideElement.style.opacity = fill.value.opacity
  118. }
  119. }
  120. }
  121. // 根据元素类型创建DOM元素
  122. const createElementByType = (element) => {
  123. switch (element.type) {
  124. case "image":
  125. return createImageElement(element)
  126. case "video":
  127. return createVideoElement(element)
  128. case "audio":
  129. return createAudioElement(element)
  130. case "shape":
  131. return createShapeElement(element)
  132. case "table":
  133. return createTableElement(element)
  134. case "chart":
  135. return createChartElement(element)
  136. case "diagram":
  137. return createDiagramElement(element)
  138. case "math":
  139. return createMathElement(element)
  140. case "group":
  141. return createGroupElement(element)
  142. default:
  143. return createTextElement(element)
  144. }
  145. }
  146. // 创建组合元素
  147. const createGroupElement = (element) => {
  148. // 创建组合容器
  149. const groupContainer = document.createElement("div")
  150. groupContainer.className = "group-element"
  151. groupContainer.style.position = "absolute"
  152. groupContainer.style.top = element.top + "px"
  153. groupContainer.style.left = element.left + "px"
  154. groupContainer.style.width = element.width + "px"
  155. groupContainer.style.height = element.height + "px"
  156. groupContainer.style.zIndex = element.order
  157. groupContainer.style.transformOrigin = "center center"
  158. // 创建内部容器来处理子元素
  159. const innerContainer = document.createElement("div")
  160. innerContainer.style.position = "relative"
  161. innerContainer.style.width = "100%"
  162. innerContainer.style.height = "100%"
  163. // 应用旋转变换
  164. if (element.rotate) {
  165. groupContainer.style.transform = `rotate(${element.rotate}deg)`
  166. }
  167. // 应用其他样式属性
  168. if (element.opacity !== undefined) {
  169. groupContainer.style.opacity = element.opacity
  170. }
  171. // 递归渲染组内的所有子元素
  172. if (element.elements && Array.isArray(element.elements)) {
  173. element.elements.forEach((childElement) => {
  174. const childCopy = JSON.parse(JSON.stringify(childElement))
  175. const childEl = createElementByType(childCopy)
  176. if (childEl) {
  177. innerContainer.appendChild(childEl)
  178. }
  179. })
  180. }
  181. groupContainer.appendChild(innerContainer)
  182. return groupContainer
  183. }
  184. // 创建图像元素
  185. const createImageElement = (element) => {
  186. const img = document.createElement("img")
  187. img.src = element.src
  188. img.style.width = element.width + "px"
  189. img.style.height = element.height + "px"
  190. img.style.objectFit = "cover" // 保持图像的宽高比并填充容器
  191. img.style.position = "absolute"
  192. img.style.top = `${element.top}px`
  193. img.style.left = `${element.left}px`
  194. img.style.zIndex = element.order
  195. return img
  196. }
  197. // 创建视频元素
  198. const createVideoElement = (element) => {
  199. const el = document.createElement("video")
  200. el.src = element.blob
  201. el.controls = true
  202. el.style.width = element.width + "px"
  203. el.style.height = element.height + "px"
  204. el.style.position = "absolute"
  205. el.style.top = element.top + "px"
  206. el.style.left = element.left + "px"
  207. el.style.zIndex = element.order
  208. return el
  209. }
  210. // 创建音频元素
  211. const createAudioElement = (element) => {
  212. const el = document.createElement("audio")
  213. el.src = element.blob
  214. el.controls = true
  215. el.style.height = element.height + "px"
  216. el.style.position = "absolute"
  217. el.style.top = element.top + "px"
  218. el.style.left = element.left + "px"
  219. el.style.zIndex = element.order
  220. return el
  221. }
  222. // 创建形状元素
  223. const createShapeElement = (element) => {
  224. const el = document.createElement("div")
  225. el.style.position = "absolute"
  226. el.style.top = element.top + "px"
  227. el.style.left = element.left + "px"
  228. el.style.width = element.width + "px"
  229. el.style.height = element.height + "px"
  230. el.style.zIndex = element.order
  231. el.style.overflow = "visible"
  232. if (element.height === 0) {
  233. // 如果高度为0,直接在div上绘制边框
  234. el.style.borderTop = `${element.borderWidth || 1}px ${
  235. element.borderType || "solid"
  236. } ${element.borderColor || "#000"}`
  237. }
  238. // 使用SVG绘制形状
  239. const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg")
  240. svg.setAttribute("width", "100%")
  241. svg.setAttribute("height", "100%")
  242. svg.setAttribute("viewBox", `0 0 ${element.width} ${element.height}`)
  243. svg.style.overflow = "visible"
  244. const setBackground = (element, shape) => {
  245. if (element.fill && element.fill.type) {
  246. // 设置填充色
  247. if (element.fill.type === "color") {
  248. shape.setAttribute("fill", element.fill.value || "transparent")
  249. } else if (element.fill.type === "gradient") {
  250. // 渐变填充
  251. const { colors, path, rot } = element.fill.value
  252. if (colors && colors.length >= 2) {
  253. const gradientType = path === "rect" ? "linear" : "radial"
  254. const gradientAngle =
  255. gradientType === "linear" ? (90 - (rot || 0)) % 360 : rot || 0
  256. let gradientString = `${gradientType}-gradient(`
  257. if (gradientType === "linear") {
  258. gradientString += `${gradientAngle}deg, `
  259. }
  260. colors.forEach((color, i) => {
  261. gradientString += `${color.color} ${color.pos}${
  262. i < colors.length - 1 ? ", " : ""
  263. }`
  264. })
  265. gradientString += ")"
  266. // 创建渐变定义
  267. const gradientDef = document.createElementNS(
  268. "http://www.w3.org/2000/svg",
  269. "defs"
  270. )
  271. const gradientEl = document.createElementNS(
  272. "http://www.w3.org/2000/svg",
  273. gradientType === "linear" ? "linearGradient" : "radialGradient"
  274. )
  275. const gradientId = `gradient-${Date.now()}-${Math.random()
  276. .toString(36)
  277. .substr(2, 9)}`
  278. gradientEl.setAttribute("id", gradientId)
  279. // 设置渐变属性
  280. if (gradientType === "linear") {
  281. gradientEl.setAttribute(
  282. "gradientTransform",
  283. `rotate(${gradientAngle})`
  284. )
  285. }
  286. // 添加渐变色标
  287. colors.forEach((color) => {
  288. const stop = document.createElementNS(
  289. "http://www.w3.org/2000/svg",
  290. "stop"
  291. )
  292. stop.setAttribute("offset", color.pos)
  293. stop.setAttribute("stop-color", color.color)
  294. gradientEl.appendChild(stop)
  295. })
  296. gradientDef.appendChild(gradientEl)
  297. svg.appendChild(gradientDef)
  298. // 应用渐变
  299. shape.setAttribute("fill", `url(#${gradientId})`)
  300. }
  301. } else if (element.fill.type === "image") {
  302. // 创建图案填充
  303. const pattern = document.createElementNS(
  304. "http://www.w3.org/2000/svg",
  305. "pattern"
  306. )
  307. const patternId = `pattern-${Date.now()}-${Math.random()
  308. .toString(36)
  309. .substr(2, 9)}`
  310. pattern.setAttribute("id", patternId)
  311. pattern.setAttribute("patternUnits", "userSpaceOnUse")
  312. pattern.setAttribute("width", "100%")
  313. pattern.setAttribute("height", "100%")
  314. // 创建图片元素
  315. const image = document.createElementNS(
  316. "http://www.w3.org/2000/svg",
  317. "image"
  318. )
  319. image.setAttribute("width", "100%")
  320. image.setAttribute("height", "100%")
  321. image.setAttribute("preserveAspectRatio", "xMidYMid slice")
  322. image.setAttributeNS(
  323. "http://www.w3.org/1999/xlink",
  324. "href",
  325. element.fill.value.picBase64
  326. )
  327. pattern.appendChild(image)
  328. // 添加pattern到defs
  329. const defs = document.createElementNS(
  330. "http://www.w3.org/2000/svg",
  331. "defs"
  332. )
  333. defs.appendChild(pattern)
  334. svg.appendChild(defs)
  335. // 应用图案填充
  336. shape.setAttribute("fill", `url(#${patternId})`)
  337. } else {
  338. shape.setAttribute("fill", "transparent")
  339. }
  340. } else {
  341. shape.setAttribute("fill", "#ffffff00")
  342. }
  343. }
  344. // 根据形状类型创建不同的SVG元素
  345. switch (element.shapType) {
  346. case "roundRect":
  347. const radius = Math.min(element.width, element.height) * 0.1
  348. const roundRect = document.createElementNS(
  349. "http://www.w3.org/2000/svg",
  350. "rect"
  351. )
  352. roundRect.setAttribute("x", 0)
  353. roundRect.setAttribute("y", 0)
  354. roundRect.setAttribute("width", element.width)
  355. roundRect.setAttribute("height", element.height)
  356. roundRect.setAttribute("rx", radius)
  357. roundRect.setAttribute("ry", radius)
  358. // 设置填充色
  359. setBackground(element, roundRect)
  360. // 设置边框
  361. if (element.borderWidth > 0) {
  362. roundRect.setAttribute("stroke", element.borderColor || "#000")
  363. roundRect.setAttribute("stroke-width", element.borderWidth || 1)
  364. roundRect.setAttribute("stroke-linejoin", "round") // 设置连接处为圆角
  365. roundRect.setAttribute("vector-effect", "non-scaling-stroke") // 防止边框宽度变形
  366. roundRect.setAttribute("shape-rendering", "geometricPrecision") // 提高渲染精度
  367. // 处理虚线边框
  368. if (
  369. element.borderType === "dotted" ||
  370. element.borderType === "dashed"
  371. ) {
  372. if (element.borderStrokeDasharray) {
  373. roundRect.setAttribute(
  374. "stroke-dasharray",
  375. element.borderStrokeDasharray
  376. )
  377. } else if (element.borderType === "dotted") {
  378. roundRect.setAttribute("stroke-dasharray", "1, 3")
  379. } else if (element.borderType === "dashed") {
  380. roundRect.setAttribute("stroke-dasharray", "5, 5")
  381. }
  382. }
  383. }
  384. svg.appendChild(roundRect)
  385. break
  386. case "snip1Rect":
  387. // 使用path元素绘制剪去单角的矩形
  388. const snip1Rect = document.createElementNS(
  389. "http://www.w3.org/2000/svg",
  390. "path"
  391. )
  392. // 计算剪角的大小,通常为矩形较短边的20%
  393. const snipSize = Math.min(element.width, element.height) * 0.35
  394. // 绘制路径:从左上角开始,顺时针方向,右上角被剪去
  395. snip1Rect.setAttribute(
  396. "d",
  397. `M0,0 ` +
  398. `L${element.width - snipSize},0 ` +
  399. `L${element.width},${snipSize} ` +
  400. `L${element.width},${element.height} ` +
  401. `L0,${element.height} ` +
  402. `Z`
  403. )
  404. // 设置填充色
  405. setBackground(element, snip1Rect)
  406. // 设置边框
  407. if (element.borderWidth > 0) {
  408. snip1Rect.setAttribute("stroke", element.borderColor || "#000")
  409. snip1Rect.setAttribute("stroke-width", element.borderWidth || 1)
  410. // 处理虚线边框
  411. if (
  412. element.borderType === "dotted" ||
  413. element.borderType === "dashed"
  414. ) {
  415. if (element.borderStrokeDasharray) {
  416. snip1Rect.setAttribute(
  417. "stroke-dasharray",
  418. element.borderStrokeDasharray
  419. )
  420. } else if (element.borderType === "dotted") {
  421. snip1Rect.setAttribute("stroke-dasharray", "1, 3")
  422. } else if (element.borderType === "dashed") {
  423. snip1Rect.setAttribute("stroke-dasharray", "5, 5")
  424. }
  425. }
  426. }
  427. svg.appendChild(snip1Rect)
  428. break
  429. case "snip2SameRect":
  430. // 使用path元素绘制剪去四个角的矩形
  431. const snip2SameRect = document.createElementNS(
  432. "http://www.w3.org/2000/svg",
  433. "path"
  434. )
  435. // 计算剪角的大小,通常为矩形较短边的20%
  436. const snip2Size = Math.min(element.width, element.height) * 0.35
  437. // 绘制路径:从左上角开始,顺时针方向,剪去四个角
  438. snip2SameRect.setAttribute(
  439. "d",
  440. `M${snip2Size},0 ` +
  441. `L${element.width - snip2Size},0 ` +
  442. `L${element.width},${snip2Size} ` +
  443. `L${element.width},${element.height - snip2Size} ` +
  444. `L${element.width - snip2Size},${element.height} ` +
  445. `L${snip2Size},${element.height} ` +
  446. `L0,${element.height - snip2Size} ` +
  447. `L0,${snip2Size} ` +
  448. `Z`
  449. )
  450. // 设置填充色
  451. setBackground(element, snip2SameRect)
  452. // 设置边框
  453. if (element.borderWidth > 0) {
  454. snip2SameRect.setAttribute("stroke", element.borderColor || "#000")
  455. snip2SameRect.setAttribute("stroke-width", element.borderWidth || 1)
  456. // 处理虚线边框
  457. if (
  458. element.borderType === "dotted" ||
  459. element.borderType === "dashed"
  460. ) {
  461. if (element.borderStrokeDasharray) {
  462. snip2SameRect.setAttribute(
  463. "stroke-dasharray",
  464. element.borderStrokeDasharray
  465. )
  466. } else if (element.borderType === "dotted") {
  467. snip2SameRect.setAttribute("stroke-dasharray", "2, 2")
  468. snip2SameRect.setAttribute("stroke-linecap", "round")
  469. } else if (element.borderType === "dashed") {
  470. snip2SameRect.setAttribute("stroke-dasharray", "6, 3")
  471. }
  472. }
  473. // 添加这些属性以确保边框正确渲染
  474. snip2SameRect.setAttribute("vector-effect", "non-scaling-stroke")
  475. snip2SameRect.setAttribute("shape-rendering", "geometricPrecision")
  476. }
  477. svg.appendChild(snip2SameRect)
  478. break
  479. case "line":
  480. // 创建直线连接符
  481. const line = document.createElementNS(
  482. "http://www.w3.org/2000/svg",
  483. "line"
  484. )
  485. // 设置SVG的最小高度为1px
  486. const svgHeight = element.height > 0 ? element.height : 1
  487. svg.setAttribute("height", svgHeight + "px")
  488. // 设置线条的起点和终点
  489. line.setAttribute("x1", 0)
  490. line.setAttribute("y1", 0)
  491. line.setAttribute("x2", element.width)
  492. line.setAttribute("y2", svgHeight)
  493. // 确保边框颜色和宽度被正确设置
  494. line.setAttribute("stroke", element.borderColor || "#000")
  495. line.setAttribute("stroke-width", element.borderWidth || 1)
  496. // 处理虚线样式
  497. if (element.borderType === "dotted" || element.borderType === "dashed") {
  498. if (element.borderStrokeDasharray) {
  499. line.setAttribute("stroke-dasharray", element.borderStrokeDasharray)
  500. } else if (element.borderType === "dotted") {
  501. line.setAttribute("stroke-dasharray", "2, 2")
  502. line.setAttribute("stroke-linecap", "round") // 添加圆角端点使点线更明显
  503. } else if (element.borderType === "dashed") {
  504. line.setAttribute("stroke-dasharray", "6, 3")
  505. }
  506. }
  507. // 确保线条正确渲染
  508. line.setAttribute("vector-effect", "non-scaling-stroke") // 防止缩放影响线条宽度
  509. svg.appendChild(line)
  510. break
  511. case "snip2DiagRect":
  512. // 使用path元素绘制剪去右上角和左下角的矩形
  513. const snip2DiagRect = document.createElementNS(
  514. "http://www.w3.org/2000/svg",
  515. "path"
  516. )
  517. // 计算剪角的大小,通常为矩形较短边的35%
  518. const snipDiagSize = Math.min(element.width, element.height) * 0.35
  519. // 绘制路径:从左上角开始,顺时针方向,右上角和左下角被剪去
  520. snip2DiagRect.setAttribute(
  521. "d",
  522. `M0,0 ` +
  523. `L${element.width - snipDiagSize},0 ` +
  524. `L${element.width},${snipDiagSize} ` +
  525. `L${element.width},${element.height} ` +
  526. `L${snipDiagSize},${element.height} ` +
  527. `L0,${element.height - snipDiagSize} ` +
  528. `Z`
  529. )
  530. // 设置填充色
  531. setBackground(element, snip2DiagRect)
  532. // 设置边框
  533. if (element.borderWidth > 0) {
  534. snip2DiagRect.setAttribute("stroke", element.borderColor || "#000")
  535. snip2DiagRect.setAttribute("stroke-width", element.borderWidth || 1)
  536. // 处理虚线边框
  537. if (
  538. element.borderType === "dotted" ||
  539. element.borderType === "dashed"
  540. ) {
  541. if (element.borderStrokeDasharray) {
  542. snip2DiagRect.setAttribute(
  543. "stroke-dasharray",
  544. element.borderStrokeDasharray
  545. )
  546. } else if (element.borderType === "dotted") {
  547. snip2DiagRect.setAttribute("stroke-dasharray", "2, 2")
  548. snip2DiagRect.setAttribute("stroke-linecap", "round")
  549. } else if (element.borderType === "dashed") {
  550. snip2DiagRect.setAttribute("stroke-dasharray", "6, 3")
  551. }
  552. }
  553. // 添加这些属性以确保边框正确渲染
  554. snip2DiagRect.setAttribute("vector-effect", "non-scaling-stroke")
  555. snip2DiagRect.setAttribute("shape-rendering", "geometricPrecision")
  556. }
  557. svg.appendChild(snip2DiagRect)
  558. break
  559. case "snipRoundRect":
  560. const snipRoundRect = document.createElementNS(
  561. "http://www.w3.org/2000/svg",
  562. "path"
  563. )
  564. // 计算剪切大小和圆角大小
  565. const snipSize2 = Math.min(element.width, element.height) * 0.4
  566. const roundSize = Math.min(element.width, element.height) * 0.5
  567. // 绘制路径:从左上角开始,顺时针方向,左上为圆角,右上为剪切角
  568. snipRoundRect.setAttribute(
  569. "d",
  570. `M${roundSize},0 ` +
  571. `L${element.width - snipSize2},0 ` +
  572. `L${element.width},${snipSize2} ` +
  573. `L${element.width},${element.height} ` +
  574. `L0,${element.height} ` +
  575. `L0,${roundSize} ` +
  576. `A${roundSize},${roundSize} 0 0,1 ${roundSize},0 ` +
  577. `Z`
  578. )
  579. // 设置填充色
  580. setBackground(element, snipRoundRect)
  581. // 设置边框
  582. if (element.borderWidth > 0) {
  583. snipRoundRect.setAttribute("stroke", element.borderColor || "#000")
  584. snipRoundRect.setAttribute("stroke-width", element.borderWidth || 1)
  585. // 处理虚线边框
  586. if (
  587. element.borderType === "dotted" ||
  588. element.borderType === "dashed"
  589. ) {
  590. if (element.borderStrokeDasharray) {
  591. snipRoundRect.setAttribute(
  592. "stroke-dasharray",
  593. element.borderStrokeDasharray
  594. )
  595. } else if (element.borderType === "dotted") {
  596. snipRoundRect.setAttribute("stroke-dasharray", "2, 2")
  597. snipRoundRect.setAttribute("stroke-linecap", "round")
  598. } else if (element.borderType === "dashed") {
  599. snipRoundRect.setAttribute("stroke-dasharray", "6, 3")
  600. }
  601. }
  602. snipRoundRect.setAttribute("vector-effect", "non-scaling-stroke")
  603. snipRoundRect.setAttribute("shape-rendering", "geometricPrecision")
  604. }
  605. svg.appendChild(snipRoundRect)
  606. break
  607. case "round1Rect":
  608. const round1Rect = document.createElementNS(
  609. "http://www.w3.org/2000/svg",
  610. "path"
  611. )
  612. // 计算圆角大小
  613. const round1Size = Math.min(element.width, element.height) * 0.5
  614. // 绘制路径:从左上角开始,顺时针方向,右上角为圆角
  615. round1Rect.setAttribute(
  616. "d",
  617. `M0,0 ` +
  618. `L${element.width - round1Size},0 ` +
  619. `Q${element.width},0 ${element.width},${round1Size} ` +
  620. `L${element.width},${element.height} ` +
  621. `L0,${element.height} ` +
  622. `Z`
  623. )
  624. // 设置填充色
  625. setBackground(element, round1Rect)
  626. // 设置边框
  627. if (element.borderWidth > 0) {
  628. round1Rect.setAttribute("stroke", element.borderColor || "#000")
  629. round1Rect.setAttribute("stroke-width", element.borderWidth || 1)
  630. // 处理虚线边框
  631. if (
  632. element.borderType === "dotted" ||
  633. element.borderType === "dashed"
  634. ) {
  635. if (element.borderStrokeDasharray) {
  636. round1Rect.setAttribute("stroke-dasharray", "40,15,5,15")
  637. } else if (element.borderType === "dotted") {
  638. round1Rect.setAttribute("stroke-dasharray", "2, 2")
  639. round1Rect.setAttribute("stroke-linecap", "round")
  640. } else if (element.borderType === "dashed") {
  641. round1Rect.setAttribute("stroke-dasharray", "6, 3")
  642. }
  643. }
  644. round1Rect.setAttribute("vector-effect", "non-scaling-stroke")
  645. round1Rect.setAttribute("shape-rendering", "geometricPrecision")
  646. }
  647. svg.appendChild(round1Rect)
  648. break
  649. case "ellipse":
  650. case "circle":
  651. const ellipse = document.createElementNS(
  652. "http://www.w3.org/2000/svg",
  653. "ellipse"
  654. )
  655. ellipse.setAttribute("cx", element.width / 2)
  656. ellipse.setAttribute("cy", element.height / 2)
  657. ellipse.setAttribute("rx", element.width / 2)
  658. ellipse.setAttribute("ry", element.height / 2)
  659. // 设置填充色
  660. setBackground(element, ellipse)
  661. // 设置边框
  662. if (element.borderWidth > 0) {
  663. ellipse.setAttribute("stroke", element.borderColor || "#000")
  664. ellipse.setAttribute("stroke-width", element.borderWidth || 1)
  665. // 处理虚线边框
  666. if (
  667. element.borderType === "dotted" ||
  668. element.borderType === "dashed"
  669. ) {
  670. if (element.borderStrokeDasharray) {
  671. ellipse.setAttribute(
  672. "stroke-dasharray",
  673. element.borderStrokeDasharray
  674. )
  675. } else if (element.borderType === "dotted") {
  676. ellipse.setAttribute("stroke-dasharray", "1, 3")
  677. } else if (element.borderType === "dashed") {
  678. ellipse.setAttribute("stroke-dasharray", "5, 5")
  679. }
  680. }
  681. }
  682. svg.appendChild(ellipse)
  683. break
  684. case "round2SameRect":
  685. const round2SameRect = document.createElementNS(
  686. "http://www.w3.org/2000/svg",
  687. "path"
  688. )
  689. // 计算圆角大小
  690. const round2Size = Math.min(element.width, element.height) * 0.5
  691. // 绘制路径:从左上角开始,顺时针方向,左上和右上为圆角
  692. round2SameRect.setAttribute(
  693. "d",
  694. `M${round2Size},0 ` +
  695. `L${element.width - round2Size},0 ` +
  696. `Q${element.width},0 ${element.width},${round2Size} ` +
  697. `L${element.width},${element.height} ` +
  698. `L0,${element.height} ` +
  699. `L0,${round2Size} ` +
  700. `Q0,0 ${round2Size},0 ` +
  701. `Z`
  702. )
  703. // 设置填充色
  704. setBackground(element, round2SameRect)
  705. // 设置边框
  706. if (element.borderWidth > 0) {
  707. round2SameRect.setAttribute("stroke", element.borderColor || "#000")
  708. round2SameRect.setAttribute("stroke-width", element.borderWidth || 1)
  709. // 处理虚线边框
  710. if (
  711. element.borderType === "dotted" ||
  712. element.borderType === "dashed"
  713. ) {
  714. if (element.borderStrokeDasharray) {
  715. round2SameRect.setAttribute(
  716. "stroke-dasharray",
  717. element.borderStrokeDasharray
  718. )
  719. } else if (element.borderType === "dotted") {
  720. round2SameRect.setAttribute("stroke-dasharray", "2, 2")
  721. round2SameRect.setAttribute("stroke-linecap", "round")
  722. } else if (element.borderType === "dashed") {
  723. round2SameRect.setAttribute("stroke-dasharray", "6, 3")
  724. }
  725. }
  726. round2SameRect.setAttribute("vector-effect", "non-scaling-stroke")
  727. round2SameRect.setAttribute("shape-rendering", "geometricPrecision")
  728. }
  729. svg.appendChild(round2SameRect)
  730. break
  731. case "round2DiagRect":
  732. const round2DiagRect = document.createElementNS(
  733. "http://www.w3.org/2000/svg",
  734. "path"
  735. )
  736. // 计算圆角大小
  737. const round2DiagSize = Math.min(element.width, element.height) * 0.5
  738. // 绘制路径:从左上角开始,顺时针方向,左上和右下为圆角
  739. round2DiagRect.setAttribute(
  740. "d",
  741. `M${round2DiagSize},0 ` +
  742. `L${element.width},0 ` +
  743. `L${element.width},${element.height - round2DiagSize} ` +
  744. `Q${element.width},${element.height} ${
  745. element.width - round2DiagSize
  746. },${element.height} ` +
  747. `L0,${element.height} ` +
  748. `L0,${round2DiagSize} ` +
  749. `Q0,0 ${round2DiagSize},0 ` +
  750. `Z`
  751. )
  752. // 设置填充色
  753. setBackground(element, round2DiagRect)
  754. // 设置边框
  755. if (element.borderWidth > 0) {
  756. round2DiagRect.setAttribute("stroke", element.borderColor || "#000")
  757. round2DiagRect.setAttribute("stroke-width", element.borderWidth || 1)
  758. // 处理虚线边框
  759. if (
  760. element.borderType === "dotted" ||
  761. element.borderType === "dashed"
  762. ) {
  763. if (element.borderStrokeDasharray) {
  764. round2DiagRect.setAttribute(
  765. "stroke-dasharray",
  766. element.borderStrokeDasharray
  767. )
  768. } else if (element.borderType === "dotted") {
  769. round2DiagRect.setAttribute("stroke-dasharray", "2, 2")
  770. round2DiagRect.setAttribute("stroke-linecap", "round")
  771. } else if (element.borderType === "dashed") {
  772. round2DiagRect.setAttribute("stroke-dasharray", "6, 3")
  773. }
  774. }
  775. round2DiagRect.setAttribute("vector-effect", "non-scaling-stroke")
  776. round2DiagRect.setAttribute("shape-rendering", "geometricPrecision")
  777. }
  778. svg.appendChild(round2DiagRect)
  779. break
  780. case "triangle":
  781. const triangle = document.createElementNS(
  782. "http://www.w3.org/2000/svg",
  783. "polygon"
  784. )
  785. triangle.setAttribute(
  786. "points",
  787. `${element.width / 2},0 ${element.width},${element.height} 0,${
  788. element.height
  789. }`
  790. )
  791. // 设置填充色
  792. setBackground(element, triangle)
  793. // 设置边框
  794. if (element.borderWidth > 0) {
  795. triangle.setAttribute("stroke", element.borderColor || "#000")
  796. triangle.setAttribute("stroke-width", element.borderWidth || 1)
  797. // 处理虚线边框
  798. if (
  799. element.borderType === "dotted" ||
  800. element.borderType === "dashed"
  801. ) {
  802. if (element.borderStrokeDasharray) {
  803. triangle.setAttribute(
  804. "stroke-dasharray",
  805. element.borderStrokeDasharray
  806. )
  807. } else if (element.borderType === "dotted") {
  808. triangle.setAttribute("stroke-dasharray", "1, 3")
  809. } else if (element.borderType === "dashed") {
  810. triangle.setAttribute("stroke-dasharray", "5, 5")
  811. }
  812. }
  813. }
  814. svg.appendChild(triangle)
  815. break
  816. case "arc":
  817. const arc = document.createElementNS("http://www.w3.org/2000/svg", "path")
  818. // 计算弧形的参数
  819. const arcRadius = Math.min(element.width, element.height) / 2
  820. // 绘制弧形路径
  821. arc.setAttribute(
  822. "d",
  823. `M${arcRadius},0 ` +
  824. `A${arcRadius},${arcRadius} 0 1 1 ${arcRadius * 0.15},${
  825. arcRadius * 0.5
  826. }`
  827. )
  828. // 设置填充色
  829. arc.setAttribute("fill", "transparent")
  830. // 设置边框
  831. if (element.borderWidth > 0) {
  832. arc.setAttribute("stroke", element.borderColor || "#000")
  833. arc.setAttribute("stroke-width", element.borderWidth || 0.5)
  834. // 处理虚线边框
  835. if (
  836. element.borderType === "dotted" ||
  837. element.borderType === "dashed"
  838. ) {
  839. if (element.borderStrokeDasharray) {
  840. arc.setAttribute("stroke-dasharray", element.borderStrokeDasharray)
  841. } else if (element.borderType === "dotted") {
  842. arc.setAttribute("stroke-dasharray", "2, 2")
  843. arc.setAttribute("stroke-linecap", "round")
  844. } else if (element.borderType === "dashed") {
  845. arc.setAttribute("stroke-dasharray", "6, 3")
  846. }
  847. }
  848. arc.setAttribute("vector-effect", "non-scaling-stroke")
  849. arc.setAttribute("shape-rendering", "geometricPrecision")
  850. } else {
  851. arc.setAttribute("stroke", element.borderColor || "#000")
  852. arc.setAttribute("stroke-width", 0.5)
  853. }
  854. svg.appendChild(arc)
  855. break
  856. case "custom":
  857. const customPath = document.createElementNS(
  858. "http://www.w3.org/2000/svg",
  859. "path"
  860. )
  861. // 直接使用传入的 path 数据
  862. customPath.setAttribute("d", element.path || "")
  863. // 设置填充色
  864. setBackground(element, customPath)
  865. // 设置边框
  866. if (element.borderWidth > 0) {
  867. customPath.setAttribute("stroke", element.borderColor || "#000")
  868. customPath.setAttribute("stroke-width", element.borderWidth || 1)
  869. // 处理虚线边框
  870. if (
  871. element.borderType === "dotted" ||
  872. element.borderType === "dashed"
  873. ) {
  874. if (element.borderStrokeDasharray) {
  875. customPath.setAttribute(
  876. "stroke-dasharray",
  877. element.borderStrokeDasharray
  878. )
  879. } else if (element.borderType === "dotted") {
  880. customPath.setAttribute("stroke-dasharray", "2, 2")
  881. customPath.setAttribute("stroke-linecap", "round")
  882. } else if (element.borderType === "dashed") {
  883. customPath.setAttribute("stroke-dasharray", "6, 3")
  884. }
  885. }
  886. customPath.setAttribute("vector-effect", "non-scaling-stroke")
  887. customPath.setAttribute("shape-rendering", "geometricPrecision")
  888. }
  889. svg.appendChild(customPath)
  890. break
  891. case "teardrop":
  892. const teardrop = document.createElementNS(
  893. "http://www.w3.org/2000/svg",
  894. "path"
  895. )
  896. // 计算泪珠形状的参数
  897. const tdCenterX = element.width / 2
  898. const tdCenterY = element.height / 2
  899. const tdRadiusX = element.width / 2
  900. const tdRadiusY = element.height / 2
  901. // 使用相对比例计算控制点
  902. teardrop.setAttribute(
  903. "d",
  904. `M${tdCenterX * 2} ${tdCenterY} ` +
  905. `A ${tdRadiusX} ${tdRadiusY} 0 1 1 ${tdCenterX} 0 ` +
  906. `Q${tdCenterX * 1.7},0 ${tdCenterX * 2.1},${-tdCenterY * 0.1} ` +
  907. `Q${tdCenterX * 2},${tdCenterY * 0.29} ${tdCenterX * 2},${tdCenterY}`
  908. )
  909. // 设置填充色
  910. setBackground(element, teardrop)
  911. // 设置边框样式
  912. if (element.borderWidth > 0) {
  913. teardrop.setAttribute("stroke", element.borderColor || "#000")
  914. teardrop.setAttribute("stroke-width", element.borderWidth || 1)
  915. teardrop.setAttribute("stroke-linejoin", "round")
  916. // 处理虚线边框
  917. if (
  918. element.borderType === "dotted" ||
  919. element.borderType === "dashed"
  920. ) {
  921. // ... 原有的虚线边框处理代码 ...
  922. }
  923. }
  924. svg.appendChild(teardrop)
  925. break
  926. case "decagon":
  927. const decagon = document.createElementNS(
  928. "http://www.w3.org/2000/svg",
  929. "polygon"
  930. )
  931. // 计算十边形的顶点
  932. let decagonPoints = ""
  933. for (let i = 0; i < 10; i++) {
  934. const angle = (i * 2 * Math.PI) / 10 - Math.PI / 2 // 从顶部开始
  935. const x = element.width / 2 + (element.width / 2) * Math.cos(angle)
  936. const y = element.height / 2 + (element.height / 2) * Math.sin(angle)
  937. decagonPoints += `${x},${y} `
  938. }
  939. decagon.setAttribute("points", decagonPoints.trim())
  940. // 设置填充色
  941. setBackground(element, decagon)
  942. // 设置边框
  943. if (element.borderWidth > 0) {
  944. decagon.setAttribute("stroke", element.borderColor || "#000")
  945. decagon.setAttribute("stroke-width", element.borderWidth || 1)
  946. // 处理虚线边框
  947. if (
  948. element.borderType === "dotted" ||
  949. element.borderType === "dashed"
  950. ) {
  951. if (element.borderStrokeDasharray) {
  952. decagon.setAttribute(
  953. "stroke-dasharray",
  954. element.borderStrokeDasharray
  955. )
  956. } else if (element.borderType === "dotted") {
  957. decagon.setAttribute("stroke-dasharray", "1, 3")
  958. } else if (element.borderType === "dashed") {
  959. decagon.setAttribute("stroke-dasharray", "5, 5")
  960. }
  961. }
  962. }
  963. svg.appendChild(decagon)
  964. break
  965. case "pentagon":
  966. const pentagon = document.createElementNS(
  967. "http://www.w3.org/2000/svg",
  968. "polygon"
  969. )
  970. pentagon.setAttribute(
  971. "points",
  972. `${element.width / 2},0 ${element.width},${element.height * 0.38} ` +
  973. `${element.width * 0.82},${element.height} ${element.width * 0.18},${
  974. element.height
  975. } ` +
  976. `0,${element.height * 0.38}`
  977. )
  978. // 设置填充色
  979. setBackground(element, pentagon)
  980. // 设置边框
  981. if (element.borderWidth > 0) {
  982. pentagon.setAttribute("stroke", element.borderColor || "#000")
  983. pentagon.setAttribute("stroke-width", element.borderWidth || 1)
  984. // 处理虚线边框
  985. if (
  986. element.borderType === "dotted" ||
  987. element.borderType === "dashed"
  988. ) {
  989. if (element.borderStrokeDasharray) {
  990. pentagon.setAttribute(
  991. "stroke-dasharray",
  992. element.borderStrokeDasharray
  993. )
  994. } else if (element.borderType === "dotted") {
  995. pentagon.setAttribute("stroke-dasharray", "1, 3")
  996. } else if (element.borderType === "dashed") {
  997. pentagon.setAttribute("stroke-dasharray", "5, 5")
  998. }
  999. }
  1000. }
  1001. svg.appendChild(pentagon)
  1002. break
  1003. case "pie":
  1004. const pie = document.createElementNS("http://www.w3.org/2000/svg", "path")
  1005. // 使用提供的路径数据,但保留元素的宽高比例
  1006. const centerX = element.width / 2
  1007. const centerY = element.height / 2
  1008. const radius2 = Math.min(element.width, element.height) / 2
  1009. // 绘制饼图,使用类似提供的路径数据
  1010. pie.setAttribute(
  1011. "d",
  1012. `M${centerX},${centerY} ` +
  1013. `L${centerX * 1.85},${centerY * 1.52} ` +
  1014. `A${radius2},${radius2} 0 1,1 ${centerX * 1.56},${centerY * 0.17} ` +
  1015. `Z`
  1016. )
  1017. // 设置填充色
  1018. setBackground(element, pie)
  1019. // 设置边框
  1020. if (element.borderWidth > 0) {
  1021. pie.setAttribute("stroke", element.borderColor || "#000")
  1022. pie.setAttribute("stroke-width", element.borderWidth || 1)
  1023. // 处理虚线边框
  1024. if (
  1025. element.borderType === "dotted" ||
  1026. element.borderType === "dashed"
  1027. ) {
  1028. if (element.borderStrokeDasharray) {
  1029. pie.setAttribute("stroke-dasharray", element.borderStrokeDasharray)
  1030. } else if (element.borderType === "dotted") {
  1031. pie.setAttribute("stroke-dasharray", "2, 2")
  1032. pie.setAttribute("stroke-linecap", "round")
  1033. } else if (element.borderType === "dashed") {
  1034. pie.setAttribute("stroke-dasharray", "6, 3")
  1035. }
  1036. }
  1037. pie.setAttribute("vector-effect", "non-scaling-stroke")
  1038. pie.setAttribute("shape-rendering", "geometricPrecision")
  1039. }
  1040. svg.appendChild(pie)
  1041. break
  1042. case "chord":
  1043. const chord = document.createElementNS(
  1044. "http://www.w3.org/2000/svg",
  1045. "path"
  1046. )
  1047. // 计算弦形的参数
  1048. const chordRadiusX = element.width * 0.4
  1049. const chordRadiusY = element.height * 0.4
  1050. // 绘制弦形 - 使用更大的圆弧和不同的起始/结束点
  1051. chord.setAttribute(
  1052. "d",
  1053. `M${element.width * 0.4},${element.height * 0.9} ` +
  1054. `A ${chordRadiusX} ${chordRadiusY} 0 1 1 ${element.width * 0.8},${
  1055. element.height * 0.5
  1056. } ` +
  1057. `Z`
  1058. )
  1059. // 设置填充色
  1060. setBackground(element, chord)
  1061. // 设置边框
  1062. if (element.borderWidth > 0) {
  1063. chord.setAttribute("stroke", element.borderColor || "#000")
  1064. chord.setAttribute("stroke-width", element.borderWidth || 1)
  1065. // 处理虚线边框
  1066. if (
  1067. element.borderType === "dotted" ||
  1068. element.borderType === "dashed"
  1069. ) {
  1070. if (element.borderStrokeDasharray) {
  1071. chord.setAttribute(
  1072. "stroke-dasharray",
  1073. element.borderStrokeDasharray
  1074. )
  1075. } else if (element.borderType === "dotted") {
  1076. chord.setAttribute("stroke-dasharray", "2, 2")
  1077. chord.setAttribute("stroke-linecap", "round")
  1078. } else if (element.borderType === "dashed") {
  1079. chord.setAttribute("stroke-dasharray", "6, 3")
  1080. }
  1081. }
  1082. chord.setAttribute("vector-effect", "non-scaling-stroke")
  1083. chord.setAttribute("shape-rendering", "geometricPrecision")
  1084. }
  1085. svg.appendChild(chord)
  1086. break
  1087. case "heptagon":
  1088. const heptagon = document.createElementNS(
  1089. "http://www.w3.org/2000/svg",
  1090. "polygon"
  1091. )
  1092. // 计算七边形的顶点
  1093. let heptagonPoints = ""
  1094. for (let i = 0; i < 7; i++) {
  1095. const angle = (i * 2 * Math.PI) / 7 - Math.PI / 2 // 从顶部开始
  1096. const x = element.width / 2 + (element.width / 2) * Math.cos(angle)
  1097. const y = element.height / 2 + (element.height / 2) * Math.sin(angle)
  1098. heptagonPoints += `${x},${y} `
  1099. }
  1100. heptagon.setAttribute("points", heptagonPoints.trim())
  1101. // 设置填充色
  1102. setBackground(element, heptagon)
  1103. // 设置边框
  1104. if (element.borderWidth > 0) {
  1105. heptagon.setAttribute("stroke", element.borderColor || "#000")
  1106. heptagon.setAttribute("stroke-width", element.borderWidth || 1)
  1107. // 处理虚线边框
  1108. if (
  1109. element.borderType === "dotted" ||
  1110. element.borderType === "dashed"
  1111. ) {
  1112. if (element.borderStrokeDasharray) {
  1113. heptagon.setAttribute(
  1114. "stroke-dasharray",
  1115. element.borderStrokeDasharray
  1116. )
  1117. } else if (element.borderType === "dotted") {
  1118. heptagon.setAttribute("stroke-dasharray", "1, 3")
  1119. } else if (element.borderType === "dashed") {
  1120. heptagon.setAttribute("stroke-dasharray", "5, 5")
  1121. }
  1122. }
  1123. }
  1124. svg.appendChild(heptagon)
  1125. break
  1126. case "hexagon":
  1127. const hexagon = document.createElementNS(
  1128. "http://www.w3.org/2000/svg",
  1129. "polygon"
  1130. )
  1131. hexagon.setAttribute(
  1132. "points",
  1133. `${element.width * 0.25},0 ${element.width * 0.75},0 ${element.width},${
  1134. element.height * 0.5
  1135. } ` +
  1136. `${element.width * 0.75},${element.height} ${element.width * 0.25},${
  1137. element.height
  1138. } 0,${element.height * 0.5}`
  1139. )
  1140. // 设置填充色
  1141. setBackground(element, hexagon)
  1142. // 设置边框
  1143. if (element.borderWidth > 0) {
  1144. hexagon.setAttribute("stroke", element.borderColor || "#000")
  1145. hexagon.setAttribute("stroke-width", element.borderWidth || 1)
  1146. // 处理虚线边框
  1147. if (
  1148. element.borderType === "dotted" ||
  1149. element.borderType === "dashed"
  1150. ) {
  1151. if (element.borderStrokeDasharray) {
  1152. hexagon.setAttribute(
  1153. "stroke-dasharray",
  1154. element.borderStrokeDasharray
  1155. )
  1156. } else if (element.borderType === "dotted") {
  1157. hexagon.setAttribute("stroke-dasharray", "1, 3")
  1158. } else if (element.borderType === "dashed") {
  1159. hexagon.setAttribute("stroke-dasharray", "5, 5")
  1160. }
  1161. }
  1162. }
  1163. svg.appendChild(hexagon)
  1164. break
  1165. case "octagon":
  1166. const octagon = document.createElementNS(
  1167. "http://www.w3.org/2000/svg",
  1168. "polygon"
  1169. )
  1170. octagon.setAttribute(
  1171. "points",
  1172. `${element.width * 0.3},0 ${element.width * 0.7},0 ${element.width},${
  1173. element.height * 0.3
  1174. } ` +
  1175. `${element.width},${element.height * 0.7} ${element.width * 0.7},${
  1176. element.height
  1177. } ` +
  1178. `${element.width * 0.3},${element.height} 0,${
  1179. element.height * 0.7
  1180. } 0,${element.height * 0.3}`
  1181. )
  1182. // 设置填充色
  1183. setBackground(element, octagon)
  1184. // 设置边框
  1185. if (element.borderWidth > 0) {
  1186. octagon.setAttribute("stroke", element.borderColor || "#000")
  1187. octagon.setAttribute("stroke-width", element.borderWidth || 1)
  1188. // 处理虚线边框
  1189. if (
  1190. element.borderType === "dotted" ||
  1191. element.borderType === "dashed"
  1192. ) {
  1193. if (element.borderStrokeDasharray) {
  1194. octagon.setAttribute(
  1195. "stroke-dasharray",
  1196. element.borderStrokeDasharray
  1197. )
  1198. } else if (element.borderType === "dotted") {
  1199. octagon.setAttribute("stroke-dasharray", "1, 3")
  1200. } else if (element.borderType === "dashed") {
  1201. octagon.setAttribute("stroke-dasharray", "5, 5")
  1202. }
  1203. }
  1204. }
  1205. svg.appendChild(octagon)
  1206. break
  1207. case "trapezoid":
  1208. const trapezoid = document.createElementNS(
  1209. "http://www.w3.org/2000/svg",
  1210. "polygon"
  1211. )
  1212. trapezoid.setAttribute(
  1213. "points",
  1214. `${element.width * 0.2},0 ${element.width * 0.8},0 ${element.width},${
  1215. element.height
  1216. } 0,${element.height}`
  1217. )
  1218. // 设置填充色
  1219. setBackground(element, trapezoid)
  1220. // 设置边框
  1221. if (element.borderWidth > 0) {
  1222. trapezoid.setAttribute("stroke", element.borderColor || "#000")
  1223. trapezoid.setAttribute("stroke-width", element.borderWidth || 1)
  1224. // 处理虚线边框
  1225. if (
  1226. element.borderType === "dotted" ||
  1227. element.borderType === "dashed"
  1228. ) {
  1229. if (element.borderStrokeDasharray) {
  1230. trapezoid.setAttribute(
  1231. "stroke-dasharray",
  1232. element.borderStrokeDasharray
  1233. )
  1234. } else if (element.borderType === "dotted") {
  1235. trapezoid.setAttribute("stroke-dasharray", "1, 3")
  1236. } else if (element.borderType === "dashed") {
  1237. trapezoid.setAttribute("stroke-dasharray", "5, 5")
  1238. }
  1239. }
  1240. }
  1241. svg.appendChild(trapezoid)
  1242. break
  1243. case "diamond":
  1244. const diamond = document.createElementNS(
  1245. "http://www.w3.org/2000/svg",
  1246. "polygon"
  1247. )
  1248. diamond.setAttribute(
  1249. "points",
  1250. `${element.width / 2},0 ${element.width},${element.height / 2} ${
  1251. element.width / 2
  1252. },${element.height} 0,${element.height / 2}`
  1253. )
  1254. // 设置填充色
  1255. setBackground(element, diamond)
  1256. // 设置边框
  1257. if (element.borderWidth > 0) {
  1258. diamond.setAttribute("stroke", element.borderColor || "#000")
  1259. diamond.setAttribute("stroke-width", element.borderWidth || 1)
  1260. // 处理虚线边框
  1261. if (
  1262. element.borderType === "dotted" ||
  1263. element.borderType === "dashed"
  1264. ) {
  1265. if (element.borderStrokeDasharray) {
  1266. diamond.setAttribute(
  1267. "stroke-dasharray",
  1268. element.borderStrokeDasharray
  1269. )
  1270. } else if (element.borderType === "dotted") {
  1271. diamond.setAttribute("stroke-dasharray", "1, 3")
  1272. } else if (element.borderType === "dashed") {
  1273. diamond.setAttribute("stroke-dasharray", "5, 5")
  1274. }
  1275. }
  1276. }
  1277. svg.appendChild(diamond)
  1278. break
  1279. case "dodecagon":
  1280. const dodecagon = document.createElementNS(
  1281. "http://www.w3.org/2000/svg",
  1282. "polygon"
  1283. )
  1284. // 计算十二边形的顶点
  1285. let dodecagonPoints = ""
  1286. for (let i = 0; i < 12; i++) {
  1287. const angle = (i * 2 * Math.PI) / 12 - Math.PI / 2 // 从顶部开始
  1288. const x = element.width / 2 + (element.width / 2) * Math.cos(angle)
  1289. const y = element.height / 2 + (element.height / 2) * Math.sin(angle)
  1290. dodecagonPoints += `${x},${y} `
  1291. }
  1292. dodecagon.setAttribute("points", dodecagonPoints.trim())
  1293. // 设置填充色
  1294. setBackground(element, dodecagon)
  1295. // 设置边框
  1296. if (element.borderWidth > 0) {
  1297. dodecagon.setAttribute("stroke", element.borderColor || "#000")
  1298. dodecagon.setAttribute("stroke-width", element.borderWidth || 1)
  1299. // 处理虚线边框
  1300. if (
  1301. element.borderType === "dotted" ||
  1302. element.borderType === "dashed"
  1303. ) {
  1304. if (element.borderStrokeDasharray) {
  1305. dodecagon.setAttribute(
  1306. "stroke-dasharray",
  1307. element.borderStrokeDasharray
  1308. )
  1309. } else if (element.borderType === "dotted") {
  1310. dodecagon.setAttribute("stroke-dasharray", "1, 3")
  1311. } else if (element.borderType === "dashed") {
  1312. dodecagon.setAttribute("stroke-dasharray", "5, 5")
  1313. }
  1314. }
  1315. }
  1316. svg.appendChild(dodecagon)
  1317. break
  1318. case "halfFrame":
  1319. // 创建外框和内框
  1320. const outerRect2 = document.createElementNS(
  1321. "http://www.w3.org/2000/svg",
  1322. "path"
  1323. )
  1324. const innerRect2 = document.createElementNS(
  1325. "http://www.w3.org/2000/svg",
  1326. "path"
  1327. )
  1328. // 计算内框的边距
  1329. const frameWidth2 = element.width / 9
  1330. // 绘制外框的左边和上边
  1331. outerRect2.setAttribute(
  1332. "d",
  1333. `M0,${element.height} L0,0 L${element.width},0`
  1334. )
  1335. // 绘制内框的左边和上边,注意起点位置调整
  1336. innerRect2.setAttribute(
  1337. "d",
  1338. `M${frameWidth2},${element.height - frameWidth2} ` +
  1339. `L${frameWidth2},${frameWidth2} ` +
  1340. `L${element.width - frameWidth2},${frameWidth2}`
  1341. )
  1342. // 设置填充色
  1343. if (element.fill && element.fill.type === "color") {
  1344. // 创建一个填充用的路径
  1345. const fillPath = document.createElementNS(
  1346. "http://www.w3.org/2000/svg",
  1347. "path"
  1348. )
  1349. fillPath.setAttribute(
  1350. "d",
  1351. `M${frameWidth2},${frameWidth2} ` +
  1352. `L${element.width - frameWidth2},${frameWidth2} ` +
  1353. `L${element.width},0 ` +
  1354. `L0,0 ` +
  1355. `L0,${element.height} ` +
  1356. `L${frameWidth2},${element.height - frameWidth2} Z`
  1357. )
  1358. fillPath.setAttribute("fill", element.fill.value || "transparent")
  1359. svg.appendChild(fillPath)
  1360. outerRect2.setAttribute("fill", "none")
  1361. innerRect2.setAttribute("fill", "none")
  1362. } else {
  1363. outerRect2.setAttribute("fill", "none")
  1364. innerRect2.setAttribute("fill", "none")
  1365. }
  1366. // 设置边框
  1367. if (element.borderWidth > 0) {
  1368. const borderColor = element.borderColor || "#000"
  1369. const borderWidth = element.borderWidth || 1
  1370. outerRect2.setAttribute("stroke", borderColor)
  1371. outerRect2.setAttribute("stroke-width", borderWidth)
  1372. innerRect2.setAttribute("stroke", borderColor)
  1373. innerRect2.setAttribute("stroke-width", borderWidth)
  1374. // 处理虚线边框
  1375. if (
  1376. element.borderType === "dotted" ||
  1377. element.borderType === "dashed"
  1378. ) {
  1379. if (element.borderStrokeDasharray) {
  1380. const dashArray = element.borderStrokeDasharray
  1381. outerRect2.setAttribute("stroke-dasharray", dashArray)
  1382. innerRect2.setAttribute("stroke-dasharray", dashArray)
  1383. } else if (element.borderType === "dotted") {
  1384. outerRect2.setAttribute("stroke-dasharray", "1, 3")
  1385. innerRect2.setAttribute("stroke-dasharray", "1, 3")
  1386. } else if (element.borderType === "dashed") {
  1387. outerRect2.setAttribute("stroke-dasharray", "5, 5")
  1388. innerRect2.setAttribute("stroke-dasharray", "5, 5")
  1389. }
  1390. }
  1391. }
  1392. svg.appendChild(outerRect2)
  1393. svg.appendChild(innerRect2)
  1394. break
  1395. case "corner":
  1396. const corner = document.createElementNS(
  1397. "http://www.w3.org/2000/svg",
  1398. "path"
  1399. )
  1400. corner.setAttribute(
  1401. "d",
  1402. `M0,0 ` +
  1403. `L0,${element.height} ` +
  1404. `L${element.width},${element.height} ` +
  1405. `L${element.width},${element.height * 0.6} ` +
  1406. `L${element.width * 0.4},${element.height * 0.6} ` +
  1407. `L${element.width * 0.4},0 Z`
  1408. )
  1409. // 设置填充色
  1410. setBackground(element, corner)
  1411. // 设置边框
  1412. if (element.borderWidth > 0) {
  1413. corner.setAttribute("stroke", element.borderColor || "#000")
  1414. corner.setAttribute("stroke-width", element.borderWidth || 1)
  1415. // 处理虚线边框
  1416. if (
  1417. element.borderType === "dotted" ||
  1418. element.borderType === "dashed"
  1419. ) {
  1420. if (element.borderStrokeDasharray) {
  1421. corner.setAttribute(
  1422. "stroke-dasharray",
  1423. element.borderStrokeDasharray
  1424. )
  1425. } else if (element.borderType === "dotted") {
  1426. corner.setAttribute("stroke-dasharray", "1, 3")
  1427. } else if (element.borderType === "dashed") {
  1428. corner.setAttribute("stroke-dasharray", "5, 5")
  1429. }
  1430. }
  1431. }
  1432. svg.appendChild(corner)
  1433. break
  1434. case "diagStripe":
  1435. const diagStripe = document.createElementNS(
  1436. "http://www.w3.org/2000/svg",
  1437. "path"
  1438. )
  1439. // 绘制斜纹路径
  1440. diagStripe.setAttribute(
  1441. "d",
  1442. `M${element.width * 0.4},0 ` +
  1443. `L${element.width},0 ` +
  1444. `L0,${element.height} ` +
  1445. `L0,${element.height * 0.4} Z`
  1446. )
  1447. // 设置填充色
  1448. setBackground(element, diagStripe)
  1449. // 设置边框
  1450. if (element.borderWidth > 0) {
  1451. diagStripe.setAttribute("stroke", element.borderColor || "#000")
  1452. diagStripe.setAttribute("stroke-width", element.borderWidth || 1)
  1453. diagStripe.setAttribute("stroke-linejoin", "round")
  1454. // 处理虚线边框
  1455. if (
  1456. element.borderType === "dotted" ||
  1457. element.borderType === "dashed"
  1458. ) {
  1459. if (element.borderStrokeDasharray) {
  1460. diagStripe.setAttribute(
  1461. "stroke-dasharray",
  1462. element.borderStrokeDasharray
  1463. )
  1464. } else if (element.borderType === "dotted") {
  1465. diagStripe.setAttribute("stroke-dasharray", "1, 3")
  1466. } else if (element.borderType === "dashed") {
  1467. diagStripe.setAttribute("stroke-dasharray", "5, 5")
  1468. }
  1469. }
  1470. }
  1471. svg.appendChild(diagStripe)
  1472. break
  1473. case "plus":
  1474. const plus = document.createElementNS(
  1475. "http://www.w3.org/2000/svg",
  1476. "polygon"
  1477. )
  1478. plus.setAttribute(
  1479. "points",
  1480. `${element.width * 0.4},0 ` +
  1481. `${element.width * 0.6},0 ` +
  1482. `${element.width * 0.6},${element.height * 0.4} ` +
  1483. `${element.width},${element.height * 0.4} ` +
  1484. `${element.width},${element.height * 0.6} ` +
  1485. `${element.width * 0.6},${element.height * 0.6} ` +
  1486. `${element.width * 0.6},${element.height} ` +
  1487. `${element.width * 0.4},${element.height} ` +
  1488. `${element.width * 0.4},${element.height * 0.6} ` +
  1489. `0,${element.height * 0.6} ` +
  1490. `0,${element.height * 0.4} ` +
  1491. `${element.width * 0.4},${element.height * 0.4}`
  1492. )
  1493. // 设置填充色
  1494. setBackground(element, plus)
  1495. // 设置边框
  1496. if (element.borderWidth > 0) {
  1497. plus.setAttribute("stroke", element.borderColor || "#000")
  1498. plus.setAttribute("stroke-width", element.borderWidth || 1)
  1499. // 处理虚线边框
  1500. if (
  1501. element.borderType === "dotted" ||
  1502. element.borderType === "dashed"
  1503. ) {
  1504. if (element.borderStrokeDasharray) {
  1505. plus.setAttribute("stroke-dasharray", element.borderStrokeDasharray)
  1506. } else if (element.borderType === "dotted") {
  1507. plus.setAttribute("stroke-dasharray", "1, 3")
  1508. } else if (element.borderType === "dashed") {
  1509. plus.setAttribute("stroke-dasharray", "5, 5")
  1510. }
  1511. }
  1512. }
  1513. svg.appendChild(plus)
  1514. break
  1515. case "can":
  1516. const can = document.createElementNS("http://www.w3.org/2000/svg", "g")
  1517. // 创建圆柱体的主体部分
  1518. const cylinderBody = document.createElementNS(
  1519. "http://www.w3.org/2000/svg",
  1520. "path"
  1521. )
  1522. cylinderBody.setAttribute(
  1523. "d",
  1524. `M0,${element.height * 0.15} ` +
  1525. `A${element.width / 2},${element.height * 0.15} 0 0 1 ${
  1526. element.width
  1527. },${element.height * 0.15} ` +
  1528. `V${element.height * 0.85} ` +
  1529. `A${element.width / 2},${element.height * 0.15} 0 0 1 0,${
  1530. element.height * 0.85
  1531. } Z`
  1532. )
  1533. // 创建顶部椭圆
  1534. const topEllipse = document.createElementNS(
  1535. "http://www.w3.org/2000/svg",
  1536. "ellipse"
  1537. )
  1538. topEllipse.setAttribute("cx", element.width / 2)
  1539. topEllipse.setAttribute("cy", element.height * 0.15)
  1540. topEllipse.setAttribute("rx", element.width / 2)
  1541. topEllipse.setAttribute("ry", element.height * 0.15)
  1542. // 设置填充色
  1543. setBackground(element, cylinderBody)
  1544. setBackground(element, topEllipse)
  1545. // 设置边框
  1546. if (element.borderWidth > 0) {
  1547. const borderColor = element.borderColor || "#000"
  1548. const borderWidth = element.borderWidth || 1
  1549. cylinderBody.setAttribute("stroke", borderColor)
  1550. cylinderBody.setAttribute("stroke-width", borderWidth)
  1551. topEllipse.setAttribute("stroke", borderColor)
  1552. topEllipse.setAttribute("stroke-width", borderWidth)
  1553. // 处理虚线边框
  1554. if (
  1555. element.borderType === "dotted" ||
  1556. element.borderType === "dashed"
  1557. ) {
  1558. if (element.borderStrokeDasharray) {
  1559. const dashArray = element.borderStrokeDasharray
  1560. cylinderBody.setAttribute("stroke-dasharray", dashArray)
  1561. topEllipse.setAttribute("stroke-dasharray", dashArray)
  1562. } else if (element.borderType === "dotted") {
  1563. cylinderBody.setAttribute("stroke-dasharray", "1, 3")
  1564. topEllipse.setAttribute("stroke-dasharray", "1, 3")
  1565. } else if (element.borderType === "dashed") {
  1566. cylinderBody.setAttribute("stroke-dasharray", "5, 5")
  1567. topEllipse.setAttribute("stroke-dasharray", "5, 5")
  1568. }
  1569. }
  1570. }
  1571. can.appendChild(cylinderBody)
  1572. can.appendChild(topEllipse)
  1573. svg.appendChild(can)
  1574. break
  1575. case "cube":
  1576. const cube = document.createElementNS("http://www.w3.org/2000/svg", "g")
  1577. // 计算关键点坐标
  1578. const offset = element.width * 0.2
  1579. const frontX = offset
  1580. const frontY = offset
  1581. const frontW = element.width - offset
  1582. const frontH = element.height
  1583. // 设置立方体的三个面的路径
  1584. const frontFace = document.createElementNS(
  1585. "http://www.w3.org/2000/svg",
  1586. "path"
  1587. )
  1588. frontFace.setAttribute(
  1589. "d",
  1590. `M${frontX},${frontY} ` +
  1591. `L${frontW},${frontY} ` +
  1592. `L${frontW},${frontH} ` +
  1593. `L${frontX},${frontH} Z`
  1594. )
  1595. const rightFace = document.createElementNS(
  1596. "http://www.w3.org/2000/svg",
  1597. "path"
  1598. )
  1599. rightFace.setAttribute(
  1600. "d",
  1601. `M${frontW},${frontY} ` +
  1602. `L${element.width},0 ` +
  1603. `L${element.width},${element.height - offset} ` +
  1604. `L${frontW},${frontH} Z`
  1605. )
  1606. const topFace = document.createElementNS(
  1607. "http://www.w3.org/2000/svg",
  1608. "path"
  1609. )
  1610. topFace.setAttribute(
  1611. "d",
  1612. `M${frontX},${frontY} ` +
  1613. `L${frontW - offset - frontX},0 ` + // 修改这里:改为从(0,0)开始
  1614. `L${element.width - offset},0 ` + // 修改这里:使用 offset 来计算右上角的位置
  1615. `L${element.width},0 ` +
  1616. `L${frontW},${frontY} Z`
  1617. )
  1618. // 设置填充色
  1619. if (element.fill && element.fill.type === "color") {
  1620. const fillColor = element.fill.value || "transparent"
  1621. frontFace.setAttribute("fill", fillColor)
  1622. rightFace.setAttribute("fill", adjustBrightness(fillColor, 0.8))
  1623. topFace.setAttribute("fill", adjustBrightness(fillColor, 1.2))
  1624. } else {
  1625. frontFace.setAttribute("fill", "transparent")
  1626. rightFace.setAttribute("fill", "transparent")
  1627. topFace.setAttribute("fill", "transparent")
  1628. }
  1629. // 设置边框
  1630. if (element.borderWidth > 0) {
  1631. const borderColor = element.borderColor || "#000"
  1632. const borderWidth = element.borderWidth || 1
  1633. frontFace.setAttribute("stroke", borderColor)
  1634. frontFace.setAttribute("stroke-width", borderWidth)
  1635. rightFace.setAttribute("stroke", borderColor)
  1636. rightFace.setAttribute("stroke-width", borderWidth)
  1637. topFace.setAttribute("stroke", borderColor)
  1638. topFace.setAttribute("stroke-width", borderWidth)
  1639. if (
  1640. element.borderType === "dotted" ||
  1641. element.borderType === "dashed"
  1642. ) {
  1643. const dashArray =
  1644. element.borderStrokeDasharray ||
  1645. (element.borderType === "dotted" ? "1, 3" : "5, 5")
  1646. frontFace.setAttribute("stroke-dasharray", dashArray)
  1647. rightFace.setAttribute("stroke-dasharray", dashArray)
  1648. topFace.setAttribute("stroke-dasharray", dashArray)
  1649. }
  1650. }
  1651. // 按正确的顺序添加面(从后到前)
  1652. cube.appendChild(rightFace)
  1653. cube.appendChild(topFace)
  1654. cube.appendChild(frontFace)
  1655. svg.appendChild(cube)
  1656. break
  1657. case "bevel":
  1658. const bevel = document.createElementNS("http://www.w3.org/2000/svg", "g")
  1659. // 计算关键点坐标
  1660. const bevelOffset = element.width * 0.2
  1661. const smallRectX = bevelOffset
  1662. const smallRectY = bevelOffset
  1663. const smallRectW = element.width - 2 * bevelOffset
  1664. const smallRectH = element.height - 2 * bevelOffset
  1665. // 绘制顶部小矩形
  1666. const topRect = document.createElementNS(
  1667. "http://www.w3.org/2000/svg",
  1668. "rect"
  1669. )
  1670. topRect.setAttribute("x", smallRectX)
  1671. topRect.setAttribute("y", smallRectY)
  1672. topRect.setAttribute("width", smallRectW)
  1673. topRect.setAttribute("height", smallRectH)
  1674. // 绘制四个梯形
  1675. const topTrapezoid = document.createElementNS(
  1676. "http://www.w3.org/2000/svg",
  1677. "path"
  1678. )
  1679. topTrapezoid.setAttribute(
  1680. "d",
  1681. `M0,0 L${element.width},0 L${
  1682. element.width - bevelOffset
  1683. },${bevelOffset} L${bevelOffset},${bevelOffset} Z`
  1684. )
  1685. const bottomTrapezoid = document.createElementNS(
  1686. "http://www.w3.org/2000/svg",
  1687. "path"
  1688. )
  1689. bottomTrapezoid.setAttribute(
  1690. "d",
  1691. `M${bevelOffset},${element.height - bevelOffset} L${
  1692. element.width - bevelOffset
  1693. },${element.height - bevelOffset} L${element.width},${
  1694. element.height
  1695. } L0,${element.height} Z`
  1696. )
  1697. const leftTrapezoid = document.createElementNS(
  1698. "http://www.w3.org/2000/svg",
  1699. "path"
  1700. )
  1701. leftTrapezoid.setAttribute(
  1702. "d",
  1703. `M0,0 L${bevelOffset},${bevelOffset} L${bevelOffset},${
  1704. element.height - bevelOffset
  1705. } L0,${element.height} Z`
  1706. )
  1707. const rightTrapezoid = document.createElementNS(
  1708. "http://www.w3.org/2000/svg",
  1709. "path"
  1710. )
  1711. rightTrapezoid.setAttribute(
  1712. "d",
  1713. `M${element.width},0 L${element.width},${element.height} L${
  1714. element.width - bevelOffset
  1715. },${element.height - bevelOffset} L${
  1716. element.width - bevelOffset
  1717. },${bevelOffset} Z`
  1718. )
  1719. // 设置填充色
  1720. if (element.fill && element.fill.type === "color") {
  1721. const fillColor = element.fill.value || "transparent"
  1722. topRect.setAttribute("fill", fillColor)
  1723. topTrapezoid.setAttribute("fill", adjustBrightness(fillColor, 1.2))
  1724. bottomTrapezoid.setAttribute("fill", adjustBrightness(fillColor, 0.8))
  1725. leftTrapezoid.setAttribute("fill", adjustBrightness(fillColor, 0.9))
  1726. rightTrapezoid.setAttribute("fill", adjustBrightness(fillColor, 0.7))
  1727. } else {
  1728. topRect.setAttribute("fill", "transparent")
  1729. topTrapezoid.setAttribute("fill", "transparent")
  1730. bottomTrapezoid.setAttribute("fill", "transparent")
  1731. leftTrapezoid.setAttribute("fill", "transparent")
  1732. rightTrapezoid.setAttribute("fill", "transparent")
  1733. }
  1734. // 设置边框
  1735. if (element.borderWidth > 0) {
  1736. const borderColor = element.borderColor || "#000"
  1737. const borderWidth = element.borderWidth || 1
  1738. const parts = [
  1739. topRect,
  1740. topTrapezoid,
  1741. bottomTrapezoid,
  1742. leftTrapezoid,
  1743. rightTrapezoid,
  1744. ]
  1745. parts.forEach((part) => {
  1746. part.setAttribute("stroke", borderColor)
  1747. part.setAttribute("stroke-width", borderWidth)
  1748. if (
  1749. element.borderType === "dotted" ||
  1750. element.borderType === "dashed"
  1751. ) {
  1752. const dashArray =
  1753. element.borderStrokeDasharray ||
  1754. (element.borderType === "dotted" ? "1, 3" : "5, 5")
  1755. part.setAttribute("stroke-dasharray", dashArray)
  1756. }
  1757. })
  1758. }
  1759. // 按正确的顺序添加面(从后到前)
  1760. bevel.appendChild(bottomTrapezoid)
  1761. bevel.appendChild(leftTrapezoid)
  1762. bevel.appendChild(rightTrapezoid)
  1763. bevel.appendChild(topTrapezoid)
  1764. bevel.appendChild(topRect)
  1765. svg.appendChild(bevel)
  1766. break
  1767. case "donut":
  1768. const donut = document.createElementNS("http://www.w3.org/2000/svg", "g")
  1769. // 外圆
  1770. const outerCircle = document.createElementNS(
  1771. "http://www.w3.org/2000/svg",
  1772. "circle"
  1773. )
  1774. outerCircle.setAttribute("cx", element.width / 2)
  1775. outerCircle.setAttribute("cy", element.height / 2)
  1776. outerCircle.setAttribute("r", Math.min(element.width, element.height) / 2)
  1777. // 内圆
  1778. const innerCircle = document.createElementNS(
  1779. "http://www.w3.org/2000/svg",
  1780. "circle"
  1781. )
  1782. const fmla = element?.formulas[0].split(" ")[1]
  1783. console.log('fmla', fmla)
  1784. innerCircle.setAttribute("cx", element.width / 2)
  1785. innerCircle.setAttribute("cy", element.height / 2)
  1786. innerCircle.setAttribute("r", Math.min(element.width, element.height)/2 * (1- Math.sqrt(fmla/100000)/2))
  1787. // 设置填充色
  1788. setBackground(element, outerCircle)
  1789. innerCircle.setAttribute("fill", "white")
  1790. // 设置边框
  1791. if (element.borderWidth > 0) {
  1792. const borderColor = element.borderColor || "#000"
  1793. const borderWidth = element.borderWidth || 1
  1794. outerCircle.setAttribute("stroke", borderColor)
  1795. outerCircle.setAttribute("stroke-width", borderWidth)
  1796. innerCircle.setAttribute("stroke", borderColor)
  1797. innerCircle.setAttribute("stroke-width", borderWidth)
  1798. if (
  1799. element.borderType === "dotted" ||
  1800. element.borderType === "dashed"
  1801. ) {
  1802. const dashArray =
  1803. element.borderStrokeDasharray ||
  1804. (element.borderType === "dotted" ? "1, 3" : "5, 5")
  1805. outerCircle.setAttribute("stroke-dasharray", dashArray)
  1806. innerCircle.setAttribute("stroke-dasharray", dashArray)
  1807. }
  1808. }
  1809. donut.appendChild(outerCircle)
  1810. donut.appendChild(innerCircle)
  1811. svg.appendChild(donut)
  1812. break
  1813. case "noSmoking":
  1814. const noSmoking = document.createElementNS(
  1815. "http://www.w3.org/2000/svg",
  1816. "g"
  1817. )
  1818. // 创建路径
  1819. const path = document.createElementNS(
  1820. "http://www.w3.org/2000/svg",
  1821. "path"
  1822. )
  1823. path.setAttribute(
  1824. "d",
  1825. "M0,70 A77,70 0 1,1 0,71 Z M123.80284467265982,99.39738105155146 A57.5386,50.5386 0 0 0 45.160427644134444,27.90427466198293 Z M30.197155327340184,40.602618948448544 A57.5386,50.5386 0 0 0 108.83957235586556,112.09572533801708 Z"
  1826. )
  1827. path.setAttribute("fill", "rgba(255,217,102,1)")
  1828. path.setAttribute("stroke", "rgba(23,44,81,1)")
  1829. path.setAttribute("stroke-width", "1px")
  1830. path.setAttribute("stroke-dasharray", "")
  1831. path.setAttribute("stroke-linecap", "butt")
  1832. path.setAttribute("stroke-linejoin", "round")
  1833. noSmoking.appendChild(path)
  1834. svg.appendChild(noSmoking)
  1835. break
  1836. case "rightArrow":
  1837. const rightArrow = document.createElementNS(
  1838. "http://www.w3.org/2000/svg",
  1839. "polygon"
  1840. )
  1841. rightArrow.setAttribute(
  1842. "points",
  1843. `0,${element.height * 0.3} ${element.width * 0.7},${
  1844. element.height * 0.3
  1845. } ` +
  1846. `${element.width * 0.7},0 ${element.width},${element.height * 0.5} ` +
  1847. `${element.width * 0.7},${element.height} ${element.width * 0.7},${
  1848. element.height * 0.7
  1849. } ` +
  1850. `0,${element.height * 0.7}`
  1851. )
  1852. // 设置填充色
  1853. setBackground(element, rightArrow)
  1854. // 设置边框
  1855. if (element.borderWidth > 0) {
  1856. rightArrow.setAttribute("stroke", element.borderColor || "#000")
  1857. rightArrow.setAttribute("stroke-width", element.borderWidth || 1)
  1858. // 处理虚线边框
  1859. if (
  1860. element.borderType === "dotted" ||
  1861. element.borderType === "dashed"
  1862. ) {
  1863. if (element.borderStrokeDasharray) {
  1864. rightArrow.setAttribute(
  1865. "stroke-dasharray",
  1866. element.borderStrokeDasharray
  1867. )
  1868. } else if (element.borderType === "dotted") {
  1869. rightArrow.setAttribute("stroke-dasharray", "1, 3")
  1870. } else if (element.borderType === "dashed") {
  1871. rightArrow.setAttribute("stroke-dasharray", "5, 5")
  1872. }
  1873. }
  1874. }
  1875. svg.appendChild(rightArrow)
  1876. break
  1877. case "leftArrow":
  1878. const leftArrow = document.createElementNS(
  1879. "http://www.w3.org/2000/svg",
  1880. "polygon"
  1881. )
  1882. leftArrow.setAttribute(
  1883. "points",
  1884. `${element.width},${element.height * 0.3} ${element.width * 0.3},${
  1885. element.height * 0.3
  1886. } ` +
  1887. `${element.width * 0.3},0 0,${element.height * 0.5} ` +
  1888. `${element.width * 0.3},${element.height} ${element.width * 0.3},${
  1889. element.height * 0.7
  1890. } ` +
  1891. `${element.width},${element.height * 0.7}`
  1892. )
  1893. // 设置填充色
  1894. setBackground(element, leftArrow)
  1895. // 设置边框
  1896. if (element.borderWidth > 0) {
  1897. leftArrow.setAttribute("stroke", element.borderColor || "#000")
  1898. leftArrow.setAttribute("stroke-width", element.borderWidth || 1)
  1899. // 处理虚线边框
  1900. if (
  1901. element.borderType === "dotted" ||
  1902. element.borderType === "dashed"
  1903. ) {
  1904. if (element.borderStrokeDasharray) {
  1905. leftArrow.setAttribute(
  1906. "stroke-dasharray",
  1907. element.borderStrokeDasharray
  1908. )
  1909. } else if (element.borderType === "dotted") {
  1910. leftArrow.setAttribute("stroke-dasharray", "1, 3")
  1911. } else if (element.borderType === "dashed") {
  1912. leftArrow.setAttribute("stroke-dasharray", "5, 5")
  1913. }
  1914. }
  1915. }
  1916. svg.appendChild(leftArrow)
  1917. break
  1918. case "upArrow":
  1919. const upArrow = document.createElementNS(
  1920. "http://www.w3.org/2000/svg",
  1921. "polygon"
  1922. )
  1923. upArrow.setAttribute(
  1924. "points",
  1925. `${element.width * 0.3},${element.height} ${element.width * 0.3},${
  1926. element.height * 0.3
  1927. } ` +
  1928. `0,${element.height * 0.3} ${element.width * 0.5},0 ` +
  1929. `${element.width},${element.height * 0.3} ${element.width * 0.7},${
  1930. element.height * 0.3
  1931. } ` +
  1932. `${element.width * 0.7},${element.height}`
  1933. )
  1934. // 设置填充色
  1935. setBackground(element, upArrow)
  1936. // 设置边框
  1937. if (element.borderWidth > 0) {
  1938. upArrow.setAttribute("stroke", element.borderColor || "#000")
  1939. upArrow.setAttribute("stroke-width", element.borderWidth || 1)
  1940. // 处理虚线边框
  1941. if (
  1942. element.borderType === "dotted" ||
  1943. element.borderType === "dashed"
  1944. ) {
  1945. if (element.borderStrokeDasharray) {
  1946. upArrow.setAttribute(
  1947. "stroke-dasharray",
  1948. element.borderStrokeDasharray
  1949. )
  1950. } else if (element.borderType === "dotted") {
  1951. upArrow.setAttribute("stroke-dasharray", "1, 3")
  1952. } else if (element.borderType === "dashed") {
  1953. upArrow.setAttribute("stroke-dasharray", "5, 5")
  1954. }
  1955. }
  1956. }
  1957. svg.appendChild(upArrow)
  1958. break
  1959. case "downArrow":
  1960. const downArrow = document.createElementNS(
  1961. "http://www.w3.org/2000/svg",
  1962. "polygon"
  1963. )
  1964. downArrow.setAttribute(
  1965. "points",
  1966. `${element.width * 0.3},0 ${element.width * 0.3},${
  1967. element.height * 0.7
  1968. } ` +
  1969. `0,${element.height * 0.7} ${element.width * 0.5},${
  1970. element.height
  1971. } ` +
  1972. `${element.width},${element.height * 0.7} ${element.width * 0.7},${
  1973. element.height * 0.7
  1974. } ` +
  1975. `${element.width * 0.7},0`
  1976. )
  1977. // 设置填充色
  1978. setBackground(element, downArrow)
  1979. // 设置边框
  1980. if (element.borderWidth > 0) {
  1981. downArrow.setAttribute("stroke", element.borderColor || "#000")
  1982. downArrow.setAttribute("stroke-width", element.borderWidth || 1)
  1983. // 处理虚线边框
  1984. if (
  1985. element.borderType === "dotted" ||
  1986. element.borderType === "dashed"
  1987. ) {
  1988. if (element.borderStrokeDasharray) {
  1989. downArrow.setAttribute(
  1990. "stroke-dasharray",
  1991. element.borderStrokeDasharray
  1992. )
  1993. } else if (element.borderType === "dotted") {
  1994. downArrow.setAttribute("stroke-dasharray", "1, 3")
  1995. } else if (element.borderType === "dashed") {
  1996. downArrow.setAttribute("stroke-dasharray", "5, 5")
  1997. }
  1998. }
  1999. }
  2000. svg.appendChild(downArrow)
  2001. break
  2002. case "leftRightArrow":
  2003. const leftRightArrow = document.createElementNS(
  2004. "http://www.w3.org/2000/svg",
  2005. "polygon"
  2006. )
  2007. leftRightArrow.setAttribute(
  2008. "points",
  2009. `0,${element.height * 0.5} ${element.width * 0.2},${
  2010. element.height * 0.2
  2011. } ` +
  2012. `${element.width * 0.2},${element.height * 0.4} ${
  2013. element.width * 0.8
  2014. },${element.height * 0.4} ` +
  2015. `${element.width * 0.8},${element.height * 0.2} ${element.width},${
  2016. element.height * 0.5
  2017. } ` +
  2018. `${element.width * 0.8},${element.height * 0.8} ${
  2019. element.width * 0.8
  2020. },${element.height * 0.6} ` +
  2021. `${element.width * 0.2},${element.height * 0.6} ${
  2022. element.width * 0.2
  2023. },${element.height * 0.8}`
  2024. )
  2025. // 设置填充色
  2026. setBackground(element, leftRightArrow)
  2027. // 设置边框
  2028. if (element.borderWidth > 0) {
  2029. leftRightArrow.setAttribute("stroke", element.borderColor || "#000")
  2030. leftRightArrow.setAttribute("stroke-width", element.borderWidth || 1)
  2031. // 处理虚线边框
  2032. if (
  2033. element.borderType === "dotted" ||
  2034. element.borderType === "dashed"
  2035. ) {
  2036. if (element.borderStrokeDasharray) {
  2037. leftRightArrow.setAttribute(
  2038. "stroke-dasharray",
  2039. element.borderStrokeDasharray
  2040. )
  2041. } else if (element.borderType === "dotted") {
  2042. leftRightArrow.setAttribute("stroke-dasharray", "1, 3")
  2043. } else if (element.borderType === "dashed") {
  2044. leftRightArrow.setAttribute("stroke-dasharray", "5, 5")
  2045. }
  2046. }
  2047. }
  2048. svg.appendChild(leftRightArrow)
  2049. break
  2050. case "upDownArrow":
  2051. const upDownArrow = document.createElementNS(
  2052. "http://www.w3.org/2000/svg",
  2053. "polygon"
  2054. )
  2055. upDownArrow.setAttribute(
  2056. "points",
  2057. `${element.width * 0.5},0 ${element.width * 0.3},${
  2058. element.height * 0.2
  2059. } ` +
  2060. `${element.width * 0.4},${element.height * 0.2} ${
  2061. element.width * 0.4
  2062. },${element.height * 0.8} ` +
  2063. `${element.width * 0.3},${element.height * 0.8} ${
  2064. element.width * 0.5
  2065. },${element.height} ` +
  2066. `${element.width * 0.7},${element.height * 0.8} ${
  2067. element.width * 0.6
  2068. },${element.height * 0.8} ` +
  2069. `${element.width * 0.6},${element.height * 0.2} ${
  2070. element.width * 0.7
  2071. },${element.height * 0.2}`
  2072. )
  2073. // 设置填充色
  2074. setBackground(element, upDownArrow)
  2075. // 设置边框
  2076. if (element.borderWidth > 0) {
  2077. upDownArrow.setAttribute("stroke", element.borderColor || "#000")
  2078. upDownArrow.setAttribute("stroke-width", element.borderWidth || 1)
  2079. // 处理虚线边框
  2080. if (
  2081. element.borderType === "dotted" ||
  2082. element.borderType === "dashed"
  2083. ) {
  2084. if (element.borderStrokeDasharray) {
  2085. upDownArrow.setAttribute(
  2086. "stroke-dasharray",
  2087. element.borderStrokeDasharray
  2088. )
  2089. } else if (element.borderType === "dotted") {
  2090. upDownArrow.setAttribute("stroke-dasharray", "1, 3")
  2091. } else if (element.borderType === "dashed") {
  2092. upDownArrow.setAttribute("stroke-dasharray", "5, 5")
  2093. }
  2094. }
  2095. }
  2096. svg.appendChild(upDownArrow)
  2097. break
  2098. case "quadArrow":
  2099. const quadArrow = document.createElementNS(
  2100. "http://www.w3.org/2000/svg",
  2101. "path"
  2102. )
  2103. // 计算缩放比例
  2104. const scale = Math.min(element.width / 167, element.height / 121)
  2105. const offsetX = (element.width - 167 * scale) / 2
  2106. const offsetY = (element.height - 121 * scale) / 2
  2107. // 构建路径数据
  2108. const pathData = `
  2109. M${offsetX},${60.5 * scale + offsetY}
  2110. L${27.225 * scale + offsetX},${33.275 * scale + offsetY}
  2111. L${27.225 * scale + offsetX},${46.8875 * scale + offsetY}
  2112. L${69.8875 * scale + offsetX},${46.8875 * scale + offsetY}
  2113. L${69.8875 * scale + offsetX},${27.225 * scale + offsetY}
  2114. L${56.275 * scale + offsetX},${27.225 * scale + offsetY}
  2115. L${83.5 * scale + offsetX},${offsetY}
  2116. L${110.725 * scale + offsetX},${27.225 * scale + offsetY}
  2117. L${97.1125 * scale + offsetX},${27.225 * scale + offsetY}
  2118. L${97.1125 * scale + offsetX},${46.8875 * scale + offsetY}
  2119. L${139.775 * scale + offsetX},${46.8875 * scale + offsetY}
  2120. L${139.775 * scale + offsetX},${33.275 * scale + offsetY}
  2121. L${167 * scale + offsetX},${60.5 * scale + offsetY}
  2122. L${139.775 * scale + offsetX},${87.725 * scale + offsetY}
  2123. L${139.775 * scale + offsetX},${74.1125 * scale + offsetY}
  2124. L${97.1125 * scale + offsetX},${74.1125 * scale + offsetY}
  2125. L${97.1125 * scale + offsetX},${93.775 * scale + offsetY}
  2126. L${110.725 * scale + offsetX},${93.775 * scale + offsetY}
  2127. L${83.5 * scale + offsetX},${121 * scale + offsetY}
  2128. L${56.275 * scale + offsetX},${93.775 * scale + offsetY}
  2129. L${69.8875 * scale + offsetX},${93.775 * scale + offsetY}
  2130. L${69.8875 * scale + offsetX},${74.1125 * scale + offsetY}
  2131. L${27.225 * scale + offsetX},${74.1125 * scale + offsetY}
  2132. L${27.225 * scale + offsetX},${87.725 * scale + offsetY}
  2133. Z`
  2134. quadArrow.setAttribute("d", pathData)
  2135. // 设置填充色
  2136. setBackground(element, quadArrow)
  2137. // 设置边框
  2138. if (element.borderWidth > 0) {
  2139. quadArrow.setAttribute("stroke", element.borderColor || "#000")
  2140. quadArrow.setAttribute("stroke-width", element.borderWidth || 1)
  2141. quadArrow.setAttribute("stroke-linecap", "butt")
  2142. quadArrow.setAttribute("stroke-linejoin", "round")
  2143. // 处理虚线边框
  2144. if (
  2145. element.borderType === "dotted" ||
  2146. element.borderType === "dashed"
  2147. ) {
  2148. if (element.borderStrokeDasharray) {
  2149. quadArrow.setAttribute(
  2150. "stroke-dasharray",
  2151. element.borderStrokeDasharray
  2152. )
  2153. } else if (element.borderType === "dotted") {
  2154. quadArrow.setAttribute("stroke-dasharray", "1, 3")
  2155. } else if (element.borderType === "dashed") {
  2156. quadArrow.setAttribute("stroke-dasharray", "5, 5")
  2157. }
  2158. }
  2159. }
  2160. svg.appendChild(quadArrow)
  2161. break
  2162. case "leftRightUpArrow":
  2163. const leftRightUpArrow = document.createElementNS(
  2164. "http://www.w3.org/2000/svg",
  2165. "path"
  2166. )
  2167. // 计算缩放比例
  2168. const scale2 = Math.min(element.width / 167, element.height / 121)
  2169. const offsetX2 = (element.width - 167 * scale2) / 2
  2170. const offsetY2 = (element.height - 121 * scale2) / 2
  2171. // 构建路径数据
  2172. const pathData2 = `
  2173. M${offsetX2},${60.5 * scale2 + offsetY2}
  2174. L${27.225 * scale2 + offsetX2},${33.275 * scale2 + offsetY2}
  2175. L${27.225 * scale2 + offsetX2},${46.8875 * scale2 + offsetY2}
  2176. L${69.8875 * scale2 + offsetX2},${46.8875 * scale2 + offsetY2}
  2177. L${69.8875 * scale2 + offsetX2},${27.225 * scale2 + offsetY2}
  2178. L${56.275 * scale2 + offsetX2},${27.225 * scale2 + offsetY2}
  2179. L${83.5 * scale2 + offsetX2},${offsetY2}
  2180. L${110.725 * scale2 + offsetX2},${27.225 * scale2 + offsetY2}
  2181. L${97.1125 * scale2 + offsetX2},${27.225 * scale2 + offsetY2}
  2182. L${97.1125 * scale2 + offsetX2},${46.8875 * scale2 + offsetY2}
  2183. L${139.775 * scale2 + offsetX2},${46.8875 * scale2 + offsetY2}
  2184. L${139.775 * scale2 + offsetX2},${33.275 * scale2 + offsetY2}
  2185. L${167 * scale2 + offsetX2},${60.5 * scale2 + offsetY2}
  2186. L${139.775 * scale2 + offsetX2},${87.725 * scale2 + offsetY2}
  2187. L${139.775 * scale2 + offsetX2},${74.1125 * scale2 + offsetY2}
  2188. L${97.1125 * scale2 + offsetX2},${74.1125 * scale2 + offsetY2}
  2189. L${69.8875 * scale2 + offsetX2},${74.1125 * scale2 + offsetY2}
  2190. L${27.225 * scale2 + offsetX2},${74.1125 * scale2 + offsetY2}
  2191. L${27.225 * scale2 + offsetX2},${87.725 * scale2 + offsetY2}
  2192. Z`
  2193. leftRightUpArrow.setAttribute("d", pathData2)
  2194. // 设置填充色
  2195. setBackground(element, leftRightUpArrow)
  2196. // 设置边框
  2197. if (element.borderWidth > 0) {
  2198. leftRightUpArrow.setAttribute("stroke", element.borderColor || "#000")
  2199. leftRightUpArrow.setAttribute("stroke-width", element.borderWidth || 1)
  2200. leftRightUpArrow.setAttribute("stroke-linecap", "butt")
  2201. leftRightUpArrow.setAttribute("stroke-linejoin", "round")
  2202. // 处理虚线边框
  2203. if (
  2204. element.borderType === "dotted" ||
  2205. element.borderType === "dashed"
  2206. ) {
  2207. if (element.borderStrokeDasharray) {
  2208. leftRightUpArrow.setAttribute(
  2209. "stroke-dasharray",
  2210. element.borderStrokeDasharray
  2211. )
  2212. } else if (element.borderType === "dotted") {
  2213. leftRightUpArrow.setAttribute("stroke-dasharray", "1, 3")
  2214. } else if (element.borderType === "dashed") {
  2215. leftRightUpArrow.setAttribute("stroke-dasharray", "5, 5")
  2216. }
  2217. }
  2218. }
  2219. svg.appendChild(leftRightUpArrow)
  2220. break
  2221. case "bentArrow":
  2222. const bentArrow = document.createElementNS(
  2223. "http://www.w3.org/2000/svg",
  2224. "path"
  2225. )
  2226. // 构建路径数据
  2227. const pathData3 = `
  2228. M0,${element.height * 0.88}
  2229. L0,${element.height * 0.495}
  2230. A${element.width * 0.385} ${element.height * 0.385} 0 0 1 ${
  2231. element.width * 0.385
  2232. } ${element.height * 0.11}
  2233. L${element.width * 0.67},${element.height * 0.11}
  2234. L${element.width * 0.67},0
  2235. L${element.width * 0.89},${element.height * 0.22}
  2236. L${element.width * 0.67},${element.height * 0.44}
  2237. L${element.width * 0.67},${element.height * 0.33}
  2238. L${element.width * 0.385},${element.height * 0.33}
  2239. A${element.width * 0.165} ${element.height * 0.165} 0 0 0 ${
  2240. element.width * 0.22
  2241. } ${element.height * 0.495}
  2242. L${element.width * 0.22},${element.height * 0.88}
  2243. Z`
  2244. bentArrow.setAttribute("d", pathData3)
  2245. // 设置填充色
  2246. setBackground(element, bentArrow)
  2247. // 设置边框
  2248. if (element.borderWidth > 0) {
  2249. bentArrow.setAttribute("stroke", element.borderColor || "#000")
  2250. bentArrow.setAttribute("stroke-width", element.borderWidth || 1)
  2251. bentArrow.setAttribute("stroke-linecap", "butt")
  2252. bentArrow.setAttribute("stroke-linejoin", "round")
  2253. // 处理虚线边框
  2254. if (
  2255. element.borderType === "dotted" ||
  2256. element.borderType === "dashed"
  2257. ) {
  2258. if (element.borderStrokeDasharray) {
  2259. bentArrow.setAttribute(
  2260. "stroke-dasharray",
  2261. element.borderStrokeDasharray
  2262. )
  2263. } else if (element.borderType === "dotted") {
  2264. bentArrow.setAttribute("stroke-dasharray", "1, 3")
  2265. } else if (element.borderType === "dashed") {
  2266. bentArrow.setAttribute("stroke-dasharray", "5, 5")
  2267. }
  2268. }
  2269. }
  2270. svg.appendChild(bentArrow)
  2271. break
  2272. case "parallelogram":
  2273. const parallelogram = document.createElementNS(
  2274. "http://www.w3.org/2000/svg",
  2275. "polygon"
  2276. )
  2277. parallelogram.setAttribute(
  2278. "points",
  2279. `${element.width * 0.25},0 ${element.width},0 ${element.width * 0.75},${
  2280. element.height
  2281. } 0,${element.height}`
  2282. )
  2283. // 设置填充色
  2284. setBackground(element, parallelogram)
  2285. // 设置边框
  2286. if (element.borderWidth > 0) {
  2287. parallelogram.setAttribute("stroke", element.borderColor || "#000")
  2288. parallelogram.setAttribute("stroke-width", element.borderWidth || 1)
  2289. // 处理虚线边框
  2290. if (
  2291. element.borderType === "dotted" ||
  2292. element.borderType === "dashed"
  2293. ) {
  2294. if (element.borderStrokeDasharray) {
  2295. parallelogram.setAttribute(
  2296. "stroke-dasharray",
  2297. element.borderStrokeDasharray
  2298. )
  2299. } else if (element.borderType === "dotted") {
  2300. parallelogram.setAttribute("stroke-dasharray", "1, 3")
  2301. } else if (element.borderType === "dashed") {
  2302. parallelogram.setAttribute("stroke-dasharray", "5, 5")
  2303. }
  2304. }
  2305. }
  2306. svg.appendChild(parallelogram)
  2307. break
  2308. case "uturnArrow":
  2309. const uturnArrow = document.createElementNS(
  2310. "http://www.w3.org/2000/svg",
  2311. "path"
  2312. )
  2313. // 构建路径数据
  2314. const pathDataUturn = `
  2315. M0,${element.height * 0.745}
  2316. L0,${element.height * 0.179375}
  2317. A${element.width * 0.179375} ${element.height * 0.179375} 0 0 1 ${
  2318. element.width * 0.179375
  2319. },0
  2320. L${element.width * 0.179375},0
  2321. A${element.width * 0.179375} ${element.height * 0.179375} 0 0 1 ${
  2322. element.width * 0.359375
  2323. },${element.height * 0.179375}
  2324. L${element.width * 0.359375},${element.height * 0.205}
  2325. L${element.width * 0.41},${element.height * 0.205}
  2326. L${element.width * 0.3075},${element.height * 0.3075}
  2327. L${element.width * 0.205},${element.height * 0.205}
  2328. L${element.width * 0.25625},${element.height * 0.205}
  2329. L${element.width * 0.25625},${element.height * 0.179375}
  2330. A${element.width * 0.076875} ${element.height * 0.076875} 0 0 0 ${
  2331. element.width * 0.179375
  2332. },${element.height * 0.1025}
  2333. L${element.width * 0.179375},${element.height * 0.1025}
  2334. A${element.width * 0.076875} ${element.height * 0.076875} 0 0 0 ${
  2335. element.width * 0.1025
  2336. },${element.height * 0.179375}
  2337. L${element.width * 0.1025},${element.height * 0.745}
  2338. Z`
  2339. uturnArrow.setAttribute("d", pathDataUturn)
  2340. // 设置填充色
  2341. setBackground(element, uturnArrow)
  2342. // 设置边框
  2343. if (element.borderWidth > 0) {
  2344. uturnArrow.setAttribute("stroke", element.borderColor || "#000")
  2345. uturnArrow.setAttribute("stroke-width", element.borderWidth || 1)
  2346. uturnArrow.setAttribute("stroke-linecap", "butt")
  2347. uturnArrow.setAttribute("stroke-linejoin", "round")
  2348. // 处理虚线边框
  2349. if (
  2350. element.borderType === "dotted" ||
  2351. element.borderType === "dashed"
  2352. ) {
  2353. if (element.borderStrokeDasharray) {
  2354. uturnArrow.setAttribute(
  2355. "stroke-dasharray",
  2356. element.borderStrokeDasharray
  2357. )
  2358. } else if (element.borderType === "dotted") {
  2359. uturnArrow.setAttribute("stroke-dasharray", "1, 3")
  2360. } else if (element.borderType === "dashed") {
  2361. uturnArrow.setAttribute("stroke-dasharray", "5, 5")
  2362. }
  2363. }
  2364. }
  2365. svg.appendChild(uturnArrow)
  2366. break
  2367. case "leftUpArrow":
  2368. const leftUpArrow = document.createElementNS(
  2369. "http://www.w3.org/2000/svg",
  2370. "path"
  2371. )
  2372. // 使用提供的路径数据
  2373. const pathDataLeftUp = `
  2374. M0,${element.height * 0.65}
  2375. L${element.width * 0.15},${element.height * 0.4}
  2376. L${element.width * 0.15},${element.height * 0.55}
  2377. L${element.width * 0.5},${element.height * 0.55}
  2378. L${element.width * 0.5},${element.height * 0.1}
  2379. L${element.width * 0.35},${element.height * 0.1}
  2380. L${element.width * 0.65},0
  2381. L${element.width * 0.85},${element.height * 0.1}
  2382. L${element.width * 0.75},${element.height * 0.1}
  2383. L${element.width * 0.75},${element.height * 0.85}
  2384. L${element.width * 0.15},${element.height * 0.85}
  2385. L${element.width * 0.15},${element.height * 1}
  2386. Z`
  2387. leftUpArrow.setAttribute("d", pathDataLeftUp)
  2388. // 设置填充色
  2389. setBackground(element, leftUpArrow)
  2390. // 设置边框
  2391. if (element.borderWidth > 0) {
  2392. leftUpArrow.setAttribute("stroke", element.borderColor || "#000")
  2393. leftUpArrow.setAttribute("stroke-width", element.borderWidth || 1)
  2394. leftUpArrow.setAttribute("stroke-linecap", "butt")
  2395. leftUpArrow.setAttribute("stroke-linejoin", "round")
  2396. // 处理虚线边框
  2397. if (
  2398. element.borderType === "dotted" ||
  2399. element.borderType === "dashed"
  2400. ) {
  2401. if (element.borderStrokeDasharray) {
  2402. leftUpArrow.setAttribute(
  2403. "stroke-dasharray",
  2404. element.borderStrokeDasharray
  2405. )
  2406. } else if (element.borderType === "dotted") {
  2407. leftUpArrow.setAttribute("stroke-dasharray", "1, 3")
  2408. } else if (element.borderType === "dashed") {
  2409. leftUpArrow.setAttribute("stroke-dasharray", "5, 5")
  2410. }
  2411. }
  2412. }
  2413. svg.appendChild(leftUpArrow)
  2414. break
  2415. case "bentUpArrow":
  2416. const bentUpArrow = document.createElementNS(
  2417. "http://www.w3.org/2000/svg",
  2418. "path"
  2419. )
  2420. // 构建路径数据,去掉左侧箭头
  2421. // 使用提供的路径数据
  2422. const pathDataBentUp = `
  2423. M0,${element.height * 0.89}
  2424. L0,${element.height * 0.7}
  2425. L${element.width * 0.575},${element.height * 0.7}
  2426. L${element.width * 0.575},${element.height * 0.2}
  2427. L${element.width * 0.46},${element.height * 0.2}
  2428. L${element.width * 0.69},0
  2429. L${element.width * 0.92},${element.height * 0.2}
  2430. L${element.width * 0.805},${element.height * 0.2}
  2431. L${element.width * 0.805},${element.height * 0.89}
  2432. Z`
  2433. bentUpArrow.setAttribute("d", pathDataBentUp)
  2434. // 设置填充色
  2435. setBackground(element, bentUpArrow)
  2436. // 设置边框
  2437. if (element.borderWidth > 0) {
  2438. bentUpArrow.setAttribute("stroke", element.borderColor || "#000")
  2439. bentUpArrow.setAttribute("stroke-width", element.borderWidth || 1)
  2440. bentUpArrow.setAttribute("stroke-linecap", "butt")
  2441. bentUpArrow.setAttribute("stroke-linejoin", "round")
  2442. // 处理虚线边框
  2443. if (
  2444. element.borderType === "dotted" ||
  2445. element.borderType === "dashed"
  2446. ) {
  2447. if (element.borderStrokeDasharray) {
  2448. bentUpArrow.setAttribute(
  2449. "stroke-dasharray",
  2450. element.borderStrokeDasharray
  2451. )
  2452. } else if (element.borderType === "dotted") {
  2453. bentUpArrow.setAttribute("stroke-dasharray", "1, 3")
  2454. } else if (element.borderType === "dashed") {
  2455. bentUpArrow.setAttribute("stroke-dasharray", "5, 5")
  2456. }
  2457. }
  2458. }
  2459. svg.appendChild(bentUpArrow)
  2460. break
  2461. case "curvedRightArrow":
  2462. const curvedRightArrow = document.createElementNS(
  2463. "http://www.w3.org/2000/svg",
  2464. "path"
  2465. )
  2466. // 使用提供的路径数据
  2467. const pathDataCurvedRight = `
  2468. M${element.width},0
  2469. A${element.width} ${element.height * 0.4} 0 0 0 0 ${
  2470. element.height * 0.4
  2471. }
  2472. L0,${element.height * 0.5}
  2473. A${element.width} ${element.height * 0.4} 0 0 1 ${element.width} ${
  2474. element.height * 0.15
  2475. }
  2476. Z
  2477. M0,${element.height * 0.4}
  2478. A${element.width} ${element.height * 0.4} 0 0 0 ${
  2479. element.width * 0.8
  2480. } ${element.height * 0.8}
  2481. L${element.width * 0.8},${element.height * 0.75}
  2482. L${element.width},${element.height * 0.875}
  2483. L${element.width * 0.8},${element.height * 1}
  2484. L${element.width * 0.8},${element.height * 0.95}
  2485. A${element.width} ${element.height * 0.4} 0 0 1 0 ${
  2486. element.height * 0.5
  2487. }
  2488. Z`
  2489. curvedRightArrow.setAttribute("d", pathDataCurvedRight)
  2490. // 设置填充色
  2491. setBackground(element, curvedRightArrow)
  2492. // 设置边框
  2493. if (element.borderWidth > 0) {
  2494. curvedRightArrow.setAttribute("stroke", element.borderColor || "#000")
  2495. curvedRightArrow.setAttribute("stroke-width", element.borderWidth || 1)
  2496. curvedRightArrow.setAttribute("stroke-linecap", "butt")
  2497. curvedRightArrow.setAttribute("stroke-linejoin", "round")
  2498. // 处理虚线边框
  2499. if (
  2500. element.borderType === "dotted" ||
  2501. element.borderType === "dashed"
  2502. ) {
  2503. if (element.borderStrokeDasharray) {
  2504. curvedRightArrow.setAttribute(
  2505. "stroke-dasharray",
  2506. element.borderStrokeDasharray
  2507. )
  2508. } else if (element.borderType === "dotted") {
  2509. curvedRightArrow.setAttribute("stroke-dasharray", "1, 3")
  2510. } else if (element.borderType === "dashed") {
  2511. curvedRightArrow.setAttribute("stroke-dasharray", "5, 5")
  2512. }
  2513. }
  2514. }
  2515. svg.appendChild(curvedRightArrow)
  2516. break
  2517. case "curvedLeftArrow":
  2518. const curvedLeftArrow = document.createElementNS(
  2519. "http://www.w3.org/2000/svg",
  2520. "path"
  2521. )
  2522. // 定义左弧形箭头的路径数据
  2523. const pathDataCurvedLeft = `
  2524. M0,0
  2525. A${element.width} ${element.height * 0.4} 0 0 1 ${element.width} ${
  2526. element.height * 0.4
  2527. }
  2528. L${element.width},${element.height * 0.55}
  2529. A${element.width} ${element.height * 0.4} 0 0 0 0 ${
  2530. element.height * 0.15
  2531. }
  2532. Z
  2533. M0,${element.height * 0.85}
  2534. L${element.width * 0.25},${element.height * 0.65}
  2535. L${element.width * 0.25},${element.height * 0.75}
  2536. A${element.width} ${element.height * 0.4} 0 0 0 ${element.width} ${
  2537. element.height * 0.4
  2538. }
  2539. L${element.width},${element.height * 0.5}
  2540. L${element.width},${element.height * 0.5}
  2541. A${element.width} ${element.height * 0.4} 0 0 1 ${
  2542. element.width * 0.25
  2543. } ${element.height * 0.9}
  2544. L${element.width * 0.25},${element.height}
  2545. Z`
  2546. curvedLeftArrow.setAttribute("d", pathDataCurvedLeft)
  2547. // 设置填充色
  2548. setBackground(element, curvedLeftArrow)
  2549. // 设置边框
  2550. if (element.borderWidth > 0) {
  2551. curvedLeftArrow.setAttribute("stroke", element.borderColor || "#000")
  2552. curvedLeftArrow.setAttribute("stroke-width", element.borderWidth || 1)
  2553. curvedLeftArrow.setAttribute("stroke-linecap", "butt")
  2554. curvedLeftArrow.setAttribute("stroke-linejoin", "round")
  2555. // 处理虚线边框
  2556. if (
  2557. element.borderType === "dotted" ||
  2558. element.borderType === "dashed"
  2559. ) {
  2560. if (element.borderStrokeDasharray) {
  2561. curvedLeftArrow.setAttribute(
  2562. "stroke-dasharray",
  2563. element.borderStrokeDasharray
  2564. )
  2565. } else if (element.borderType === "dotted") {
  2566. curvedLeftArrow.setAttribute("stroke-dasharray", "1, 3")
  2567. } else if (element.borderType === "dashed") {
  2568. curvedLeftArrow.setAttribute("stroke-dasharray", "5, 5")
  2569. }
  2570. }
  2571. }
  2572. svg.appendChild(curvedLeftArrow)
  2573. break
  2574. case "curvedUpArrow":
  2575. const curvedUpArrow = document.createElementNS(
  2576. "http://www.w3.org/2000/svg",
  2577. "path"
  2578. )
  2579. // 定义上弧形箭头的路径数据
  2580. const pathDataCurvedUp = `
  2581. M${element.width * 0.905},0
  2582. L${element.width * 0.81},${element.height * 0.25}
  2583. L${element.width * 0.857},${element.height * 0.25}
  2584. A${element.width * 0.428} ${element.height} 0 0 1 ${
  2585. element.width * 0.428
  2586. },${element.height}
  2587. L${element.width * 0.522},${element.height}
  2588. A${element.width * 0.428} ${element.height} 0 0 0 ${
  2589. element.width * 0.952
  2590. },${element.height * 0.25}
  2591. L${element.width},${element.height * 0.25}
  2592. Z
  2593. M${element.width * 0.094},0
  2594. L0,0
  2595. A${element.width * 0.428} ${element.height} 0 0 0 ${
  2596. element.width * 0.428
  2597. },${element.height}
  2598. L${element.width * 0.522},${element.height}
  2599. A${element.width * 0.428} ${element.height} 0 0 1 ${
  2600. element.width * 0.094
  2601. },0
  2602. Z`
  2603. curvedUpArrow.setAttribute("d", pathDataCurvedUp)
  2604. // 设置填充色
  2605. setBackground(element, curvedUpArrow)
  2606. // 设置边框
  2607. if (element.borderWidth > 0) {
  2608. curvedUpArrow.setAttribute("stroke", element.borderColor || "#000")
  2609. curvedUpArrow.setAttribute("stroke-width", element.borderWidth || 1)
  2610. curvedUpArrow.setAttribute("stroke-linecap", "butt")
  2611. curvedUpArrow.setAttribute("stroke-linejoin", "round")
  2612. // 处理虚线边框
  2613. if (
  2614. element.borderType === "dotted" ||
  2615. element.borderType === "dashed"
  2616. ) {
  2617. if (element.borderStrokeDasharray) {
  2618. curvedUpArrow.setAttribute(
  2619. "stroke-dasharray",
  2620. element.borderStrokeDasharray
  2621. )
  2622. } else if (element.borderType === "dotted") {
  2623. curvedUpArrow.setAttribute("stroke-dasharray", "1, 3")
  2624. } else if (element.borderType === "dashed") {
  2625. curvedUpArrow.setAttribute("stroke-dasharray", "5, 5")
  2626. }
  2627. }
  2628. }
  2629. svg.appendChild(curvedUpArrow)
  2630. break
  2631. case "curvedDownArrow":
  2632. const curvedDownArrow = document.createElementNS(
  2633. "http://www.w3.org/2000/svg",
  2634. "path"
  2635. )
  2636. // 定义下弧形箭头的路径数据
  2637. const pathDataCurvedDown = `
  2638. M0,${element.height}
  2639. L${element.width * 0.16},${element.height}
  2640. A${element.width * 0.46} ${element.height} 0 0 1 ${
  2641. element.width * 0.62
  2642. },0
  2643. L${element.width * 0.46},0
  2644. A${element.width * 0.46} ${element.height} 0 0 0 0,${element.height}
  2645. Z
  2646. M${element.width},${element.height}
  2647. L${element.width * 0.84},${element.height * 0.75}
  2648. L${element.width * 0.92},${element.height * 0.75}
  2649. A${element.width * 0.46} ${element.height} 0 0 0 ${
  2650. element.width * 0.46
  2651. },0
  2652. L${element.width * 0.62},0
  2653. A${element.width * 0.46} ${element.height} 0 0 1 ${
  2654. element.width * 1.08
  2655. },${element.height * 0.75}
  2656. L${element.width * 1.16},${element.height * 0.75}
  2657. Z`
  2658. curvedDownArrow.setAttribute("d", pathDataCurvedDown)
  2659. // 设置填充色
  2660. setBackground(element, curvedDownArrow)
  2661. // 设置边框
  2662. if (element.borderWidth > 0) {
  2663. curvedDownArrow.setAttribute("stroke", element.borderColor || "#000")
  2664. curvedDownArrow.setAttribute("stroke-width", element.borderWidth || 1)
  2665. curvedDownArrow.setAttribute("stroke-linecap", "butt")
  2666. curvedDownArrow.setAttribute("stroke-linejoin", "round")
  2667. // 处理虚线边框
  2668. if (
  2669. element.borderType === "dotted" ||
  2670. element.borderType === "dashed"
  2671. ) {
  2672. if (element.borderStrokeDasharray) {
  2673. curvedDownArrow.setAttribute(
  2674. "stroke-dasharray",
  2675. element.borderStrokeDasharray
  2676. )
  2677. } else if (element.borderType === "dotted") {
  2678. curvedDownArrow.setAttribute("stroke-dasharray", "1, 3")
  2679. } else if (element.borderType === "dashed") {
  2680. curvedDownArrow.setAttribute("stroke-dasharray", "5, 5")
  2681. }
  2682. }
  2683. }
  2684. svg.appendChild(curvedDownArrow)
  2685. break
  2686. case "stripedRightArrow":
  2687. const stripedRightArrow = document.createElementNS(
  2688. "http://www.w3.org/2000/svg",
  2689. "g"
  2690. )
  2691. // 主箭头部分
  2692. const mainArrow = document.createElementNS(
  2693. "http://www.w3.org/2000/svg",
  2694. "path"
  2695. )
  2696. mainArrow.setAttribute(
  2697. "d",
  2698. `M${element.width * 0.062},${element.height * 0.25}
  2699. L${element.width * 0.8},${element.height * 0.25}
  2700. L${element.width * 0.8},0
  2701. L${element.width},${element.height * 0.5}
  2702. L${element.width * 0.8},${element.height}
  2703. L${element.width * 0.8},${element.height * 0.75}
  2704. L${element.width * 0.062},${element.height * 0.75}
  2705. Z`
  2706. )
  2707. // 第一条尾部条纹
  2708. const stripe1 = document.createElementNS(
  2709. "http://www.w3.org/2000/svg",
  2710. "path"
  2711. )
  2712. stripe1.setAttribute(
  2713. "d",
  2714. `M0,${element.height * 0.25}
  2715. L${element.width * 0.012},${element.height * 0.25}
  2716. L${element.width * 0.012},${element.height * 0.75}
  2717. L0,${element.height * 0.75}
  2718. Z`
  2719. )
  2720. // 第二条尾部条纹
  2721. const stripe2 = document.createElementNS(
  2722. "http://www.w3.org/2000/svg",
  2723. "path"
  2724. )
  2725. stripe2.setAttribute(
  2726. "d",
  2727. `M${element.width * 0.025},${element.height * 0.25}
  2728. L${element.width * 0.049},${element.height * 0.25}
  2729. L${element.width * 0.049},${element.height * 0.75}
  2730. L${element.width * 0.025},${element.height * 0.75}
  2731. Z`
  2732. )
  2733. // 设置填充色
  2734. setBackground(element, mainArrow)
  2735. setBackground(element, stripe1)
  2736. setBackground(element, stripe2)
  2737. // 设置边框
  2738. if (element.borderWidth > 0) {
  2739. ;[mainArrow, stripe1, stripe2].forEach((path) => {
  2740. path.setAttribute("stroke", element.borderColor || "#000")
  2741. path.setAttribute("stroke-width", element.borderWidth || 1)
  2742. path.setAttribute("stroke-linecap", "butt")
  2743. path.setAttribute("stroke-linejoin", "round")
  2744. // 处理虚线边框
  2745. if (
  2746. element.borderType === "dotted" ||
  2747. element.borderType === "dashed"
  2748. ) {
  2749. if (element.borderStrokeDasharray) {
  2750. path.setAttribute(
  2751. "stroke-dasharray",
  2752. element.borderStrokeDasharray
  2753. )
  2754. } else if (element.borderType === "dotted") {
  2755. path.setAttribute("stroke-dasharray", "1, 3")
  2756. } else if (element.borderType === "dashed") {
  2757. path.setAttribute("stroke-dasharray", "5, 5")
  2758. }
  2759. }
  2760. })
  2761. }
  2762. stripedRightArrow.appendChild(mainArrow)
  2763. stripedRightArrow.appendChild(stripe1)
  2764. stripedRightArrow.appendChild(stripe2)
  2765. svg.appendChild(stripedRightArrow)
  2766. break
  2767. case "rightArrowCallout":
  2768. const rightArrowCallout = document.createElementNS(
  2769. "http://www.w3.org/2000/svg",
  2770. "path"
  2771. )
  2772. rightArrowCallout.setAttribute(
  2773. "d",
  2774. `M0,0
  2775. L${element.width * 0.44},0
  2776. L${element.width * 0.44},${element.height * 0.375}
  2777. L${element.width * 0.79},${element.height * 0.375}
  2778. L${element.width * 0.79},${element.height * 0.25}
  2779. L${element.width},${element.height * 0.5}
  2780. L${element.width * 0.79},${element.height * 0.75}
  2781. L${element.width * 0.79},${element.height * 0.625}
  2782. L${element.width * 0.44},${element.height * 0.625}
  2783. L${element.width * 0.44},${element.height}
  2784. L0,${element.height}
  2785. Z`
  2786. )
  2787. // 设置填充色
  2788. setBackground(element, rightArrowCallout)
  2789. // 设置边框
  2790. if (element.borderWidth > 0) {
  2791. rightArrowCallout.setAttribute("stroke", element.borderColor || "#000")
  2792. rightArrowCallout.setAttribute("stroke-width", element.borderWidth || 1)
  2793. rightArrowCallout.setAttribute("stroke-linecap", "butt")
  2794. rightArrowCallout.setAttribute("stroke-linejoin", "round")
  2795. // 处理虚线边框
  2796. if (
  2797. element.borderType === "dotted" ||
  2798. element.borderType === "dashed"
  2799. ) {
  2800. if (element.borderStrokeDasharray) {
  2801. rightArrowCallout.setAttribute(
  2802. "stroke-dasharray",
  2803. element.borderStrokeDasharray
  2804. )
  2805. } else if (element.borderType === "dotted") {
  2806. rightArrowCallout.setAttribute("stroke-dasharray", "1, 3")
  2807. } else if (element.borderType === "dashed") {
  2808. rightArrowCallout.setAttribute("stroke-dasharray", "5, 5")
  2809. }
  2810. }
  2811. }
  2812. svg.appendChild(rightArrowCallout)
  2813. break
  2814. case "leftRightArrowCallout":
  2815. const leftRightArrowCallout = document.createElementNS(
  2816. "http://www.w3.org/2000/svg",
  2817. "path"
  2818. )
  2819. leftRightArrowCallout.setAttribute(
  2820. "d",
  2821. `M0,${element.height * 0.5}
  2822. L${element.width * 0.139},${element.height * 0.25}
  2823. L${element.width * 0.139},${element.height * 0.375}
  2824. L${element.width * 0.364},${element.height * 0.375}
  2825. L${element.width * 0.364},0
  2826. L${element.width * 0.636},0
  2827. L${element.width * 0.636},${element.height * 0.375}
  2828. L${element.width * 0.861},${element.height * 0.375}
  2829. L${element.width * 0.861},${element.height * 0.25}
  2830. L${element.width},${element.height * 0.5}
  2831. L${element.width * 0.861},${element.height * 0.75}
  2832. L${element.width * 0.861},${element.height * 0.625}
  2833. L${element.width * 0.636},${element.height * 0.625}
  2834. L${element.width * 0.636},${element.height}
  2835. L${element.width * 0.364},${element.height}
  2836. L${element.width * 0.364},${element.height * 0.625}
  2837. L${element.width * 0.139},${element.height * 0.625}
  2838. L${element.width * 0.139},${element.height * 0.75}
  2839. Z`
  2840. )
  2841. // 设置填充色
  2842. setBackground(element, leftRightArrowCallout)
  2843. // 设置边框
  2844. if (element.borderWidth > 0) {
  2845. leftRightArrowCallout.setAttribute(
  2846. "stroke",
  2847. element.borderColor || "#000"
  2848. )
  2849. leftRightArrowCallout.setAttribute(
  2850. "stroke-width",
  2851. element.borderWidth || 1
  2852. )
  2853. leftRightArrowCallout.setAttribute("stroke-linecap", "butt")
  2854. leftRightArrowCallout.setAttribute("stroke-linejoin", "round")
  2855. // 处理虚线边框
  2856. if (
  2857. element.borderType === "dotted" ||
  2858. element.borderType === "dashed"
  2859. ) {
  2860. if (element.borderStrokeDasharray) {
  2861. leftRightArrowCallout.setAttribute(
  2862. "stroke-dasharray",
  2863. element.borderStrokeDasharray
  2864. )
  2865. } else if (element.borderType === "dotted") {
  2866. leftRightArrowCallout.setAttribute("stroke-dasharray", "1, 3")
  2867. } else if (element.borderType === "dashed") {
  2868. leftRightArrowCallout.setAttribute("stroke-dasharray", "5, 5")
  2869. }
  2870. }
  2871. }
  2872. svg.appendChild(leftRightArrowCallout)
  2873. break
  2874. case "quadArrowCallout":
  2875. const quadArrowCallout = document.createElementNS(
  2876. "http://www.w3.org/2000/svg",
  2877. "path"
  2878. )
  2879. quadArrowCallout.setAttribute(
  2880. "d",
  2881. `M0,${element.height * 0.5}
  2882. L${element.width * 0.096},${element.height * 0.315}
  2883. L${element.width * 0.096},${element.height * 0.407}
  2884. L${element.width * 0.26},${element.height * 0.407}
  2885. L${element.width * 0.26},${element.height * 0.259}
  2886. L${element.width * 0.453},${element.height * 0.259}
  2887. L${element.width * 0.453},${element.height * 0.185}
  2888. L${element.width * 0.405},${element.height * 0.185}
  2889. L${element.width * 0.5},0
  2890. L${element.width * 0.595},${element.height * 0.185}
  2891. L${element.width * 0.547},${element.height * 0.185}
  2892. L${element.width * 0.547},${element.height * 0.259}
  2893. L${element.width * 0.74},${element.height * 0.259}
  2894. L${element.width * 0.74},${element.height * 0.407}
  2895. L${element.width * 0.904},${element.height * 0.407}
  2896. L${element.width * 0.904},${element.height * 0.315}
  2897. L${element.width},${element.height * 0.5}
  2898. L${element.width * 0.904},${element.height * 0.685}
  2899. L${element.width * 0.904},${element.height * 0.593}
  2900. L${element.width * 0.74},${element.height * 0.593}
  2901. L${element.width * 0.74},${element.height * 0.741}
  2902. L${element.width * 0.547},${element.height * 0.741}
  2903. L${element.width * 0.547},${element.height * 0.815}
  2904. L${element.width * 0.595},${element.height * 0.815}
  2905. L${element.width * 0.5},${element.height}
  2906. L${element.width * 0.405},${element.height * 0.815}
  2907. L${element.width * 0.453},${element.height * 0.815}
  2908. L${element.width * 0.453},${element.height * 0.741}
  2909. L${element.width * 0.26},${element.height * 0.741}
  2910. L${element.width * 0.26},${element.height * 0.593}
  2911. L${element.width * 0.096},${element.height * 0.593}
  2912. L${element.width * 0.096},${element.height * 0.685}
  2913. Z`
  2914. )
  2915. // 设置填充色
  2916. setBackground(element, quadArrowCallout)
  2917. // 设置边框
  2918. if (element.borderWidth > 0) {
  2919. quadArrowCallout.setAttribute("stroke", element.borderColor || "#000")
  2920. quadArrowCallout.setAttribute("stroke-width", element.borderWidth || 1)
  2921. quadArrowCallout.setAttribute("stroke-linecap", "butt")
  2922. quadArrowCallout.setAttribute("stroke-linejoin", "round")
  2923. // 处理虚线边框
  2924. if (
  2925. element.borderType === "dotted" ||
  2926. element.borderType === "dashed"
  2927. ) {
  2928. if (element.borderStrokeDasharray) {
  2929. quadArrowCallout.setAttribute(
  2930. "stroke-dasharray",
  2931. element.borderStrokeDasharray
  2932. )
  2933. } else if (element.borderType === "dotted") {
  2934. quadArrowCallout.setAttribute("stroke-dasharray", "1, 3")
  2935. } else if (element.borderType === "dashed") {
  2936. quadArrowCallout.setAttribute("stroke-dasharray", "5, 5")
  2937. }
  2938. }
  2939. }
  2940. svg.appendChild(quadArrowCallout)
  2941. break
  2942. case "leftArrowCallout":
  2943. const leftArrowCallout = document.createElementNS(
  2944. "http://www.w3.org/2000/svg",
  2945. "path"
  2946. )
  2947. leftArrowCallout.setAttribute(
  2948. "d",
  2949. `M0,${element.height * 0.5}
  2950. L${element.width * 0.183},${element.height * 0.25}
  2951. L${element.width * 0.183},${element.height * 0.375}
  2952. L${element.width * 0.35},${element.height * 0.375}
  2953. L${element.width * 0.35},0
  2954. L${element.width},0
  2955. L${element.width},${element.height}
  2956. L${element.width * 0.35},${element.height}
  2957. L${element.width * 0.35},${element.height * 0.625}
  2958. L${element.width * 0.183},${element.height * 0.625}
  2959. L${element.width * 0.183},${element.height * 0.75}
  2960. Z`
  2961. )
  2962. // 设置填充色
  2963. setBackground(element, leftArrowCallout)
  2964. // 设置边框
  2965. if (element.borderWidth > 0) {
  2966. leftArrowCallout.setAttribute("stroke", element.borderColor || "#000")
  2967. leftArrowCallout.setAttribute("stroke-width", element.borderWidth || 1)
  2968. leftArrowCallout.setAttribute("stroke-linecap", "butt")
  2969. leftArrowCallout.setAttribute("stroke-linejoin", "round")
  2970. // 处理虚线边框
  2971. if (
  2972. element.borderType === "dotted" ||
  2973. element.borderType === "dashed"
  2974. ) {
  2975. if (element.borderStrokeDasharray) {
  2976. leftArrowCallout.setAttribute(
  2977. "stroke-dasharray",
  2978. element.borderStrokeDasharray
  2979. )
  2980. } else if (element.borderType === "dotted") {
  2981. leftArrowCallout.setAttribute("stroke-dasharray", "1, 3")
  2982. } else if (element.borderType === "dashed") {
  2983. leftArrowCallout.setAttribute("stroke-dasharray", "5, 5")
  2984. }
  2985. }
  2986. }
  2987. svg.appendChild(leftArrowCallout)
  2988. break
  2989. case "upArrowCallout":
  2990. const upArrowCallout = document.createElementNS(
  2991. "http://www.w3.org/2000/svg",
  2992. "path"
  2993. )
  2994. upArrowCallout.setAttribute(
  2995. "d",
  2996. `M0,${element.height * 0.35}
  2997. L${element.width * 0.41},${element.height * 0.35}
  2998. L${element.width * 0.41},${element.height * 0.25}
  2999. L${element.width * 0.32},${element.height * 0.25}
  3000. L${element.width * 0.5},0
  3001. L${element.width * 0.68},${element.height * 0.25}
  3002. L${element.width * 0.59},${element.height * 0.25}
  3003. L${element.width * 0.59},${element.height * 0.35}
  3004. L${element.width},${element.height * 0.35}
  3005. L${element.width},${element.height}
  3006. L0,${element.height}
  3007. Z`
  3008. )
  3009. // 设置填充色
  3010. setBackground(element, upArrowCallout)
  3011. // 设置边框
  3012. if (element.borderWidth > 0) {
  3013. upArrowCallout.setAttribute("stroke", element.borderColor || "#000")
  3014. upArrowCallout.setAttribute("stroke-width", element.borderWidth || 1)
  3015. upArrowCallout.setAttribute("stroke-linecap", "butt")
  3016. upArrowCallout.setAttribute("stroke-linejoin", "round")
  3017. // 处理虚线边框
  3018. if (
  3019. element.borderType === "dotted" ||
  3020. element.borderType === "dashed"
  3021. ) {
  3022. if (element.borderStrokeDasharray) {
  3023. upArrowCallout.setAttribute(
  3024. "stroke-dasharray",
  3025. element.borderStrokeDasharray
  3026. )
  3027. } else if (element.borderType === "dotted") {
  3028. upArrowCallout.setAttribute("stroke-dasharray", "1, 3")
  3029. } else if (element.borderType === "dashed") {
  3030. upArrowCallout.setAttribute("stroke-dasharray", "5, 5")
  3031. }
  3032. }
  3033. }
  3034. svg.appendChild(upArrowCallout)
  3035. break
  3036. case "notchedRightArrow":
  3037. const notchedRightArrow = document.createElementNS(
  3038. "http://www.w3.org/2000/svg",
  3039. "path"
  3040. )
  3041. notchedRightArrow.setAttribute(
  3042. "d",
  3043. `M0,${element.height * 0.25}
  3044. L${element.width * 0.83},${element.height * 0.25}
  3045. L${element.width * 0.83},0
  3046. L${element.width},${element.height * 0.5}
  3047. L${element.width * 0.83},${element.height}
  3048. L${element.width * 0.83},${element.height * 0.75}
  3049. L0,${element.height * 0.75}
  3050. L${element.width * 0.086},${element.height * 0.5}
  3051. Z`
  3052. )
  3053. // 设置填充色
  3054. setBackground(element, notchedRightArrow)
  3055. // 设置边框
  3056. if (element.borderWidth > 0) {
  3057. notchedRightArrow.setAttribute("stroke", element.borderColor || "#000")
  3058. notchedRightArrow.setAttribute("stroke-width", element.borderWidth || 1)
  3059. notchedRightArrow.setAttribute("stroke-linecap", "butt")
  3060. notchedRightArrow.setAttribute("stroke-linejoin", "round")
  3061. // 处理虚线边框
  3062. if (
  3063. element.borderType === "dotted" ||
  3064. element.borderType === "dashed"
  3065. ) {
  3066. if (element.borderStrokeDasharray) {
  3067. notchedRightArrow.setAttribute(
  3068. "stroke-dasharray",
  3069. element.borderStrokeDasharray
  3070. )
  3071. } else if (element.borderType === "dotted") {
  3072. notchedRightArrow.setAttribute("stroke-dasharray", "1, 3")
  3073. } else if (element.borderType === "dashed") {
  3074. notchedRightArrow.setAttribute("stroke-dasharray", "5, 5")
  3075. }
  3076. }
  3077. }
  3078. svg.appendChild(notchedRightArrow)
  3079. break
  3080. case "homePlate":
  3081. const homePlate = document.createElementNS(
  3082. "http://www.w3.org/2000/svg",
  3083. "path"
  3084. )
  3085. homePlate.setAttribute(
  3086. "d",
  3087. `M0,0
  3088. L${element.width * 0.925},0
  3089. L${element.width},${element.height * 0.5}
  3090. L${element.width * 0.925},${element.height}
  3091. L0,${element.height}
  3092. Z`
  3093. )
  3094. // 设置填充色
  3095. setBackground(element, homePlate)
  3096. // 设置边框
  3097. if (element.borderWidth > 0) {
  3098. homePlate.setAttribute("stroke", element.borderColor || "#000")
  3099. homePlate.setAttribute("stroke-width", element.borderWidth || 1)
  3100. homePlate.setAttribute("stroke-linecap", "butt")
  3101. homePlate.setAttribute("stroke-linejoin", "round")
  3102. // 处理虚线边框
  3103. if (
  3104. element.borderType === "dotted" ||
  3105. element.borderType === "dashed"
  3106. ) {
  3107. if (element.borderStrokeDasharray) {
  3108. homePlate.setAttribute(
  3109. "stroke-dasharray",
  3110. element.borderStrokeDasharray
  3111. )
  3112. } else if (element.borderType === "dotted") {
  3113. homePlate.setAttribute("stroke-dasharray", "1, 3")
  3114. } else if (element.borderType === "dashed") {
  3115. homePlate.setAttribute("stroke-dasharray", "5, 5")
  3116. }
  3117. }
  3118. }
  3119. svg.appendChild(homePlate)
  3120. break
  3121. case "rightTriangle":
  3122. const rightTriangle = document.createElementNS(
  3123. "http://www.w3.org/2000/svg",
  3124. "polygon"
  3125. )
  3126. rightTriangle.setAttribute(
  3127. "points",
  3128. `0,0 ${element.width},${element.height} 0,${element.height}`
  3129. )
  3130. // 设置填充色
  3131. setBackground(element, rightTriangle)
  3132. // 设置边框
  3133. if (element.borderWidth > 0) {
  3134. rightTriangle.setAttribute("stroke", element.borderColor || "#000")
  3135. rightTriangle.setAttribute("stroke-width", element.borderWidth || 1)
  3136. // 处理虚线边框
  3137. if (
  3138. element.borderType === "dotted" ||
  3139. element.borderType === "dashed"
  3140. ) {
  3141. if (element.borderStrokeDasharray) {
  3142. rightTriangle.setAttribute(
  3143. "stroke-dasharray",
  3144. element.borderStrokeDasharray
  3145. )
  3146. } else if (element.borderType === "dotted") {
  3147. rightTriangle.setAttribute("stroke-dasharray", "1, 3")
  3148. } else if (element.borderType === "dashed") {
  3149. rightTriangle.setAttribute("stroke-dasharray", "5, 5")
  3150. }
  3151. }
  3152. }
  3153. svg.appendChild(rightTriangle)
  3154. break
  3155. case "semiCircle":
  3156. const semiCircle = document.createElementNS(
  3157. "http://www.w3.org/2000/svg",
  3158. "path"
  3159. )
  3160. semiCircle.setAttribute(
  3161. "d",
  3162. `M0,${element.height} A${element.width / 2},${element.height} 0 0,1 ${
  3163. element.width
  3164. },${element.height} Z`
  3165. )
  3166. // 设置填充色
  3167. setBackground(element, semiCircle)
  3168. // 设置边框
  3169. if (element.borderWidth > 0) {
  3170. semiCircle.setAttribute("stroke", element.borderColor || "#000")
  3171. semiCircle.setAttribute("stroke-width", element.borderWidth || 1)
  3172. // 处理虚线边框
  3173. if (
  3174. element.borderType === "dotted" ||
  3175. element.borderType === "dashed"
  3176. ) {
  3177. if (element.borderStrokeDasharray) {
  3178. semiCircle.setAttribute(
  3179. "stroke-dasharray",
  3180. element.borderStrokeDasharray
  3181. )
  3182. } else if (element.borderType === "dotted") {
  3183. semiCircle.setAttribute("stroke-dasharray", "1, 3")
  3184. } else if (element.borderType === "dashed") {
  3185. semiCircle.setAttribute("stroke-dasharray", "5, 5")
  3186. }
  3187. }
  3188. }
  3189. svg.appendChild(semiCircle)
  3190. break
  3191. case "star":
  3192. const star = document.createElementNS(
  3193. "http://www.w3.org/2000/svg",
  3194. "polygon"
  3195. )
  3196. const cx = element.width / 2
  3197. const cy = element.height / 2
  3198. const outerRadius = Math.min(element.width, element.height) / 2
  3199. const innerRadius = outerRadius * 0.4
  3200. let starPoints = ""
  3201. for (let i = 0; i < 10; i++) {
  3202. const radius = i % 2 === 0 ? outerRadius : innerRadius
  3203. const angle = (Math.PI * i) / 5
  3204. const x = cx + radius * Math.sin(angle)
  3205. const y = cy - radius * Math.cos(angle)
  3206. starPoints += `${x},${y} `
  3207. }
  3208. star.setAttribute("points", starPoints.trim())
  3209. // 设置填充色
  3210. setBackground(element, star)
  3211. // 设置边框
  3212. if (element.borderWidth > 0) {
  3213. star.setAttribute("stroke", element.borderColor || "#000")
  3214. star.setAttribute("stroke-width", element.borderWidth || 1)
  3215. // 处理虚线边框
  3216. if (
  3217. element.borderType === "dotted" ||
  3218. element.borderType === "dashed"
  3219. ) {
  3220. if (element.borderStrokeDasharray) {
  3221. star.setAttribute("stroke-dasharray", element.borderStrokeDasharray)
  3222. } else if (element.borderType === "dotted") {
  3223. star.setAttribute("stroke-dasharray", "1, 3")
  3224. } else if (element.borderType === "dashed") {
  3225. star.setAttribute("stroke-dasharray", "5, 5")
  3226. }
  3227. }
  3228. }
  3229. svg.appendChild(star)
  3230. break
  3231. case "cross":
  3232. const cross = document.createElementNS(
  3233. "http://www.w3.org/2000/svg",
  3234. "polygon"
  3235. )
  3236. cross.setAttribute(
  3237. "points",
  3238. `${element.width * 0.35},0 ${element.width * 0.65},0 ${
  3239. element.width * 0.65
  3240. },${element.height * 0.35} ` +
  3241. `${element.width},${element.height * 0.35} ${element.width},${
  3242. element.height * 0.65
  3243. } ` +
  3244. `${element.width * 0.65},${element.height * 0.65} ${
  3245. element.width * 0.65
  3246. },${element.height} ` +
  3247. `${element.width * 0.35},${element.height} ${element.width * 0.35},${
  3248. element.height * 0.65
  3249. } ` +
  3250. `0,${element.height * 0.65} 0,${element.height * 0.35} ${
  3251. element.width * 0.35
  3252. },${element.height * 0.35}`
  3253. )
  3254. // 设置填充色
  3255. setBackground(element, cross)
  3256. // 设置边框
  3257. if (element.borderWidth > 0) {
  3258. cross.setAttribute("stroke", element.borderColor || "#000")
  3259. cross.setAttribute("stroke-width", element.borderWidth || 1)
  3260. // 处理虚线边框
  3261. if (
  3262. element.borderType === "dotted" ||
  3263. element.borderType === "dashed"
  3264. ) {
  3265. if (element.borderStrokeDasharray) {
  3266. cross.setAttribute(
  3267. "stroke-dasharray",
  3268. element.borderStrokeDasharray
  3269. )
  3270. } else if (element.borderType === "dotted") {
  3271. cross.setAttribute("stroke-dasharray", "1, 3")
  3272. } else if (element.borderType === "dashed") {
  3273. cross.setAttribute("stroke-dasharray", "5, 5")
  3274. }
  3275. }
  3276. }
  3277. svg.appendChild(cross)
  3278. break
  3279. case "chevron":
  3280. const chevron = document.createElementNS(
  3281. "http://www.w3.org/2000/svg",
  3282. "polygon"
  3283. )
  3284. chevron.setAttribute(
  3285. "points",
  3286. `${element.width * 0.5},0 ${element.width},${element.height * 0.5} ` +
  3287. `${element.width * 0.5},${element.height} ` +
  3288. `0,${element.height} ${element.width * 0.5},${
  3289. element.height * 0.5
  3290. } 0,0`
  3291. )
  3292. // 设置填充色
  3293. setBackground(element, chevron)
  3294. // 设置边框
  3295. if (element.borderWidth > 0) {
  3296. chevron.setAttribute("stroke", element.borderColor || "#000")
  3297. chevron.setAttribute("stroke-width", element.borderWidth || 1)
  3298. // 处理虚线边框
  3299. if (
  3300. element.borderType === "dotted" ||
  3301. element.borderType === "dashed"
  3302. ) {
  3303. if (element.borderStrokeDasharray) {
  3304. chevron.setAttribute(
  3305. "stroke-dasharray",
  3306. element.borderStrokeDasharray
  3307. )
  3308. } else if (element.borderType === "dotted") {
  3309. chevron.setAttribute("stroke-dasharray", "1, 3")
  3310. } else if (element.borderType === "dashed") {
  3311. chevron.setAttribute("stroke-dasharray", "5, 5")
  3312. }
  3313. }
  3314. }
  3315. svg.appendChild(chevron)
  3316. break
  3317. case "frame":
  3318. // 创建外框和内框
  3319. const outerRect = document.createElementNS(
  3320. "http://www.w3.org/2000/svg",
  3321. "rect"
  3322. )
  3323. outerRect.setAttribute("x", 0)
  3324. outerRect.setAttribute("y", 0)
  3325. outerRect.setAttribute("width", element.width)
  3326. outerRect.setAttribute("height", element.height)
  3327. const innerRect = document.createElementNS(
  3328. "http://www.w3.org/2000/svg",
  3329. "rect"
  3330. )
  3331. const frameWidth = element.width / 10
  3332. innerRect.setAttribute("x", frameWidth)
  3333. innerRect.setAttribute("y", frameWidth)
  3334. innerRect.setAttribute("width", element.width - frameWidth * 2)
  3335. innerRect.setAttribute("height", element.height - frameWidth * 2)
  3336. // 设置填充色
  3337. setBackground(element, outerRect)
  3338. innerRect.setAttribute("fill", "white") // 内框为白色
  3339. // 设置边框
  3340. if (element.borderWidth > 0) {
  3341. outerRect.setAttribute("stroke", element.borderColor || "#000")
  3342. outerRect.setAttribute("stroke-width", element.borderWidth || 1)
  3343. // 处理虚线边框
  3344. if (
  3345. element.borderType === "dotted" ||
  3346. element.borderType === "dashed"
  3347. ) {
  3348. if (element.borderStrokeDasharray) {
  3349. outerRect.setAttribute(
  3350. "stroke-dasharray",
  3351. element.borderStrokeDasharray
  3352. )
  3353. } else if (element.borderType === "dotted") {
  3354. outerRect.setAttribute("stroke-dasharray", "1, 3")
  3355. } else if (element.borderType === "dashed") {
  3356. outerRect.setAttribute("stroke-dasharray", "5, 5")
  3357. }
  3358. }
  3359. }
  3360. svg.appendChild(outerRect)
  3361. svg.appendChild(innerRect)
  3362. break
  3363. case "cloud":
  3364. // 使用路径绘制云形
  3365. const cloud = document.createElementNS(
  3366. "http://www.w3.org/2000/svg",
  3367. "path"
  3368. )
  3369. const w = element.width
  3370. const h = element.height
  3371. cloud.setAttribute(
  3372. "d",
  3373. `M${w * 0.2},${h * 0.6} ` +
  3374. `C${w * 0.05},${h * 0.6} ${w * 0.05},${h * 0.3} ${w * 0.2},${
  3375. h * 0.3
  3376. } ` +
  3377. `C${w * 0.2},${h * 0.1} ${w * 0.45},${h * 0.1} ${w * 0.5},${
  3378. h * 0.3
  3379. } ` +
  3380. `C${w * 0.55},${h * 0.1} ${w * 0.8},${h * 0.1} ${w * 0.8},${
  3381. h * 0.3
  3382. } ` +
  3383. `C${w * 0.95},${h * 0.3} ${w * 0.95},${h * 0.6} ${w * 0.8},${
  3384. h * 0.6
  3385. } ` +
  3386. `L${w * 0.2},${h * 0.6} Z`
  3387. )
  3388. // 设置填充色
  3389. setBackground(element, cloud)
  3390. // 设置边框
  3391. if (element.borderWidth > 0) {
  3392. cloud.setAttribute("stroke", element.borderColor || "#000")
  3393. cloud.setAttribute("stroke-width", element.borderWidth || 1)
  3394. // 处理虚线边框
  3395. if (
  3396. element.borderType === "dotted" ||
  3397. element.borderType === "dashed"
  3398. ) {
  3399. if (element.borderStrokeDasharray) {
  3400. cloud.setAttribute(
  3401. "stroke-dasharray",
  3402. element.borderStrokeDasharray
  3403. )
  3404. } else if (element.borderType === "dotted") {
  3405. cloud.setAttribute("stroke-dasharray", "1, 3")
  3406. } else if (element.borderType === "dashed") {
  3407. cloud.setAttribute("stroke-dasharray", "5, 5")
  3408. }
  3409. }
  3410. }
  3411. svg.appendChild(cloud)
  3412. break
  3413. case "blockArc":
  3414. const blockArc = document.createElementNS(
  3415. "http://www.w3.org/2000/svg",
  3416. "path"
  3417. )
  3418. // 计算弧形参数
  3419. const rx = element.width / 2
  3420. const ry = element.height / 2
  3421. const innerRatio = 0.86 // 根据示例计算的内弧半径比例
  3422. const innerRx = rx * innerRatio
  3423. const innerRy = ry * innerRatio
  3424. // 构建路径
  3425. const path2 = `
  3426. M 0,${ry}
  3427. A ${rx} ${ry} 0 1 1 ${element.width} ${ry}
  3428. L ${element.width - (rx - innerRx)},${ry}
  3429. A ${innerRx} ${innerRy} 0 1 0 ${rx - innerRx},${ry}
  3430. Z`
  3431. blockArc.setAttribute("d", path2.trim())
  3432. // 设置填充色
  3433. setBackground(element, blockArc)
  3434. // 设置边框
  3435. if (element.borderWidth > 0) {
  3436. blockArc.setAttribute("stroke", element.borderColor || "#000")
  3437. blockArc.setAttribute("stroke-width", element.borderWidth || 1)
  3438. if (
  3439. element.borderType === "dotted" ||
  3440. element.borderType === "dashed"
  3441. ) {
  3442. if (element.borderStrokeDasharray) {
  3443. blockArc.setAttribute(
  3444. "stroke-dasharray",
  3445. element.borderStrokeDasharray
  3446. )
  3447. } else if (element.borderType === "dotted") {
  3448. blockArc.setAttribute("stroke-dasharray", "1, 3")
  3449. } else if (element.borderType === "dashed") {
  3450. blockArc.setAttribute("stroke-dasharray", "5, 5")
  3451. }
  3452. }
  3453. }
  3454. svg.appendChild(blockArc)
  3455. break
  3456. case "rect":
  3457. default:
  3458. const rect = document.createElementNS(
  3459. "http://www.w3.org/2000/svg",
  3460. "rect"
  3461. )
  3462. rect.setAttribute("x", 0)
  3463. rect.setAttribute("y", 0)
  3464. rect.setAttribute("width", element.width)
  3465. rect.setAttribute("height", element.height)
  3466. if (element.fill && element.fill.type) {
  3467. // 设置填充色
  3468. if (element.fill.type === "color") {
  3469. rect.setAttribute("fill", element.fill.value || "transparent")
  3470. } else if (element.fill.type === "gradient") {
  3471. // 渐变填充
  3472. const { colors, path, rot } = element.fill.value
  3473. if (colors && colors.length >= 2) {
  3474. const gradientType = path === "rect" ? "linear" : "radial"
  3475. const gradientAngle =
  3476. gradientType === "linear" ? (90 - (rot || 0)) % 360 : rot || 0
  3477. let gradientString = `${gradientType}-gradient(`
  3478. if (gradientType === "linear") {
  3479. gradientString += `${gradientAngle}deg, `
  3480. }
  3481. colors.forEach((color, i) => {
  3482. gradientString += `${color.color} ${color.pos}${
  3483. i < colors.length - 1 ? ", " : ""
  3484. }`
  3485. })
  3486. gradientString += ")"
  3487. // 创建渐变定义
  3488. const gradientDef = document.createElementNS(
  3489. "http://www.w3.org/2000/svg",
  3490. "defs"
  3491. )
  3492. const gradientEl = document.createElementNS(
  3493. "http://www.w3.org/2000/svg",
  3494. gradientType === "linear" ? "linearGradient" : "radialGradient"
  3495. )
  3496. const gradientId = `gradient-${Date.now()}-${Math.random()
  3497. .toString(36)
  3498. .substr(2, 9)}`
  3499. gradientEl.setAttribute("id", gradientId)
  3500. // 设置渐变属性
  3501. if (gradientType === "linear") {
  3502. gradientEl.setAttribute(
  3503. "gradientTransform",
  3504. `rotate(${gradientAngle})`
  3505. )
  3506. }
  3507. // 添加渐变色标
  3508. colors.forEach((color) => {
  3509. const stop = document.createElementNS(
  3510. "http://www.w3.org/2000/svg",
  3511. "stop"
  3512. )
  3513. stop.setAttribute("offset", color.pos)
  3514. stop.setAttribute("stop-color", color.color)
  3515. gradientEl.appendChild(stop)
  3516. })
  3517. gradientDef.appendChild(gradientEl)
  3518. svg.appendChild(gradientDef)
  3519. // 应用渐变
  3520. rect.setAttribute("fill", `url(#${gradientId})`)
  3521. }
  3522. } else if (element.fill.type === "image") {
  3523. // 创建图案填充
  3524. const pattern = document.createElementNS(
  3525. "http://www.w3.org/2000/svg",
  3526. "pattern"
  3527. )
  3528. const patternId = `pattern-${Date.now()}-${Math.random()
  3529. .toString(36)
  3530. .substr(2, 9)}`
  3531. pattern.setAttribute("id", patternId)
  3532. pattern.setAttribute("patternUnits", "userSpaceOnUse")
  3533. pattern.setAttribute("width", "100%")
  3534. pattern.setAttribute("height", "100%")
  3535. // 创建图片元素
  3536. const image = document.createElementNS(
  3537. "http://www.w3.org/2000/svg",
  3538. "image"
  3539. )
  3540. image.setAttribute("width", "100%")
  3541. image.setAttribute("height", "100%")
  3542. image.setAttribute("preserveAspectRatio", "xMidYMid slice")
  3543. image.setAttributeNS(
  3544. "http://www.w3.org/1999/xlink",
  3545. "href",
  3546. element.fill.value.picBase64
  3547. )
  3548. pattern.appendChild(image)
  3549. // 添加pattern到defs
  3550. const defs = document.createElementNS(
  3551. "http://www.w3.org/2000/svg",
  3552. "defs"
  3553. )
  3554. defs.appendChild(pattern)
  3555. svg.appendChild(defs)
  3556. // 应用图案填充
  3557. rect.setAttribute("fill", `url(#${patternId})`)
  3558. } else {
  3559. rect.setAttribute("fill", "transparent")
  3560. }
  3561. } else {
  3562. rect.setAttribute("fill", "#ffffff00")
  3563. }
  3564. // 设置边框
  3565. if (element.borderWidth > 0) {
  3566. rect.setAttribute("stroke", element.borderColor || "#000")
  3567. rect.setAttribute("stroke-width", element.borderWidth || 1)
  3568. // 处理虚线边框
  3569. if (
  3570. element.borderType === "dotted" ||
  3571. element.borderType === "dashed"
  3572. ) {
  3573. if (element.borderStrokeDasharray) {
  3574. rect.setAttribute("stroke-dasharray", element.borderStrokeDasharray)
  3575. } else if (element.borderType === "dotted") {
  3576. rect.setAttribute("stroke-dasharray", "1, 3")
  3577. } else if (element.borderType === "dashed") {
  3578. rect.setAttribute("stroke-dasharray", "5, 5")
  3579. }
  3580. }
  3581. }
  3582. svg.appendChild(rect)
  3583. break
  3584. }
  3585. const transformList = []
  3586. let rotateDeg = element.rotate || 0
  3587. if (element.isFlipV) {
  3588. transformList.push(`scaleY(-1)`)
  3589. rotateDeg = -rotateDeg // 垂直翻转时反转旋转方向
  3590. }
  3591. if (element.isFlipH) {
  3592. transformList.push(`scaleX(-1)`)
  3593. rotateDeg = -rotateDeg // 水平翻转时反转旋转方向
  3594. }
  3595. if (element.rotate) {
  3596. transformList.push(`rotate(${rotateDeg}deg)`)
  3597. }
  3598. if (transformList.length > 0) {
  3599. el.style.transform = transformList.join(" ")
  3600. el.style.transformOrigin = "center center"
  3601. }
  3602. el.appendChild(svg)
  3603. // 设置形状内容
  3604. if (element.content) {
  3605. const contentContainer = document.createElement("div")
  3606. contentContainer.innerHTML = convertPtToPxInContent(element.content)
  3607. contentContainer.style.position = "absolute"
  3608. contentContainer.style.width = element.width + "px"
  3609. contentContainer.style.height = element.height + "px"
  3610. contentContainer.style.top = "0px"
  3611. contentContainer.style.left = "0px"
  3612. contentContainer.style.display = "flex"
  3613. contentContainer.style.alignItems = "center"
  3614. contentContainer.style.justifyContent = "center"
  3615. contentContainer.style.zIndex = element.order
  3616. contentContainer.style.pointerEvents = "none"
  3617. const transformList = []
  3618. let rotateDeg = element.rotate || 0
  3619. if (element.isFlipV) {
  3620. transformList.push(`scaleY(-1)`)
  3621. rotateDeg = -rotateDeg // 垂直翻转时反转旋转方向
  3622. }
  3623. if (element.isFlipH) {
  3624. transformList.push(`scaleX(-1)`)
  3625. rotateDeg = -rotateDeg // 水平翻转时反转旋转方向
  3626. }
  3627. if (element.rotate) {
  3628. transformList.push(`rotate(${rotateDeg}deg)`)
  3629. }
  3630. if (transformList.length > 0) {
  3631. contentContainer.style.transform = transformList.join(" ")
  3632. contentContainer.style.transformOrigin = "center center"
  3633. }
  3634. el.appendChild(contentContainer)
  3635. }
  3636. return el
  3637. }
  3638. // 创建表格元素
  3639. const createTableElement = (element) => {
  3640. const el = document.createElement("div")
  3641. el.style.position = "absolute"
  3642. el.style.top = element.top + "px"
  3643. el.style.left = element.left + "px"
  3644. el.style.width = element.width + "px"
  3645. el.style.height = element.height + "px"
  3646. el.style.zIndex = element.order
  3647. // 创建表格元素
  3648. const table = document.createElement("table")
  3649. table.style.width = element.width + "px"
  3650. table.style.height = element.height + "px"
  3651. table.style.borderCollapse = "collapse"
  3652. table.style.tableLayout = "fixed"
  3653. // 设置表格边框
  3654. if (element.borders) {
  3655. if (element.borders.all) {
  3656. const border = element.borders.all
  3657. table.style.border = `${border.borderWidth || 1}px ${
  3658. border.borderType || "solid"
  3659. } ${border.borderColor || "#000"}`
  3660. } else {
  3661. // 分别设置四边边框
  3662. if (element.borders.top) {
  3663. table.style.borderTop = `${element.borders.top.borderWidth || 1}px ${
  3664. element.borders.top.borderType || "solid"
  3665. } ${element.borders.top.borderColor || "#000"}`
  3666. }
  3667. if (element.borders.bottom) {
  3668. table.style.borderBottom = `${
  3669. element.borders.bottom.borderWidth || 1
  3670. }px ${element.borders.bottom.borderType || "solid"} ${
  3671. element.borders.bottom.borderColor || "#000"
  3672. }`
  3673. }
  3674. if (element.borders.left) {
  3675. table.style.borderLeft = `${element.borders.left.borderWidth || 1}px ${
  3676. element.borders.left.borderType || "solid"
  3677. } ${element.borders.left.borderColor || "#000"}`
  3678. }
  3679. if (element.borders.right) {
  3680. table.style.borderRight = `${
  3681. element.borders.right.borderWidth || 1
  3682. }px ${element.borders.right.borderType || "solid"} ${
  3683. element.borders.right.borderColor || "#000"
  3684. }`
  3685. }
  3686. }
  3687. }
  3688. // 创建表格内容
  3689. const tbody = document.createElement("tbody")
  3690. // 处理表格数据
  3691. if (element.data && element.data.length > 0) {
  3692. element.data.forEach((rowData, rowIndex) => {
  3693. const tr = document.createElement("tr")
  3694. rowData.forEach((cell, colIndex) => {
  3695. // 跳过被合并的单元格
  3696. if (cell.hMerge) return
  3697. const td = document.createElement("td")
  3698. // 设置单元格内容
  3699. if (cell.text) {
  3700. td.innerHTML = convertPtToPxInContent(cell.text)
  3701. }
  3702. // 设置单元格样式
  3703. td.style.padding = "0px"
  3704. td.style.verticalAlign = "middle"
  3705. // 设置文本样式
  3706. if (cell.fontColor) td.style.color = cell.fontColor
  3707. if (cell.fontSize) td.style.fontSize = cell.fontSize
  3708. if (cell.fontFamily) td.style.fontFamily = cell.fontFamily
  3709. if (cell.bold) td.style.fontWeight = "bold"
  3710. if (cell.italic) td.style.fontStyle = "italic"
  3711. if (cell.underline) td.style.textDecoration = "underline"
  3712. if (cell.align) td.style.textAlign = cell.align
  3713. // 设置背景色
  3714. if (cell.fillColor) td.style.backgroundColor = cell.fillColor
  3715. // 设置单元格边框
  3716. if (cell.borders) {
  3717. if (cell.borders.all) {
  3718. const border = cell.borders.all
  3719. td.style.border = `${border.borderWidth || 1}px ${
  3720. border.borderType || "solid"
  3721. } ${border.borderColor || "#000"}`
  3722. } else {
  3723. // 分别设置四边边框
  3724. if (cell.borders.top) {
  3725. td.style.borderTop = `${cell.borders.top.borderWidth || 1}px ${
  3726. cell.borders.top.borderType || "solid"
  3727. } ${cell.borders.top.borderColor || "#000"}`
  3728. }
  3729. if (cell.borders.bottom) {
  3730. td.style.borderBottom = `${
  3731. cell.borders.bottom.borderWidth || 1
  3732. }px ${cell.borders.bottom.borderType || "solid"} ${
  3733. cell.borders.bottom.borderColor || "#000"
  3734. }`
  3735. }
  3736. if (cell.borders.left) {
  3737. td.style.borderLeft = `${cell.borders.left.borderWidth || 1}px ${
  3738. cell.borders.left.borderType || "solid"
  3739. } ${cell.borders.left.borderColor || "#000"}`
  3740. }
  3741. if (cell.borders.right) {
  3742. td.style.borderRight = `${
  3743. cell.borders.right.borderWidth || 1
  3744. }px ${cell.borders.right.borderType || "solid"} ${
  3745. cell.borders.right.borderColor || "#000"
  3746. }`
  3747. }
  3748. }
  3749. }
  3750. td.style.width = element.colWidths[colIndex] + "px"
  3751. // 设置单元格合并
  3752. if (cell.colSpan && cell.colSpan > 1) {
  3753. td.colSpan = cell.colSpan
  3754. td.style.width = element.colWidths[colIndex] * cell.colSpan + "px"
  3755. }
  3756. if (cell.rowSpan && cell.rowSpan > 1) {
  3757. td.rowSpan = cell.rowSpan
  3758. }
  3759. tr.appendChild(td)
  3760. })
  3761. tr.style.height = element.rowHeights[rowIndex] + "px"
  3762. tbody.appendChild(tr)
  3763. })
  3764. }
  3765. table.appendChild(tbody)
  3766. el.appendChild(table)
  3767. return el
  3768. }
  3769. const createChartElement = (element) => {
  3770. // 1. 创建基础容器
  3771. const el = document.createElement("div")
  3772. el.style.position = "absolute"
  3773. el.style.top = element.top + "px"
  3774. el.style.left = element.left + "px"
  3775. el.style.width = element.width + "px"
  3776. el.style.height = element.height + "px"
  3777. el.style.zIndex = element.order
  3778. // 2. 创建SVG画布
  3779. const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg")
  3780. svg.setAttribute("width", element.width)
  3781. svg.setAttribute("height", element.height)
  3782. svg.setAttribute("viewBox", `0 0 ${element.width} ${element.height}`)
  3783. // 3. 设置图表内边距
  3784. const padding = {
  3785. top: 60, // 为图例留出空间
  3786. right: 40, // 右侧边距
  3787. bottom: 60, // X轴标签空间
  3788. left: 60, // Y轴标签空间
  3789. }
  3790. // 4. 计算实际绘图区域
  3791. const chartWidth = element.width - padding.left - padding.right
  3792. const chartHeight = element.height - padding.top - padding.bottom
  3793. // 处理不同图表类型
  3794. switch (element.chartType) {
  3795. case "barChart":
  3796. // 绘制柱状图
  3797. drawBarChart(svg, element, {
  3798. padding,
  3799. chartWidth,
  3800. chartHeight,
  3801. barDir: element.barDir || "col",
  3802. grouping: element.grouping || "clustered",
  3803. })
  3804. break
  3805. case "pieChart":
  3806. case "doughnutChart":
  3807. drawDonutChart(svg, element, chartWidth, chartHeight)
  3808. break
  3809. default:
  3810. // 占位符
  3811. svg.innerHTML = `<text x="${element.width / 2}" y="${
  3812. element.height / 2
  3813. }" text-anchor="middle" fill="#999" font-size="12px">
  3814. 暂不支持该类型图表
  3815. </text>`
  3816. console.warn("Unsupported chart type:", element.chartType)
  3817. }
  3818. el.appendChild(svg)
  3819. return el
  3820. }
  3821. // 创建图表元素
  3822. const createDiagramElement = (element) => {
  3823. const el = document.createElement("div")
  3824. el.style.position = "absolute"
  3825. el.style.top = element.top + "px"
  3826. el.style.left = element.left + "px"
  3827. el.style.width = element.width + "px"
  3828. el.style.height = element.height + "px"
  3829. el.style.zIndex = element.order
  3830. // 递归渲染SmartArt节点
  3831. const renderDiagramNode = (node) => {
  3832. const nodeEl = document.createElement("div")
  3833. nodeEl.style.position = "absolute"
  3834. nodeEl.style.left = node.left + "px"
  3835. nodeEl.style.top = node.top + "px"
  3836. nodeEl.style.width = node.width + "px"
  3837. nodeEl.style.height = node.height + "px"
  3838. // 设置边框
  3839. if (node.borderWidth > 0) {
  3840. nodeEl.style.border = `${node.borderWidth}px ${node.borderType} ${node.borderColor}`
  3841. if (node.borderStrokeDasharray && node.borderStrokeDasharray !== "0") {
  3842. nodeEl.style.borderStyle = "dashed"
  3843. }
  3844. }
  3845. // 设置背景填充
  3846. if (node.fill && node.fill.type === "color") {
  3847. nodeEl.style.backgroundColor = node.fill.value
  3848. }
  3849. // 设置内容
  3850. if (node.content) {
  3851. nodeEl.innerHTML = convertPtToPxInContent(node.content)
  3852. }
  3853. // 设置垂直对齐
  3854. if (node.vAlign === "mid") {
  3855. nodeEl.style.display = "flex"
  3856. nodeEl.style.alignItems = "center"
  3857. nodeEl.style.justifyContent = "center"
  3858. }
  3859. // 设置翻转
  3860. const transforms = []
  3861. if (node.isFlipV) {
  3862. transforms.push("scaleY(-1)")
  3863. }
  3864. if (node.isFlipH) {
  3865. transforms.push("scaleX(-1)")
  3866. }
  3867. if (transforms.length > 0) {
  3868. nodeEl.style.transform = transforms.join(" ")
  3869. }
  3870. return nodeEl
  3871. }
  3872. // 按照 order 排序元素
  3873. const sortedElements = [...element.elements].sort((a, b) => a.order - b.order)
  3874. // 渲染所有节点
  3875. sortedElements.forEach((node) => {
  3876. const nodeEl = renderDiagramNode(node)
  3877. el.appendChild(nodeEl)
  3878. })
  3879. return el
  3880. }
  3881. // 创建数学公式元素
  3882. const createMathElement = (element) => {
  3883. const el = document.createElement("div")
  3884. el.style.position = "absolute"
  3885. el.style.top = element.top + "px"
  3886. el.style.left = element.left + "px"
  3887. el.style.width = element.width + "px"
  3888. el.style.height = element.height + "px"
  3889. el.style.zIndex = element.order
  3890. // 应用旋转变换
  3891. if (element.rotate) {
  3892. el.style.transform = `rotate(${element.rotate}deg)`
  3893. el.style.transformOrigin = "center center"
  3894. }
  3895. // 设置数学公式内容
  3896. if (element.mathXml) {
  3897. // 如果有MathML格式的内容
  3898. try {
  3899. // 创建MathML命名空间的元素
  3900. const mathEl = document.createElementNS(
  3901. "http://www.w3.org/1998/Math/MathML",
  3902. "math"
  3903. )
  3904. mathEl.innerHTML = element.mathXml
  3905. el.appendChild(mathEl)
  3906. } catch (error) {
  3907. console.error("创建MathML元素失败:", error)
  3908. // 回退方案:直接显示文本
  3909. el.textContent = element.text || "数学公式"
  3910. }
  3911. } else if (element.text) {
  3912. // 如果只有文本内容
  3913. el.textContent = element.text
  3914. }
  3915. // 应用样式
  3916. if (element.style) {
  3917. // 字体样式
  3918. if (element.style.fontFamily) {
  3919. el.style.fontFamily = element.style.fontFamily
  3920. }
  3921. // 字体大小
  3922. if (element.style.fontSize) {
  3923. el.style.fontSize = element.style.fontSize + "px"
  3924. }
  3925. // 字体颜色
  3926. if (element.style.color) {
  3927. el.style.color = element.style.color
  3928. }
  3929. }
  3930. // 应用背景色
  3931. if (element.fill && element.fill.type === "color") {
  3932. el.style.backgroundColor = element.fill.value
  3933. }
  3934. // 应用边框
  3935. if (element.borderColor && element.borderWidth) {
  3936. el.style.border = `${element.borderWidth}px ${
  3937. element.borderType || "solid"
  3938. } ${element.borderColor}`
  3939. }
  3940. return el
  3941. }
  3942. // 创建文本元素
  3943. const createTextElement = (element) => {
  3944. const el = document.createElement("div")
  3945. if (element.content) {
  3946. // 转换内容中的pt单位为px单位
  3947. const convertedContent = convertPtToPxInContent(element.content)
  3948. el.innerHTML = convertedContent
  3949. // 设置文本样式
  3950. el.style.width = element.width + "px"
  3951. el.style.height = element.height + "px"
  3952. el.style.color = element.fontColor || "#000"
  3953. el.style.fontSize = element.fontSize
  3954. el.style.fontFamily = element.fontFamily || "Arial"
  3955. el.style.textAlign = element.align || "left"
  3956. el.style.fontWeight = element.bold ? "bold" : "normal"
  3957. el.style.fontStyle = element.italic ? "italic" : "normal"
  3958. el.style.textDecoration = element.underline ? "underline" : "none"
  3959. el.style.position = "absolute"
  3960. el.style.top = element.top + "px" || "0"
  3961. el.style.left = element.left + "px" || "0"
  3962. el.style.zIndex = element.order
  3963. el.style.whiteSpace = "pre-wrap"
  3964. // 添加垂直对齐支持
  3965. el.style.display = "flex"
  3966. el.style.flexDirection = "column"
  3967. switch (element.vAlign) {
  3968. case "up":
  3969. el.style.justifyContent = "flex-start"
  3970. break
  3971. case "mid":
  3972. el.style.justifyContent = "center"
  3973. break
  3974. case "down":
  3975. el.style.justifyContent = "flex-end"
  3976. break
  3977. default:
  3978. el.style.justifyContent = "flex-start"
  3979. }
  3980. // 设置段落间距
  3981. el.style.lineHeight = element.lineHeight + "px" || "1.2"
  3982. el.style.letterSpacing = element.charSpacing
  3983. ? `${element.charSpacing}px`
  3984. : "normal"
  3985. }
  3986. return el
  3987. }
  3988. // 递归调整元素位置
  3989. const adjustElementPosition = (element, parentElement) => {
  3990. // 创建深拷贝,但保留特殊属性的引用
  3991. const adjustedElement = JSON.parse(JSON.stringify(element))
  3992. // 调整位置为相对于父组合元素的位置
  3993. adjustedElement.top = element.top - parentElement.top
  3994. adjustedElement.left = element.left - parentElement.left
  3995. // 恢复特殊属性的引用
  3996. const specialProps = [
  3997. "src",
  3998. "blob",
  3999. "fill",
  4000. "text",
  4001. "path",
  4002. "elements",
  4003. "borderColor",
  4004. "borderWidth",
  4005. "borderType",
  4006. ]
  4007. specialProps.forEach((prop) => {
  4008. if (element[prop] !== undefined) {
  4009. adjustedElement[prop] = element[prop]
  4010. }
  4011. })
  4012. // 如果是组合元素,递归处理其子元素
  4013. if (element.type === "group" && element.elements) {
  4014. adjustedElement.elements = element.elements.map((childElement) =>
  4015. adjustElementPosition(childElement, {
  4016. top: element.top,
  4017. left: element.left,
  4018. })
  4019. )
  4020. }
  4021. return adjustedElement
  4022. }
  4023. // 绘制类别标签
  4024. const drawCategoryLabels = (svg, categories, padding, groupWidth, barDir) => {
  4025. if (!categories || !categories.length) return
  4026. // 创建标签组
  4027. const labelGroup = document.createElementNS("http://www.w3.org/2000/svg", "g")
  4028. labelGroup.setAttribute("class", "category-labels")
  4029. // 计算标签位置
  4030. const isVertical = barDir === "vertical"
  4031. const labelSpacing = groupWidth
  4032. // 绘制每个类别标签
  4033. categories.forEach((category, index) => {
  4034. const label = document.createElementNS("http://www.w3.org/2000/svg", "text")
  4035. // 设置标签文本
  4036. label.textContent = category
  4037. // 设置标签样式
  4038. label.setAttribute("font-size", "12")
  4039. label.setAttribute("text-anchor", isVertical ? "middle" : "start")
  4040. // 设置标签位置
  4041. if (isVertical) {
  4042. // 垂直条形图,标签在底部
  4043. label.setAttribute("x", padding + index * labelSpacing + labelSpacing / 2)
  4044. label.setAttribute("y", svg.getAttribute("height") - padding / 3)
  4045. label.setAttribute("dominant-baseline", "hanging")
  4046. } else {
  4047. // 水平条形图,标签在左侧
  4048. label.setAttribute("x", padding / 2)
  4049. label.setAttribute("y", padding + index * labelSpacing + labelSpacing / 2)
  4050. label.setAttribute("dominant-baseline", "middle")
  4051. label.setAttribute("text-anchor", "end")
  4052. }
  4053. // 添加标签到组
  4054. labelGroup.appendChild(label)
  4055. })
  4056. // 将标签组添加到SVG
  4057. svg.appendChild(labelGroup)
  4058. return labelGroup
  4059. }
  4060. /**
  4061. * 绘制甜甜圈图表
  4062. * @param {SVGElement} svg - SVG容器元素
  4063. * @param {Object} element - 图表配置对象
  4064. * @param {number} chartWidth - 图表宽度
  4065. * @param {number} chartHeight - 图表高度
  4066. */
  4067. const drawDonutChart = (svg, element, chartWidth, chartHeight) => {
  4068. // 数据验证
  4069. if (!element?.data?.[0]?.values) return
  4070. const series = element.data[0]
  4071. const values = series.values.map((v) => Number(v.y) || 0)
  4072. const total = values.reduce((sum, v) => sum + v, 0)
  4073. if (total === 0) return
  4074. // 基础配置
  4075. const cx = chartWidth / 2
  4076. const cy = chartHeight / 2
  4077. // 保持较大的外半径
  4078. const outerR = (Math.min(chartWidth, chartHeight) / 2) * 0.98
  4079. // 处理空心大小
  4080. const holeSize = element.holeSize ? parseInt(element.holeSize) : 50
  4081. const innerR = outerR * (holeSize / 100)
  4082. // 默认颜色和自定义颜色处理
  4083. const defaultColors = [
  4084. "#4e79a7",
  4085. "#f28e2b",
  4086. "#e15759",
  4087. "#76b7b2",
  4088. "#59a14f",
  4089. "#edc949",
  4090. "#af7aa1",
  4091. "#ff9da7",
  4092. ]
  4093. const colors =
  4094. element.colors?.map(
  4095. (color, i) => color || defaultColors[i % defaultColors.length]
  4096. ) || defaultColors
  4097. // 标签数据
  4098. const labels = series.xlabels || {}
  4099. // 创建图表组
  4100. const chartGroup = document.createElementNS("http://www.w3.org/2000/svg", "g")
  4101. chartGroup.setAttribute("transform", `translate(${cx},${cy})`)
  4102. // 绘制扇形
  4103. let startAngle = -Math.PI / 2 // 从顶部开始绘制
  4104. values.forEach((value, index) => {
  4105. if (value <= 0) return
  4106. const percentage = value / total
  4107. const angle = percentage * Math.PI * 2
  4108. const endAngle = startAngle + angle
  4109. // 计算路径点 (相对于组中心 0,0)
  4110. const x1 = outerR * Math.cos(startAngle)
  4111. const y1 = outerR * Math.sin(startAngle)
  4112. const x2 = outerR * Math.cos(endAngle)
  4113. const y2 = outerR * Math.sin(endAngle)
  4114. const x3 = innerR * Math.cos(endAngle)
  4115. const y3 = innerR * Math.sin(endAngle)
  4116. const x4 = innerR * Math.cos(startAngle)
  4117. const y4 = innerR * Math.sin(startAngle)
  4118. // 构建路径
  4119. const path = document.createElementNS("http://www.w3.org/2000/svg", "path")
  4120. const largeArc = angle > Math.PI ? 1 : 0
  4121. const d = [
  4122. `M ${x1} ${y1}`,
  4123. `A ${outerR} ${outerR} 0 ${largeArc} 1 ${x2} ${y2}`,
  4124. `L ${x3} ${y3}`,
  4125. `A ${innerR} ${innerR} 0 ${largeArc} 0 ${x4} ${y4}`,
  4126. "Z",
  4127. ].join(" ")
  4128. path.setAttribute("d", d)
  4129. path.setAttribute("fill", colors[index % colors.length]) // 确保颜色循环使用
  4130. // 添加交互效果
  4131. path.style.transition = "transform 0.2s"
  4132. path.addEventListener("mouseover", () => {
  4133. path.style.transform = "scale(1.03)"
  4134. })
  4135. path.addEventListener("mouseout", () => {
  4136. path.style.transform = "scale(1)"
  4137. })
  4138. chartGroup.appendChild(path)
  4139. // 添加标签
  4140. const midAngle = startAngle + angle / 2
  4141. const labelR = outerR * 1.1
  4142. const labelX = labelR * Math.cos(midAngle)
  4143. const labelY = labelR * Math.sin(midAngle)
  4144. const text = document.createElementNS("http://www.w3.org/2000/svg", "text")
  4145. text.setAttribute("x", labelX)
  4146. text.setAttribute("y", labelY)
  4147. text.setAttribute("text-anchor", labelX < 0 ? "end" : "start")
  4148. text.setAttribute("dominant-baseline", "middle")
  4149. text.setAttribute("fill", "#555")
  4150. text.setAttribute("font-size", "9")
  4151. text.setAttribute("font-weight", "normal")
  4152. const tspanLabel = document.createElementNS(
  4153. "http://www.w3.org/2000/svg",
  4154. "tspan"
  4155. )
  4156. tspanLabel.setAttribute("x", labelX)
  4157. tspanLabel.textContent = labels[index] || `类别 ${index + 1}`
  4158. text.appendChild(tspanLabel)
  4159. const tspanPercent = document.createElementNS(
  4160. "http://www.w3.org/2000/svg",
  4161. "tspan"
  4162. )
  4163. tspanPercent.setAttribute("x", labelX)
  4164. tspanPercent.setAttribute("dy", "1.2em")
  4165. tspanPercent.textContent = `${(percentage * 100).toFixed(1)}%`
  4166. text.appendChild(tspanPercent)
  4167. chartGroup.appendChild(text)
  4168. startAngle = endAngle
  4169. })
  4170. svg.appendChild(chartGroup)
  4171. const padding = 50
  4172. svg.setAttribute(
  4173. "viewBox",
  4174. `${-cx / 2} ${-cy / 2} ${chartWidth + padding * 2} ${
  4175. chartHeight + padding * 2
  4176. }`
  4177. )
  4178. svg.style.overflow = "visible"
  4179. }
  4180. const drawBarChart = (svg, element, options) => {
  4181. const { padding, chartWidth, chartHeight, barDir, grouping } = options
  4182. const series = element.data
  4183. const categories = series[0].xlabels
  4184. const categoryCount = Object.keys(categories).length
  4185. // 1. 计算最大值
  4186. let maxValue = 0
  4187. series.forEach((serie) => {
  4188. const seriesMax = Math.max(...serie.values.map((v) => v.y))
  4189. maxValue = Math.max(maxValue, seriesMax)
  4190. })
  4191. maxValue = maxValue * 1.2 // 增加20%空间
  4192. // 2. 计算柱子布局
  4193. const groupWidth = chartWidth / categoryCount
  4194. const barWidth =
  4195. grouping === "clustered"
  4196. ? (groupWidth * 0.6) / series.length // 分组模式
  4197. : groupWidth * 0.6 // 堆叠模式
  4198. const barSpacing =
  4199. (groupWidth * 0.4) / (grouping === "clustered" ? series.length + 1 : 2)
  4200. // 3. 绘制坐标轴
  4201. // X轴
  4202. const xAxisPath = document.createElementNS(
  4203. "http://www.w3.org/2000/svg",
  4204. "path"
  4205. )
  4206. xAxisPath.setAttribute(
  4207. "d",
  4208. `M${padding.left},${element.height - padding.bottom} L${
  4209. element.width - padding.right
  4210. },${element.height - padding.bottom}`
  4211. )
  4212. xAxisPath.setAttribute("stroke", "#000")
  4213. xAxisPath.setAttribute("stroke-width", "1")
  4214. svg.appendChild(xAxisPath)
  4215. // Y轴
  4216. const yAxisPath = document.createElementNS(
  4217. "http://www.w3.org/2000/svg",
  4218. "path"
  4219. )
  4220. yAxisPath.setAttribute(
  4221. "d",
  4222. `M${padding.left},${padding.top} L${padding.left},${
  4223. element.height - padding.bottom
  4224. }`
  4225. )
  4226. yAxisPath.setAttribute("stroke", "#000")
  4227. yAxisPath.setAttribute("stroke-width", "1")
  4228. svg.appendChild(yAxisPath)
  4229. // 4. 绘制Y轴刻度和网格线
  4230. const yTickCount = 5
  4231. for (let i = 0; i <= yTickCount; i++) {
  4232. const y = padding.top + (chartHeight * i) / yTickCount
  4233. const value = maxValue - (maxValue * i) / yTickCount
  4234. // 水平网格线
  4235. const gridLine = document.createElementNS(
  4236. "http://www.w3.org/2000/svg",
  4237. "line"
  4238. )
  4239. gridLine.setAttribute("x1", padding.left)
  4240. gridLine.setAttribute("y1", y)
  4241. gridLine.setAttribute("x2", padding.left + chartWidth)
  4242. gridLine.setAttribute("y2", y)
  4243. gridLine.setAttribute("stroke", "#eee")
  4244. gridLine.setAttribute("stroke-width", "1")
  4245. svg.appendChild(gridLine)
  4246. // 刻度线
  4247. const tick = document.createElementNS("http://www.w3.org/2000/svg", "line")
  4248. tick.setAttribute("x1", padding.left - 6)
  4249. tick.setAttribute("y1", y)
  4250. tick.setAttribute("x2", padding.left)
  4251. tick.setAttribute("y2", y)
  4252. tick.setAttribute("stroke", "#000")
  4253. tick.setAttribute("stroke-width", "1")
  4254. svg.appendChild(tick)
  4255. // 刻度值
  4256. const label = document.createElementNS("http://www.w3.org/2000/svg", "text")
  4257. label.setAttribute("x", padding.left - 10)
  4258. label.setAttribute("y", y + 4)
  4259. label.setAttribute("text-anchor", "end")
  4260. label.setAttribute("font-size", "12px")
  4261. label.textContent = value.toFixed(1)
  4262. svg.appendChild(label)
  4263. }
  4264. // 5. 绘制数据条
  4265. series.forEach((serie, serieIndex) => {
  4266. serie.values.forEach((value, index) => {
  4267. const barHeight = (value.y / maxValue) * chartHeight
  4268. const x =
  4269. padding.left +
  4270. groupWidth * index +
  4271. (grouping === "clustered"
  4272. ? barSpacing * (serieIndex + 1) + barWidth * serieIndex
  4273. : barSpacing)
  4274. const y = element.height - padding.bottom - barHeight
  4275. // 绘制柱子
  4276. const bar = document.createElementNS("http://www.w3.org/2000/svg", "rect")
  4277. bar.setAttribute("x", x)
  4278. bar.setAttribute("y", y)
  4279. bar.setAttribute("width", barWidth)
  4280. bar.setAttribute("height", barHeight)
  4281. bar.setAttribute(
  4282. "fill",
  4283. element.colors[serieIndex] || `hsl(${serieIndex * 60}, 70%, 50%)`
  4284. )
  4285. svg.appendChild(bar)
  4286. // 数值标签
  4287. if (element.marker) {
  4288. const label = document.createElementNS(
  4289. "http://www.w3.org/2000/svg",
  4290. "text"
  4291. )
  4292. label.setAttribute("x", x + barWidth / 2)
  4293. label.setAttribute("y", y - 5)
  4294. label.setAttribute("text-anchor", "middle")
  4295. label.setAttribute("font-size", "12px")
  4296. label.textContent = value.y.toFixed(1)
  4297. svg.appendChild(label)
  4298. }
  4299. })
  4300. })
  4301. // 6. 绘制X轴类别标签
  4302. Object.values(categories).forEach((label, index) => {
  4303. const x = padding.left + groupWidth * (index + 0.5)
  4304. const text = document.createElementNS("http://www.w3.org/2000/svg", "text")
  4305. text.setAttribute("x", x)
  4306. text.setAttribute("y", element.height - padding.bottom + 20)
  4307. text.setAttribute("text-anchor", "middle")
  4308. text.setAttribute("font-size", "12px")
  4309. text.textContent = label
  4310. svg.appendChild(text)
  4311. })
  4312. // 7. 绘制图例
  4313. series.forEach((serie, index) => {
  4314. const legendX = padding.left + index * 120
  4315. const legendY = 20
  4316. const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect")
  4317. rect.setAttribute("x", legendX)
  4318. rect.setAttribute("y", legendY)
  4319. rect.setAttribute("width", 15)
  4320. rect.setAttribute("height", 15)
  4321. rect.setAttribute(
  4322. "fill",
  4323. element.colors[index] || `hsl(${index * 60}, 70%, 50%)`
  4324. )
  4325. svg.appendChild(rect)
  4326. const text = document.createElementNS("http://www.w3.org/2000/svg", "text")
  4327. text.setAttribute("x", legendX + 25)
  4328. text.setAttribute("y", legendY + 12)
  4329. text.setAttribute("font-size", "12px")
  4330. text.textContent = serie.key
  4331. svg.appendChild(text)
  4332. })
  4333. }
  4334. // 绘制网格线
  4335. const drawGrid = (svg, padding, width, height, maxValue) => {
  4336. // 创建网格组
  4337. const gridGroup = document.createElementNS("http://www.w3.org/2000/svg", "g")
  4338. gridGroup.setAttribute("class", "chart-grid")
  4339. // 设置网格线样式
  4340. const gridColor = "#e0e0e0"
  4341. const gridWidth = 1
  4342. // 计算网格间距
  4343. const gridCount = 5 // 网格线数量
  4344. const gridStep = (height - padding * 2) / gridCount
  4345. // 绘制水平网格线
  4346. for (let i = 0; i <= gridCount; i++) {
  4347. const y = padding + i * gridStep
  4348. const line = document.createElementNS("http://www.w3.org/2000/svg", "line")
  4349. line.setAttribute("x1", padding)
  4350. line.setAttribute("y1", y)
  4351. line.setAttribute("x2", width - padding)
  4352. line.setAttribute("y2", y)
  4353. line.setAttribute("stroke", gridColor)
  4354. line.setAttribute("stroke-width", gridWidth)
  4355. // 如果是底线,加粗显示
  4356. if (i === gridCount) {
  4357. line.setAttribute("stroke-width", gridWidth * 2)
  4358. line.setAttribute("stroke", "#aaa")
  4359. }
  4360. gridGroup.appendChild(line)
  4361. // 添加刻度值(除了底线)
  4362. if (i < gridCount) {
  4363. const valueText = document.createElementNS(
  4364. "http://www.w3.org/2000/svg",
  4365. "text"
  4366. )
  4367. const value = Math.round((gridCount - i) * (maxValue / gridCount))
  4368. valueText.textContent = value
  4369. valueText.setAttribute("x", padding - 5)
  4370. valueText.setAttribute("y", y)
  4371. valueText.setAttribute("text-anchor", "end")
  4372. valueText.setAttribute("dominant-baseline", "middle")
  4373. valueText.setAttribute("font-size", "10")
  4374. valueText.setAttribute("fill", "#666")
  4375. gridGroup.appendChild(valueText)
  4376. }
  4377. }
  4378. // 添加网格组到SVG
  4379. svg.appendChild(gridGroup)
  4380. return gridGroup
  4381. }
  4382. // 绘制图表图例
  4383. const drawLegend = (svg, series, colors, padding) => {
  4384. // 创建图例容器
  4385. const legendGroup = document.createElementNS(
  4386. "http://www.w3.org/2000/svg",
  4387. "g"
  4388. )
  4389. legendGroup.setAttribute("class", "chart-legend")
  4390. // 设置图例位置
  4391. const legendX = padding
  4392. const legendY = padding
  4393. let currentY = legendY
  4394. // 为每个系列创建图例项
  4395. series.forEach((item, index) => {
  4396. const itemGroup = document.createElementNS(
  4397. "http://www.w3.org/2000/svg",
  4398. "g"
  4399. )
  4400. itemGroup.setAttribute("transform", `translate(${legendX}, ${currentY})`)
  4401. // 创建图例颜色标记
  4402. const colorMark = document.createElementNS(
  4403. "http://www.w3.org/2000/svg",
  4404. "rect"
  4405. )
  4406. colorMark.setAttribute("width", "12")
  4407. colorMark.setAttribute("height", "12")
  4408. colorMark.setAttribute("fill", colors[index % colors.length])
  4409. // 创建图例文本
  4410. const text = document.createElementNS("http://www.w3.org/2000/svg", "text")
  4411. text.setAttribute("x", "20")
  4412. text.setAttribute("y", "10")
  4413. text.setAttribute("font-size", "12")
  4414. text.setAttribute("alignment-baseline", "middle")
  4415. text.textContent = item.name || `系列 ${index + 1}`
  4416. // 将元素添加到组中
  4417. itemGroup.appendChild(colorMark)
  4418. itemGroup.appendChild(text)
  4419. legendGroup.appendChild(itemGroup)
  4420. // 更新下一个图例项的Y坐标
  4421. currentY += 20
  4422. })
  4423. // 将图例组添加到SVG中
  4424. svg.appendChild(legendGroup)
  4425. return legendGroup
  4426. }
  4427. // 调整颜色亮度
  4428. const adjustBrightness = (color, factor) => {
  4429. // 如果颜色为空或不是字符串,返回原值
  4430. if (!color || typeof color !== "string") return color
  4431. // 处理十六进制颜色
  4432. if (color.startsWith("#")) {
  4433. let hex = color.substring(1)
  4434. // 处理简写形式 (#RGB)
  4435. if (hex.length === 3) {
  4436. hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]
  4437. }
  4438. // 解析RGB值
  4439. const r = parseInt(hex.substring(0, 2), 16)
  4440. const g = parseInt(hex.substring(2, 4), 16)
  4441. const b = parseInt(hex.substring(4, 6), 16)
  4442. // 调整亮度
  4443. const adjustedR = Math.min(255, Math.max(0, Math.round(r * factor)))
  4444. const adjustedG = Math.min(255, Math.max(0, Math.round(g * factor)))
  4445. const adjustedB = Math.min(255, Math.max(0, Math.round(b * factor)))
  4446. // 转换回十六进制
  4447. return `#${adjustedR.toString(16).padStart(2, "0")}${adjustedG
  4448. .toString(16)
  4449. .padStart(2, "0")}${adjustedB.toString(16).padStart(2, "0")}`
  4450. }
  4451. // 处理rgb/rgba颜色
  4452. if (color.startsWith("rgb")) {
  4453. const rgbMatch = color.match(
  4454. /rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/
  4455. )
  4456. if (rgbMatch) {
  4457. const r = parseInt(rgbMatch[1])
  4458. const g = parseInt(rgbMatch[2])
  4459. const b = parseInt(rgbMatch[3])
  4460. const a = rgbMatch[4] !== undefined ? parseFloat(rgbMatch[4]) : 1
  4461. // 调整亮度
  4462. const adjustedR = Math.min(255, Math.max(0, Math.round(r * factor)))
  4463. const adjustedG = Math.min(255, Math.max(0, Math.round(g * factor)))
  4464. const adjustedB = Math.min(255, Math.max(0, Math.round(b * factor)))
  4465. // 返回调整后的颜色
  4466. return a < 1
  4467. ? `rgba(${adjustedR}, ${adjustedG}, ${adjustedB}, ${a})`
  4468. : `rgb(${adjustedR}, ${adjustedG}, ${adjustedB})`
  4469. }
  4470. }
  4471. // 如果不是支持的颜色格式,返回原值
  4472. return color
  4473. }
  4474. const convertPtToPxInContent = (content) => {
  4475. if (!content) return ""
  4476. // 使用正则表达式查找所有包含pt单位的样式
  4477. const ptRegex = /(\d+(\.\d+)?)pt/g
  4478. return content.replace(/(\d+\.?\d*)(pt|PT)/g, (match, size) => {
  4479. // 将 pt 转换为 px(1pt ≈ 1.33333px)
  4480. const pxSize = size
  4481. return `${pxSize}px`
  4482. })
  4483. }
  4484. const processElements = (elements, slideIndex) => {
  4485. if (!elements || !Array.isArray(elements)) return
  4486. // 使用 Map 存储原始顺序,避免多次排序
  4487. const orderMap = new Map(elements.map((el, index) => [el, el.order || index]))
  4488. // 一次性排序
  4489. elements.sort((a, b) => orderMap.get(a) - orderMap.get(b))
  4490. const processElement = (element, baseOrder) => {
  4491. // 设置当前元素的 order
  4492. element.order = baseOrder
  4493. // 如果有子元素,递归处理
  4494. if (element.elements?.length > 0) {
  4495. element.elements
  4496. .sort((a, b) => (a.order || 0) - (b.order || 0))
  4497. .forEach((child, idx) => {
  4498. processElement(child, baseOrder * 10 + idx + 1)
  4499. })
  4500. }
  4501. }
  4502. // 处理每个顶层元素
  4503. elements.forEach((element, index) => {
  4504. processElement(element, (slideIndex + 1) * 10 + index + 1)
  4505. })
  4506. }
  4507. // 监听 pptxJson 变化
  4508. watch(
  4509. () => props.pptxJson,
  4510. (newVal) => {
  4511. if (newVal) {
  4512. renderSlides()
  4513. }
  4514. },
  4515. { deep: true }
  4516. )
  4517. // 组件挂载时渲染幻灯片
  4518. onMounted(() => {
  4519. renderSlides()
  4520. })
  4521. </script>
  4522. <style scoped>
  4523. .pptx-container {
  4524. width: 100%;
  4525. overflow-x: auto;
  4526. padding: 20px 0;
  4527. }
  4528. </style>