PensProps.vue 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071
  1. <template>
  2. <div class="props">
  3. <t-tabs v-model="data.tab">
  4. <t-tab-panel :value="1" label="外观">
  5. <t-space direction="vertical" class="py-16 w-full">
  6. <div class="px-16 flex between" style="margin-bottom:2px;">
  7. <label>选中了{{ selections.pens.length }}个图元</label>
  8. <div class="icons">
  9. <t-tooltip
  10. class="mr-4"
  11. v-if="!data.locked"
  12. content="可编辑"
  13. placement="top"
  14. >
  15. <svg class="l-icon" aria-hidden="true" @click="lock(1)">
  16. <use xlink:href="#l-unlock"></use>
  17. </svg>
  18. </t-tooltip>
  19. <t-tooltip
  20. class="mr-4"
  21. v-else-if="data.locked == 1"
  22. content="禁止编辑"
  23. placement="top"
  24. >
  25. <svg class="l-icon" aria-hidden="true" @click="lock(2)">
  26. <use xlink:href="#l-lock"></use>
  27. </svg>
  28. </t-tooltip>
  29. <t-tooltip
  30. class="mr-4"
  31. v-else-if="data.locked == 2"
  32. content="禁止编辑和移动"
  33. placement="top"
  34. >
  35. <svg class="l-icon" aria-hidden="true" @click="lock(10)">
  36. <use xlink:href="#l-wufayidong"></use>
  37. </svg>
  38. </t-tooltip>
  39. <t-tooltip
  40. class="mr-4"
  41. v-else-if="data.locked == 10"
  42. content="禁止所有事件"
  43. placement="top"
  44. >
  45. <svg class="l-icon" aria-hidden="true" @click="lock(0)">
  46. <use xlink:href="#l-jinyong"></use>
  47. </svg>
  48. </t-tooltip>
  49. <browse-icon v-if="data.visible !== false"
  50. @click="visible(false)"
  51. class="ml-8"/>
  52. <browse-off-icon v-else
  53. @click="visible(true)"
  54. class="ml-8"/>
  55. <!-- <t-icon
  56. v-if="data.visible !== false"
  57. name="browse"
  58. @click="visible(false)"
  59. class="ml-8"
  60. />
  61. <t-icon
  62. v-else
  63. name="browse-off"
  64. @click="visible(true)"
  65. class="ml-8"
  66. /> -->
  67. </div>
  68. </div>
  69. <div class="form-item px-16" style="margin-top: -12px">
  70. <label style="width: 50px">分组</label>
  71. <t-select-input
  72. v-model:inputValue="data.inputTag"
  73. :value="data.tags"
  74. allow-input
  75. placeholder="请输入或选择分组"
  76. multiple
  77. @tag-change="onChangeInputTag"
  78. @focus="data.tagPopupVisible = true"
  79. @blur="data.tagPopupVisible = false"
  80. :tag-input-props="{ excessTagsDisplayType: 'break-line' }"
  81. >
  82. <template #panel>
  83. <ul style="padding: 8px 12px">
  84. <li
  85. v-for="item in data.groups"
  86. :key="item"
  87. @click="onSelectTag(item)"
  88. >
  89. {{ item }}
  90. </li>
  91. </ul>
  92. </template>
  93. </t-select-input>
  94. </div>
  95. <div class="form-item px-16" style="margin-top: -12px">
  96. <label style="width: 50px">画布层</label>
  97. <t-select
  98. v-model="data.canvasLayer"
  99. @change="changeValue('canvasLayer')"
  100. >
  101. <t-option :key="4" :disabled="!allImg" :value="4" label="上层图片层"> 上层图片层 </t-option>
  102. <t-option :key="3" :disabled="hasDom" :value="3" label="主画布层"> 主画布层 </t-option>
  103. <t-option :key="2" :disabled="!allImg" :value="2" label="下层图片层"> 下层图片层 </t-option>
  104. <t-option :key="1" :disabled="hasDom" :value="1" label="模板层"> 模板层 </t-option>
  105. </t-select>
  106. </div>
  107. <t-collapse
  108. :defaultValue="['1', '2', '3', '4']"
  109. expandIconPlacement="right"
  110. :borderless="true"
  111. >
  112. <t-collapse-panel value="1" header="对齐">
  113. <t-space direction="vertical" size="small" class="w-full">
  114. <div style="color: var(--color); margin-bottom: 2px">
  115. 区域对齐
  116. </div>
  117. <div class="icons">
  118. <t-tooltip
  119. v-for="item in aligns"
  120. :content="item.label"
  121. placement="top"
  122. >
  123. <svg
  124. class="l-icon btn"
  125. aria-hidden="true"
  126. @click="align(item.value)"
  127. >
  128. <use :xlink:href="item.icon"></use>
  129. </svg>
  130. </t-tooltip>
  131. </div>
  132. </t-space>
  133. <t-divider
  134. style="margin: 16px -16px 12px -16px; width: calc(100% + 32px)"
  135. />
  136. <t-space direction="vertical" size="small" class="w-full">
  137. <div style="color: var(--color); margin-bottom: 2px">
  138. 以最后选中图元对齐
  139. </div>
  140. <div class="icons">
  141. <t-tooltip
  142. v-for="item in aligns2"
  143. :content="item.label"
  144. placement="top"
  145. >
  146. <svg
  147. class="l-icon btn"
  148. aria-hidden="true"
  149. @click="align2(item.value)"
  150. >
  151. <use :xlink:href="item.icon"></use>
  152. </svg>
  153. </t-tooltip>
  154. </div>
  155. </t-space>
  156. </t-collapse-panel>
  157. <t-collapse-panel value="2" header="外观">
  158. <t-space direction="vertical" size="small" class="w-full">
  159. <div class="form-item">
  160. <t-color-picker
  161. class="simple mt-8 mr-4"
  162. format="CSS"
  163. :enable-alpha="true"
  164. :recent-colors="null"
  165. :swatch-colors="defaultPureColor"
  166. :color-modes="['monochrome']"
  167. :show-primary-color-preview="false"
  168. :clearable="true"
  169. v-model="data.color"
  170. @change="changeValue('color')"
  171. />
  172. <label style="width: 64px">前景颜色</label>
  173. <t-color-picker
  174. class="simple mt-8 mr-4"
  175. format="CSS"
  176. :enable-alpha="true"
  177. :recent-colors="null"
  178. :swatch-colors="defaultPureColor"
  179. :color-modes="['monochrome']"
  180. :show-primary-color-preview="false"
  181. v-model="data.hoverColor"
  182. @change="changeValue('hoverColor')"
  183. />
  184. <label style="width: 64px">悬停颜色</label>
  185. <t-color-picker
  186. class="simple mt-8 mr-4"
  187. format="CSS"
  188. :enable-alpha="true"
  189. :recent-colors="null"
  190. :swatch-colors="defaultPureColor"
  191. :color-modes="['monochrome']"
  192. :show-primary-color-preview="false"
  193. v-model="data.activeColor"
  194. @change="changeValue('activeColor')"
  195. />
  196. <label style="width: 64px">选中颜色</label>
  197. </div>
  198. <div class="form-item">
  199. <label style="width: 32px">线条 </label>
  200. <t-select
  201. v-model="data.dash"
  202. placeholder="线条样式"
  203. @change="changeValue('dash')"
  204. style="width: 80px"
  205. >
  206. <template #valueDisplay="{ value }">
  207. <svg
  208. xmlns="http://www.w3.org/2000/svg"
  209. version="1.1"
  210. style="width: 100%; height: 20px"
  211. >
  212. <g fill="none" stroke="var(--color)" stroke-width="1">
  213. <path v-if="value === 0" d="M0 9 l85 0" />
  214. <path
  215. v-else-if="value === 1"
  216. stroke-dasharray="5 5"
  217. d="M0 9 l85 0"
  218. />
  219. <path
  220. v-else-if="value === 2"
  221. stroke-dasharray="10 10"
  222. d="M0 9 l85 0"
  223. />
  224. <path
  225. v-else-if="value === 3"
  226. stroke-dasharray="10 10 2 10"
  227. d="M0 9 l85 0"
  228. />
  229. </g>
  230. </svg>
  231. </template>
  232. <t-option :key="0" :value="0">
  233. <svg
  234. xmlns="http://www.w3.org/2000/svg"
  235. version="1.1"
  236. style="width: 80px; height: 14px"
  237. >
  238. <g fill="none" stroke="var(--color)" stroke-width="1">
  239. <path d="M0 9 l85 0" />
  240. </g>
  241. </svg>
  242. </t-option>
  243. <t-option :key="1" :value="1">
  244. <svg
  245. xmlns="http://www.w3.org/2000/svg"
  246. version="1.1"
  247. style="width: 80px; height: 14px"
  248. >
  249. <g fill="none" stroke="var(--color)" stroke-width="1">
  250. <path stroke-dasharray="5 5" d="M0 9 l85 0" />
  251. </g>
  252. </svg>
  253. </t-option>
  254. <t-option :key="2" :value="2">
  255. <svg
  256. xmlns="http://www.w3.org/2000/svg"
  257. version="1.1"
  258. style="width: 80px; height: 14px"
  259. >
  260. <g fill="none" stroke="var(--color)" stroke-width="1">
  261. <path stroke-dasharray="10 10" d="M0 9 l85 0" />
  262. </g>
  263. </svg>
  264. </t-option>
  265. <t-option :key="3" :value="3">
  266. <svg
  267. xmlns="http://www.w3.org/2000/svg"
  268. version="1.1"
  269. style="width: 80px; height: 14px"
  270. >
  271. <g fill="none" stroke="var(--color)" stroke-width="1">
  272. <path stroke-dasharray="10 10 2 10" d="M0 9 l85 0" />
  273. </g>
  274. </svg>
  275. </t-option>
  276. </t-select>
  277. <t-input-number
  278. theme="normal"
  279. placeholder="线条宽度"
  280. v-model="data.lineWidth"
  281. :min="1"
  282. :decimalPlaces="0"
  283. @change="changeValue('lineWidth')"
  284. class="ml-4"
  285. style="width: 40px"
  286. />
  287. <t-tooltip content="线条渐变" placement="top">
  288. <div class="flex middle ml-8">
  289. <t-checkbox
  290. v-model="data.strokeType"
  291. @change="changeValue('strokeType')"
  292. style="width: 22px"
  293. />
  294. <t-color-picker
  295. v-if="data.strokeType"
  296. class="simple mr-4"
  297. format="CSS"
  298. :color-modes="['linear-gradient']"
  299. :show-primary-color-preview="false"
  300. :clearable="true"
  301. :enableAlpha="true"
  302. :recent-colors="null"
  303. :swatch-colors="defaultGradientColor"
  304. v-model="data.lineGradientColors"
  305. @change="changeValue('lineGradientColors')"
  306. placeholder="无"
  307. />
  308. </div>
  309. </t-tooltip>
  310. </div>
  311. <div class="flex" style="margin-left: 40px">
  312. <div class="flex column middle">
  313. <t-radio-group
  314. size="small"
  315. v-model="data.lineCap"
  316. default-value="butt"
  317. @change="changeValue('lineCap')"
  318. >
  319. <t-radio-button value="butt">
  320. <t-tooltip content="默认" placement="top">
  321. <svg class="l-icon" aria-hidden="true">
  322. <use xlink:href="#l-duandian1"></use>
  323. </svg>
  324. </t-tooltip>
  325. </t-radio-button>
  326. <t-radio-button value="round">
  327. <t-tooltip content="圆形" placement="top">
  328. <svg class="l-icon" aria-hidden="true">
  329. <use xlink:href="#l-duandian2"></use>
  330. </svg>
  331. </t-tooltip>
  332. </t-radio-button>
  333. <t-radio-button value="square">
  334. <t-tooltip content="方形" placement="top">
  335. <svg class="l-icon" aria-hidden="true">
  336. <use xlink:href="#l-duandian3"></use>
  337. </svg>
  338. </t-tooltip>
  339. </t-radio-button>
  340. </t-radio-group>
  341. <div class="mt-4" style="font-size: 12px">末端样式</div>
  342. </div>
  343. <div class="flex column middle ml-16">
  344. <t-radio-group
  345. size="small"
  346. v-model="data.lineJoin"
  347. default-value="miter"
  348. @change="changeValue('lineJoin')"
  349. >
  350. <t-radio-button value="miter">
  351. <t-tooltip content="默认" placement="top">
  352. <svg class="l-icon" aria-hidden="true">
  353. <use xlink:href="#l-jiedian1"></use>
  354. </svg>
  355. </t-tooltip>
  356. </t-radio-button>
  357. <t-radio-button value="round">
  358. <t-tooltip content="圆形" placement="top">
  359. <svg class="l-icon" aria-hidden="true">
  360. <use xlink:href="#l-jiedian2"></use>
  361. </svg>
  362. </t-tooltip>
  363. </t-radio-button>
  364. <t-radio-button value="bevel">
  365. <t-tooltip content="斜角" placement="top">
  366. <svg class="l-icon" aria-hidden="true">
  367. <use xlink:href="#l-jiedian3"></use>
  368. </svg>
  369. </t-tooltip>
  370. </t-radio-button>
  371. </t-radio-group>
  372. <div class="mt-4" style="font-size: 12px">连接样式</div>
  373. </div>
  374. </div>
  375. <div class="form-item">
  376. <label style="width: 32px">背景</label>
  377. <div class="ml-8">
  378. <t-radio-group
  379. size="small"
  380. v-model="data.bkType"
  381. :default-value="0"
  382. @change="changeValue('bkType')"
  383. >
  384. <t-radio-button :value="0"> 纯色 </t-radio-button>
  385. <t-radio-button :value="1"> 线性渐变 </t-radio-button>
  386. <t-radio-button :value="2"> 径向渐变 </t-radio-button>
  387. </t-radio-group>
  388. <div v-if="data.bkType === 0" class="mt-8 -ml-8">
  389. <t-color-picker
  390. class="w-full"
  391. format="CSS"
  392. :enable-alpha="true"
  393. :recent-colors="null"
  394. :swatch-colors="defaultPureColor"
  395. :color-modes="['monochrome']"
  396. :show-primary-color-preview="false"
  397. v-model="data.background"
  398. @change="changeValue('background')"
  399. />
  400. </div>
  401. <div
  402. v-else-if="data.bkType === 1"
  403. class="mt-8 -ml-8"
  404. style="width: 200px"
  405. >
  406. <t-color-picker
  407. class="w-full"
  408. format="CSS"
  409. :enable-alpha="true"
  410. :recent-colors="null"
  411. :swatch-colors="defaultGradientColor"
  412. :color-modes="['linear-gradient']"
  413. :show-primary-color-preview="false"
  414. v-model="data.gradientColors"
  415. @change="changeValue('gradientColors')"
  416. />
  417. </div>
  418. <div v-else-if="data.bkType === 2" class="mt-8 flex middle">
  419. <t-color-picker
  420. class="simple"
  421. format="CSS"
  422. :enable-alpha="true"
  423. :recent-colors="null"
  424. :swatch-colors="defaultGradientColor"
  425. :color-modes="['linear-gradient']"
  426. :show-primary-color-preview="false"
  427. v-model="data.gradientColors"
  428. @change="changeValue('gradientColors')"
  429. />
  430. <t-input-number
  431. theme="column"
  432. placeholder="渐变半径"
  433. v-model="data.gradientRadius"
  434. :min="0"
  435. :max="1"
  436. :step="0.1"
  437. @change="changeValue('gradientRadius')"
  438. class="ml-8"
  439. style="width: 100px"
  440. />
  441. </div>
  442. </div>
  443. </div>
  444. <div class="form-item">
  445. <label style="width: 32px">阴影 </label>
  446. <div class="flex middle ml-8">
  447. <t-checkbox
  448. v-model="data.shadow"
  449. @change="changeValue('shadow')"
  450. style="width: 22px"
  451. />
  452. <t-color-picker
  453. v-if="data.shadow"
  454. class="simple"
  455. format="CSS"
  456. :enable-alpha="true"
  457. :recent-colors="null"
  458. :swatch-colors="defaultPureColor"
  459. :color-modes="['monochrome']"
  460. :show-primary-color-preview="false"
  461. v-model="data.shadowColor"
  462. @change="changeValue('shadowColor')"
  463. />
  464. </div>
  465. <label
  466. v-if="data.shadow"
  467. style="width: 50px; margin-left: 25px"
  468. >文字阴影
  469. </label>
  470. <div v-if="data.shadow" class="flex middle ml-8">
  471. <t-checkbox
  472. v-model="data.textHasShadow"
  473. @change="changeValue('textHasShadow')"
  474. style="width: 22px"
  475. />
  476. </div>
  477. </div>
  478. <div class="form-item" v-if="data.shadow">
  479. <label style="width: 28px"></label>
  480. <div class="flex" style="margin-top: -8px">
  481. <t-input
  482. class="ml-4"
  483. label="X"
  484. placeholder="0"
  485. v-model.number="data.shadowOffsetX"
  486. style="width: 60px"
  487. @change="changeValue('x')"
  488. title="X偏移"
  489. />
  490. <t-input
  491. class="ml-4"
  492. label="Y"
  493. placeholder="0"
  494. v-model.number="data.shadowOffsetY"
  495. style="width: 60px"
  496. @change="changeValue('shadowOffsetY')"
  497. title="Y偏移"
  498. />
  499. <t-input
  500. class="ml-4"
  501. label="模糊"
  502. placeholder="0"
  503. v-model.number="data.shadowBlur"
  504. style="width: 64px"
  505. @change="changeValue('shadowBlur')"
  506. title="模糊大小"
  507. />
  508. </div>
  509. </div>
  510. </t-space>
  511. </t-collapse-panel>
  512. <t-collapse-panel value="3" header="文字">
  513. <t-space direction="vertical" size="small" class="w-full">
  514. <div class="form-item">
  515. <div class="flex middle" style="margin-left: -10px">
  516. <t-select-input
  517. :value="data.fontFamily"
  518. :popup-visible="data.fontFamilyPopupVisible"
  519. placeholder="字体名"
  520. allow-input
  521. style="width: 170px"
  522. @change="changeValue('fontFamily')"
  523. @enter="changeValue('fontFamily')"
  524. @blur="changeValue('fontFamily')"
  525. @popup-visible-change="onFontPopupVisible"
  526. :popup-props="{
  527. overlayInnerStyle: { width: 'auto' },
  528. }"
  529. >
  530. <template #panel>
  531. <ul style="padding: 12px">
  532. <li
  533. v-for="item in fonts"
  534. :key="item"
  535. @click="onFontFamily(item)"
  536. >
  537. {{ item }}
  538. </li>
  539. </ul>
  540. </template>
  541. <template #suffixIcon>
  542. <chevron-down-icon />
  543. <!-- <t-icon name="chevron-down" /> -->
  544. </template>
  545. </t-select-input>
  546. <t-input
  547. class="ml-8"
  548. placeholder="字体大小"
  549. v-model.number="data.fontSize"
  550. style="width: 80px"
  551. :format="decimalRound"
  552. @change="changeValue('fontSize')"
  553. />
  554. </div>
  555. </div>
  556. <div class="flex middle">
  557. <t-radio-group
  558. size="small"
  559. v-model="data.textAlign"
  560. default-value="center"
  561. @change="changeValue('textAlign')"
  562. >
  563. <t-radio-button value="left">
  564. <t-tooltip content="居左" placement="top">
  565. <format-vertical-align-left-icon />
  566. <!-- <t-icon name="format-vertical-align-left" /> -->
  567. </t-tooltip>
  568. </t-radio-button>
  569. <t-radio-button value="center">
  570. <t-tooltip content="居中" placement="top">
  571. <format-vertical-align-center-icon />
  572. <!-- <t-icon name="format-vertical-align-center" /> -->
  573. </t-tooltip>
  574. </t-radio-button>
  575. <t-radio-button value="right">
  576. <t-tooltip content="居右" placement="top">
  577. <format-vertical-align-right-icon />
  578. <!-- <t-icon name="format-vertical-align-right" /> -->
  579. </t-tooltip>
  580. </t-radio-button>
  581. </t-radio-group>
  582. <t-radio-group
  583. class="ml-8"
  584. size="small"
  585. v-model="data.textBaseline"
  586. default-value="top"
  587. @change="changeValue('textBaseline')"
  588. >
  589. <t-radio-button value="top">
  590. <t-tooltip content="顶部对齐" placement="top">
  591. <format-horizontal-align-top-icon />
  592. <!-- <t-icon name="format-horizontal-align-top" /> -->
  593. </t-tooltip>
  594. </t-radio-button>
  595. <t-radio-button value="middle">
  596. <t-tooltip content="垂直居中" placement="middle">
  597. <format-horizontal-align-center-icon />
  598. <!-- <t-icon name="format-horizontal-align-center" /> -->
  599. </t-tooltip>
  600. </t-radio-button>
  601. <t-radio-button value="bottom">
  602. <t-tooltip content="底部对齐" placement="top">
  603. <format-horizontal-align-bottom-icon />
  604. <!-- <t-icon name="format-horizontal-align-bottom" /> -->
  605. </t-tooltip>
  606. </t-radio-button>
  607. </t-radio-group>
  608. <t-button
  609. :class="{ active: data.fontWeight === 'bold' }"
  610. class="ml-8 icon"
  611. shape="rectangle"
  612. variant="text"
  613. @click="
  614. data.fontWeight === 'bold'
  615. ? (data.fontWeight = 'normal')
  616. : (data.fontWeight = 'bold');
  617. changeValue('fontWeight');
  618. "
  619. >
  620. B
  621. </t-button>
  622. <t-button
  623. :class="{ active: data.fontStyle === 'italic' }"
  624. class="ml-4 icon"
  625. shape="rectangle"
  626. variant="text"
  627. @click="
  628. data.fontStyle === 'italic'
  629. ? (data.fontStyle = 'normal')
  630. : (data.fontStyle = 'italic');
  631. changeValue('fontStyle');
  632. "
  633. style="font-style: italic; font-family: serif"
  634. >I</t-button
  635. >
  636. </div>
  637. <div class="form-item">
  638. <t-color-picker
  639. class="simple mt-8 mr-4"
  640. format="CSS"
  641. :enable-alpha="true"
  642. :recentColors="null"
  643. :swatch-colors="defaultPureColor"
  644. :color-modes="['monochrome']"
  645. :show-primary-color-preview="false"
  646. v-model="data.textColor"
  647. @change="changeValue('textColor')"
  648. />
  649. <label style="width: 44px">前景</label>
  650. <t-color-picker
  651. class="simple mt-8 mr-4"
  652. :enable-alpha="true"
  653. :recent-colors="null"
  654. format="CSS"
  655. :swatch-colors="defaultPureColor"
  656. :color-modes="['monochrome']"
  657. :show-primary-color-preview="false"
  658. v-model="data.textBackground"
  659. @change="changeValue('textBackground')"
  660. />
  661. <label style="width: 44px">背景</label>
  662. <t-color-picker
  663. class="simple mt-8 mr-4"
  664. :enable-alpha="true"
  665. :recent-colors="null"
  666. format="CSS"
  667. :swatch-colors="defaultPureColor"
  668. :color-modes="['monochrome']"
  669. :show-primary-color-preview="false"
  670. v-model="data.hoverTextColor"
  671. @change="changeValue('hoverTextColor')"
  672. />
  673. <label style="width: 44px">悬停</label>
  674. <t-color-picker
  675. class="simple mt-8 mr-4"
  676. format="CSS"
  677. :enable-alpha="true"
  678. :recent-colors="null"
  679. :swatch-colors="defaultPureColor"
  680. :color-modes="['monochrome']"
  681. :show-primary-color-preview="false"
  682. v-model="data.activeTextColor"
  683. @change="changeValue('activeTextColor')"
  684. />
  685. <label style="width: 44px">选中</label>
  686. </div>
  687. <div class="form-item">
  688. <t-checkbox
  689. v-model="data.whiteSpace"
  690. @change="changeValue('whiteSpace')"
  691. style="width: 64px"
  692. >
  693. 换行
  694. </t-checkbox>
  695. <t-checkbox
  696. v-model="data.ellipsis"
  697. @change="changeValue('ellipsis')"
  698. style="width: 68px"
  699. >
  700. 省略号
  701. </t-checkbox>
  702. <t-tooltip content="行高">
  703. <t-input
  704. placeholder="行高"
  705. v-model.number="data.lineHeight"
  706. style="width: 40px"
  707. @change="changeValue('lineHeight')"
  708. />
  709. </t-tooltip>
  710. <t-tooltip content="显示时保留小数位数">
  711. <t-input
  712. class="ml-4"
  713. placeholder="小数"
  714. v-model.number="data.keepDecimal"
  715. style="width: 60px"
  716. @change="changeValue('keepDecimal')"
  717. />
  718. </t-tooltip>
  719. </div>
  720. <div class="form-item" style="margin-top: -4px">
  721. <t-tooltip content="水平偏移">
  722. <t-input
  723. placeholder="X"
  724. v-model.number="data.textLeft"
  725. style="width: 60px; margin-left: -8px"
  726. @change="changeValue('textLeft')"
  727. />
  728. </t-tooltip>
  729. <t-tooltip content="垂直偏移">
  730. <t-input
  731. class="ml-4"
  732. placeholder="Y"
  733. v-model.number="data.textTop"
  734. style="width: 60px"
  735. @change="changeValue('textTop')"
  736. />
  737. </t-tooltip>
  738. <t-tooltip content="宽">
  739. <t-input
  740. class="ml-4"
  741. placeholder="宽"
  742. v-model.number="data.textWidth"
  743. style="width: 60px"
  744. @change="changeValue('textWidth')"
  745. />
  746. </t-tooltip>
  747. <t-tooltip content="高">
  748. <t-input
  749. class="ml-4"
  750. placeholder="高"
  751. v-model.number="data.textHeight"
  752. style="width: 60px"
  753. @change="changeValue('textHeight')"
  754. />
  755. </t-tooltip>
  756. </div>
  757. <div class="flex middle">
  758. <t-checkbox
  759. v-model="data.disableInput"
  760. @change="changeValue('disableInput')"
  761. style="width: 64px"
  762. >
  763. 只读
  764. </t-checkbox>
  765. <t-checkbox
  766. v-model="data.hiddenText"
  767. @change="changeValue('hiddenText')"
  768. style="width: 90px"
  769. >
  770. 隐藏文字
  771. </t-checkbox>
  772. </div>
  773. </t-space>
  774. </t-collapse-panel>
  775. </t-collapse>
  776. </t-space>
  777. <t-divider style="margin-top: -8px" />
  778. <div class="form-item p-16">
  779. <t-checkbox
  780. v-model="data.flipX"
  781. @change="changeValue('flipX')"
  782. style="width: 90px"
  783. >
  784. 水平翻转
  785. </t-checkbox>
  786. <t-checkbox
  787. v-model="data.flipY"
  788. @change="changeValue('flipY')"
  789. style="width: 90px"
  790. >
  791. 垂直翻转
  792. </t-checkbox>
  793. <label style="width: 50px">锚点半径</label>
  794. <input
  795. class="ml-4"
  796. v-model.number="data.anchorRadius"
  797. style="width: 20px"
  798. @change="changeValue('anchorRadius')"
  799. placeholder="4"
  800. />
  801. </div>
  802. <t-divider />
  803. <div class="form-item p-16" style="margin-bottom: 20px">
  804. <t-checkbox
  805. v-model="data.disableRotate"
  806. @change="changeValue('disableRotate')"
  807. style="width: 90px"
  808. >
  809. 禁止旋转
  810. </t-checkbox>
  811. <t-checkbox
  812. v-model="data.disableSize"
  813. @change="changeValue('disableSize')"
  814. style="width: 90px"
  815. >
  816. 禁止缩放
  817. </t-checkbox>
  818. <t-checkbox
  819. v-model="data.disableAnchor"
  820. @change="changeValue('disableAnchor')"
  821. style="width: 90px"
  822. >
  823. 禁用锚点
  824. </t-checkbox>
  825. </div>
  826. </t-tab-panel>
  827. </t-tabs>
  828. </div>
  829. </template>
  830. <script lang="ts" setup>
  831. import { onBeforeMount, onUnmounted, reactive, ref, computed } from 'vue';
  832. import { LockState, Pen, isDomShapes } from '@meta2d/core';
  833. import { updatePen } from './pen';
  834. import { useSelection } from '@/services/selections';
  835. import { fonts, setChildrenVisible } from '@/services/common';
  836. import { defaultGradientColor, defaultPureColor } from '@/services/defaults';
  837. import { BrowseIcon, BrowseOffIcon, ChevronDownIcon, FormatVerticalAlignLeftIcon, FormatHorizontalAlignCenterIcon, FormatVerticalAlignCenterIcon, FormatVerticalAlignRightIcon, FormatHorizontalAlignTopIcon, FormatHorizontalAlignBottomIcon } from 'tdesign-icons-vue-next';
  838. const { selections } = useSelection();
  839. const data = reactive<any>({
  840. tab: 1,
  841. locked: 0,
  842. lineWidth: 1,
  843. });
  844. const aligns = [
  845. {
  846. value: 'left',
  847. label: '左对齐',
  848. icon: '#l-align-left',
  849. },
  850. {
  851. value: 'center',
  852. label: '垂直居中对齐',
  853. icon: '#l-align-center',
  854. },
  855. {
  856. value: 'right',
  857. label: '右对齐',
  858. icon: '#l-align-right',
  859. },
  860. {
  861. value: 'top',
  862. label: '顶部对齐',
  863. icon: '#l-align-top',
  864. },
  865. {
  866. value: 'middle',
  867. label: '水平居中对齐',
  868. icon: '#l-align-middle',
  869. },
  870. {
  871. value: 'bottom',
  872. label: '底部对齐',
  873. icon: '#l-align-bottom',
  874. },
  875. {
  876. value: 'h-distribute',
  877. label: '水平等距',
  878. icon: '#l-horizontal-between',
  879. },
  880. {
  881. value: 'v-distribute',
  882. label: '垂直等距',
  883. icon: '#l-vertical-between',
  884. },
  885. ];
  886. const aligns2 = [
  887. {
  888. value: 'left',
  889. label: '左对齐',
  890. icon: '#l-align-left',
  891. },
  892. {
  893. value: 'center',
  894. label: '垂直居中对齐',
  895. icon: '#l-align-center',
  896. },
  897. {
  898. value: 'right',
  899. label: '右对齐',
  900. icon: '#l-align-right',
  901. },
  902. {
  903. value: 'top',
  904. label: '顶部对齐',
  905. icon: '#l-align-top',
  906. },
  907. {
  908. value: 'middle',
  909. label: '水平居中对齐',
  910. icon: '#l-align-middle',
  911. },
  912. {
  913. value: 'bottom',
  914. label: '底部对齐',
  915. icon: '#l-align-bottom',
  916. },
  917. {
  918. value: 'same-size',
  919. label: '相同大小',
  920. icon: '#l-same-size',
  921. },
  922. ];
  923. onBeforeMount(() => {
  924. const d = meta2d.store.data as any;
  925. if (!d.groups) {
  926. d.groups = [];
  927. }
  928. data.groups = d.groups;
  929. if (!data.tags) {
  930. data.tags = [];
  931. }
  932. });
  933. const lock = (v: LockState) => {
  934. data.locked = v;
  935. for (const item of selections.pens) {
  936. meta2d.setValue({
  937. id: item.id,
  938. locked: v,
  939. });
  940. }
  941. };
  942. const visible = (v: boolean) => {
  943. data.visible = v;
  944. for (const item of selections.pens) {
  945. meta2d.setVisible(item as any, v);
  946. }
  947. };
  948. const align = (align: string) => {
  949. if (align === 'h-distribute') {
  950. meta2d.spaceBetween(meta2d.store.active);
  951. } else if (align === 'v-distribute') {
  952. meta2d.spaceBetweenColumn(meta2d.store.active);
  953. } else {
  954. meta2d.alignNodes(align, meta2d.store.active);
  955. }
  956. };
  957. const align2 = (align: string) => {
  958. if (align === 'same-size') {
  959. meta2d.beSameByLast(meta2d.store.active);
  960. } else {
  961. meta2d.alignNodesByLast(align, meta2d.store.active);
  962. }
  963. };
  964. const changeValue = (prop: string) => {
  965. for (const item of selections.pens) {
  966. data.id = item.id;
  967. updatePen(data, prop, false);
  968. }
  969. meta2d.render();
  970. };
  971. const onFontFamily = (fontFamily: string) => {
  972. data.fontFamily = fontFamily;
  973. data.fontFamilyPopupVisible = false;
  974. changeValue('fontFamily');
  975. };
  976. const onFontPopupVisible = (val: boolean) => {
  977. data.fontFamilyPopupVisible = val;
  978. };
  979. const decimalRound = (val: number) => {
  980. return Math.round(+val || 0);
  981. };
  982. const onSelectTag = (tag: string) => {
  983. data.tagPopupVisible = false;
  984. if (data.tags.includes(tag)) {
  985. return;
  986. }
  987. data.tags.push(tag);
  988. changeValue('tags');
  989. };
  990. const onChangeInputTag = (currentTags: any, context: any) => {
  991. const { trigger, index, item } = context;
  992. if (['tag-remove', 'backspace'].includes(trigger)) {
  993. data.tags.splice(index, 1);
  994. }
  995. if (trigger === 'enter') {
  996. onSelectTag(item);
  997. const d = meta2d.store.data as any;
  998. if (!d.groups.includes(item)) {
  999. d.groups.push(item);
  1000. data.groups = d.groups;
  1001. }
  1002. data.inputTag = '';
  1003. }
  1004. data.tagPopupVisible = false;
  1005. };
  1006. const hasDom = computed(() => {
  1007. return selections.pens.some((item: Pen) => {
  1008. return isDomShapes.includes(item.name) ||
  1009. item.name.endsWith('Dom') ||
  1010. meta2d.store.options.domShapes.includes(item.name);
  1011. });
  1012. });
  1013. const allImg = computed(() => {
  1014. return selections.pens.every((item: Pen) => {
  1015. return item.name === 'image';
  1016. });
  1017. });
  1018. </script>
  1019. <style lang="postcss" scoped>
  1020. .props {
  1021. .icons {
  1022. display: flex;
  1023. svg:hover {
  1024. cursor: pointer;
  1025. color: var(--color-primary);
  1026. }
  1027. .btn {
  1028. font-size: 16px;
  1029. margin-right: 16px;
  1030. color: var(--color);
  1031. }
  1032. }
  1033. }
  1034. </style>