frameToolBar.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. <template>
  2. <!-- 框架工具栏 -->
  3. <div class="frame-tool-bar-wrap">
  4. <div class="cell-style">
  5. <!-- 撤销 -->
  6. <ToolItem tooltip="撤销" toolkey="undo">
  7. <div class="tool-item" @click="handleGraphHistory('undo')">
  8. <img :src="require(`@/assets/icons/chartFrame/undo.svg`)"
  9. :class="{'img-disabled':!canUndo,'actived':canUndo}">
  10. <span class="disabled" v-if="!canUndo"></span>
  11. </div>
  12. </ToolItem>
  13. <!-- 恢复 -->
  14. <ToolItem tooltip="恢复" toolkey="undo">
  15. <div class="tool-item" @click="handleGraphHistory('redo')">
  16. <img :src="require(`@/assets/icons/chartFrame/redo.svg`)"
  17. :class="{'img-disabled':!canRedo,'actived':canRedo}">
  18. <span class="disabled" v-if="!canRedo"></span>
  19. </div>
  20. </ToolItem>
  21. <!-- 字体 暂定-->
  22. <!-- 字号 -->
  23. <ToolItem tooltip="字号" toolkey="fontSize">
  24. <el-dropdown @command="changeStyle" trigger="click" class="tool-item">
  25. <span class="el-dropdown-link tool-item">
  26. <span>{{nodeStyle.fontSize}}px</span>
  27. <i class="el-icon-caret-bottom"></i>
  28. </span>
  29. <el-dropdown-menu slot="dropdown">
  30. <el-dropdown-item v-for="item in sizeOptions"
  31. :key="item" :command="{attr:'label/fontSize',value:item}">{{item}}</el-dropdown-item>
  32. </el-dropdown-menu>
  33. <span class="disabled" v-if="!isSelectNode"></span>
  34. </el-dropdown>
  35. </ToolItem>
  36. <!-- 加粗 -->
  37. <ToolItem tooltip="加粗" toolkey="fontWeight">
  38. <span class="tool-item">
  39. <span class="item-text" :class="{'text-disabled':!isSelectNode,'text-actived':isSelectNode}"
  40. :style="'font-size: 16px;font-weight: bold;'"
  41. @click="changeStyleToggle('label/fontWeight')">B</span>
  42. <span class="disabled" v-if="!isSelectNode"></span>
  43. </span>
  44. </ToolItem>
  45. <!-- 斜体 -->
  46. <ToolItem tooltip="斜体" toolkey="fontstyle">
  47. <span class="tool-item">
  48. <span style="font-style: italic;" class="item-text"
  49. @click="changeStyleToggle('label/fontStyle')">
  50. <img :src="require(`@/assets/icons/chartFrame/fontStyle.svg`)"
  51. :class="{'img-disabled':!isSelectNode,'actived':isSelectNode}">
  52. </span>
  53. <span class="disabled" v-if="!isSelectNode"></span>
  54. </span>
  55. </ToolItem>
  56. <!-- 下划线 -->
  57. <ToolItem tooltip="下划线" toolkey="textDecoration">
  58. <span class="tool-item">
  59. <span style="text-decoration: underline;" class="item-text"
  60. @click="changeStyleToggle('label/textDecoration')">
  61. <img :src="require(`@/assets/icons/chartFrame/fontText.svg`)"
  62. :class="{'img-disabled':!isSelectNode,'actived':isSelectNode}">
  63. </span>
  64. <span class="disabled" v-if="!isSelectNode"></span>
  65. </span>
  66. </ToolItem>
  67. <!-- 字体颜色 -->
  68. <ToolItem tooltip="字体颜色" toolkey="textDecoration">
  69. <span class="tool-item">
  70. <label for="label/fill" :style="`color:${color}`">
  71. <img :src="require(`@/assets/icons/chartFrame/fontColor.svg`)"
  72. :class="{'img-disabled':!isSelectNode,'actived':isSelectNode}">
  73. </label>
  74. <input type="color" id="label/fill" style="width: 0;height: 0;visibility: hidden;"
  75. :value="nodeStyle.color"
  76. @input="valueChange"/>
  77. <span class="disabled" v-if="!isSelectNode"></span>
  78. </span>
  79. </ToolItem>
  80. <!-- 文本行高 暂定-->
  81. <!-- 文本对齐 -->
  82. <ToolItem tooltip="文本对齐" toolkey="textAligh">
  83. <el-dropdown @command="changeTextStyle" trigger="click" class="tool-item">
  84. <span class="el-dropdown-link tool-item">
  85. <img :src="require(`@/assets/icons/chartFrame/textAlign.svg`)"
  86. :class="{'img-disabled':!isSelectNode,'actived':isSelectNode}">
  87. <i class="el-icon-caret-bottom"></i>
  88. </span>
  89. <el-dropdown-menu slot="dropdown">
  90. <el-dropdown-item v-for="item in textAnchorOptions"
  91. :key="item.label" :command="{attr:'label/textAligh',value:item.options}">{{item.label}}</el-dropdown-item>
  92. </el-dropdown-menu>
  93. <span class="disabled" v-if="!isSelectNode"></span>
  94. </el-dropdown>
  95. </ToolItem>
  96. <!-- 节点颜色填充 -->
  97. <ToolItem tooltip="填充颜色" toolkey="fillColor">
  98. <span class="tool-item">
  99. <label for="body/fill" :style="`color:${fillColor}`">
  100. <img :src="require(`@/assets/icons/chartFrame/fillColor.svg`)"
  101. :class="{'img-disabled':!isSelectNode,'actived':isSelectNode}">
  102. </label>
  103. <input type="color" id="body/fill" style="width: 0;height: 0;visibility: hidden;"
  104. :value="nodeStyle.fill"
  105. @input="valueChange"/>
  106. <span class="disabled" v-if="!isSelectNode"></span>
  107. </span>
  108. </ToolItem>
  109. <!-- 节点/线条边框颜色 -->
  110. <ToolItem tooltip="边框颜色" toolkey="borderColor">
  111. <span class="tool-item">
  112. <label for="storke" :style="`color:${borderColor}`">
  113. <img :src="require(`@/assets/icons/chartFrame/stokeColor.svg`)"
  114. :class="{'img-disabled':!isSelectNode&&!isSelectEdge,'actived':isSelectNode||isSelectEdge}">
  115. </label>
  116. <input type="color" id="storke" style="width: 0;height: 0;visibility: hidden;"
  117. :value="nodeStyle.stroke"
  118. @input="valueChange"/>
  119. <span class="disabled" v-if="!isSelectNode&&!isSelectEdge"></span>
  120. </span>
  121. </ToolItem>
  122. <!-- 节点/线条边框宽度 -->
  123. <ToolItem tooltip="线框宽度" toolkey="stokeWidth">
  124. <el-dropdown @command="changeCellStyle" trigger="click" class="tool-item">
  125. <span class="el-dropdown-link tool-item">
  126. <i class="el-icon-minus"></i>
  127. <i class="el-icon-caret-bottom"></i>
  128. </span>
  129. <el-dropdown-menu slot="dropdown">
  130. <el-dropdown-item v-for="item in stokeWidthOptions"
  131. :key="item" :command="{attr:'width',value:item}">{{item}}</el-dropdown-item>
  132. </el-dropdown-menu>
  133. <span class="disabled" v-if="!isSelectNode&&!isSelectEdge"></span>
  134. </el-dropdown>
  135. </ToolItem>
  136. <!-- 节点/线条边框样式 -->
  137. <ToolItem tooltip="边框样式" toolkey="stokeWidth">
  138. <el-dropdown @command="changeCellStyle" trigger="click" class="tool-item">
  139. <span class="el-dropdown-link tool-item">
  140. <img :src="require(`@/assets/icons/chartFrame/stokeStyle.svg`)"
  141. :class="{'img-disabled':!isSelectNode&&!isSelectEdge,'actived':isSelectNode||isSelectEdge}">
  142. <i class="el-icon-caret-bottom"></i>
  143. </span>
  144. <el-dropdown-menu slot="dropdown">
  145. <el-dropdown-item :command="{attr:'dash',value:5}">
  146. <i class="iconfont icon--xuxian" style="color:'#000';fontSize:30px"></i>
  147. </el-dropdown-item>
  148. <el-dropdown-item :command="{attr:'dash',value:0}">
  149. <i class="iconfont icon--shixian" style="color:'#000';fontSize:30px"></i>
  150. </el-dropdown-item>
  151. </el-dropdown-menu>
  152. <span class="disabled" v-if="!isSelectNode&&!isSelectEdge"></span>
  153. </el-dropdown>
  154. </ToolItem>
  155. <!-- 开始箭头 -->
  156. <ToolItem tooltip="开始箭头" toolkey="stokeWidth">
  157. <el-dropdown trigger="click" @command="changeStyle" class="tool-item">
  158. <div class="el-dropdown-link">
  159. <img :src="require(`@/assets/icons/chartFrame/arrow-left.svg`)"
  160. :class="{'img-disabled':!isSelectEdge,'actived':isSelectEdge}">
  161. <i class="el-icon-caret-bottom"></i>
  162. </div>
  163. <el-dropdown-menu slot="dropdown">
  164. <el-dropdown-item :command="{attr:'line/sourceMarker',value: 'classic'}">
  165. <i class="iconfont icon-arrow-left" style="color:'#000';fontSize:24px"></i>
  166. </el-dropdown-item>
  167. <el-dropdown-item :command="{attr:'line/sourceMarker',value: ''}">
  168. <i class="iconfont icon--shixian" style="color:'#000';fontSize:32px"></i>
  169. </el-dropdown-item>
  170. </el-dropdown-menu>
  171. <span class="disabled" v-if="!isSelectEdge"></span>
  172. </el-dropdown>
  173. </ToolItem>
  174. <!-- 结束箭头 -->
  175. <ToolItem tooltip="结束箭头" toolkey="stokeWidth">
  176. <el-dropdown trigger="click" @command="changeStyle" class="tool-item">
  177. <div class="el-dropdown-link">
  178. <img :src="require(`@/assets/icons/chartFrame/arrow-right.svg`)"
  179. :class="{'img-disabled':!isSelectEdge,'actived':isSelectEdge}">
  180. <i class="el-icon-caret-bottom"></i>
  181. </div>
  182. <el-dropdown-menu slot="dropdown">
  183. <el-dropdown-item :command="{attr:'line/targetMarker',value: 'classic'}">
  184. <i class="iconfont icon-arrow-right" style="color:'#000';fontSize:24px"></i>
  185. </el-dropdown-item>
  186. <el-dropdown-item :command="{attr:'line/targetMarker',value: ''}">
  187. <i class="iconfont icon--shixian" style="color:'#000';fontSize:32px"></i>
  188. </el-dropdown-item>
  189. </el-dropdown-menu>
  190. <span class="disabled" v-if="!isSelectNode&&!isSelectEdge"></span>
  191. </el-dropdown>
  192. </ToolItem>
  193. </div>
  194. </div>
  195. </template>
  196. <script>
  197. import '@/assets/icons/iconfont.css';
  198. import ToolItem from './toolItem.vue';
  199. import {sizeOptions,stokeWidthOptions,lineHeightOptions,textAnchorOptions} from '../common/config';
  200. export default {
  201. components: { ToolItem },
  202. props:{
  203. isSelectNode:{//当前选中的元素是否是节点
  204. type:Boolean,
  205. default:false
  206. },
  207. isSelectEdge:{//当前选中的元素是否是边
  208. type:Boolean,
  209. default:false
  210. },
  211. currentCell:{//当前传入的元素,Node/Edge
  212. type:Object,
  213. },
  214. graph:{ //当前画布
  215. type:Object,
  216. },
  217. canRedo:{
  218. type:Boolean
  219. },
  220. canUndo:{
  221. type:Boolean
  222. }
  223. },
  224. data() {
  225. this.sizeOptions=sizeOptions
  226. this.stokeWidthOptions=stokeWidthOptions
  227. this.textAnchorOptions=textAnchorOptions
  228. return {
  229. nodeStyle:{ //回显用的
  230. fontSize:14,
  231. fill:'#333',
  232. color:'#333',
  233. },
  234. cellStyle:{
  235. stroke:'#333',
  236. },
  237. color:'#333',
  238. fillColor:'#333',
  239. borderColor:'#333',
  240. };
  241. },
  242. watch:{
  243. isSelectNode(newVal){
  244. if(!newVal){
  245. //重置 node相关样式
  246. this.nodeStyle = {
  247. fontSize:14,
  248. fill:'#333',
  249. color:'#333',
  250. stroke:'#333'
  251. }
  252. }
  253. },
  254. currentCell(newVal){
  255. if(newVal){
  256. if(newVal.isNode&&newVal.isNode()){
  257. this.nodeStyle = {
  258. fontSize:newVal.attrs.label.fontSize,
  259. fill:newVal.attrs.body.fill,
  260. color:newVal.attrs.label.fill,
  261. stroke:newVal.attrs.body.stroke,
  262. }
  263. this.cellStyle = {
  264. store:newVal.attrs.body.stroke,
  265. }
  266. }
  267. if(newVal.isEdge&&newVal.isEdge()){
  268. this.cellStyle = {
  269. store:newVal.attrs.line.stroke
  270. }
  271. }
  272. }
  273. },
  274. },
  275. methods: {
  276. //加粗,斜体,下划线样式
  277. changeStyleToggle(attr){
  278. const value = this.currentCell.attr(attr)
  279. const valueMap = {
  280. 'label/fontWeight':['normal','bold'],
  281. 'label/fontStyle':['normal','italic'],
  282. 'label/textDecoration':['normal','underline'],
  283. }
  284. this.changeStyle({attr,
  285. value:value===valueMap[attr][0]
  286. ?valueMap[attr][1]
  287. :valueMap[attr][0]})
  288. },
  289. changeStyle({attr,value}){
  290. this.currentCell.attr(attr,value)
  291. if(attr==='label/fontSize'){
  292. this.nodeStyle.fontSize = value
  293. }
  294. },
  295. //边框和线条通用样式:线条颜色,宽度,虚线
  296. valueChange(e){
  297. //t.target.value: "#9c3535"
  298. if(e.target){
  299. const styleMap = {
  300. 'storke':['body/stroke','line/stroke'],
  301. 'width':['body/strokeWidth','line/strokeWidth'],
  302. 'dash':['body/strokeDasharray','line/strokeDasharray']
  303. }
  304. const {id,value} = e.target
  305. let attr = id
  306. if(styleMap[id]){
  307. attr = this.isSelectNode?styleMap[id][0]:styleMap[id][1]
  308. }
  309. this.currentCell.attr(attr,value)
  310. //改变节点字体颜色时,角标的颜色也一起改变
  311. if(attr==='label/fill'){
  312. let tool = this.currentCell.getTools().items[0]
  313. tool.args.markup[0].attrs.fill = value
  314. this.currentCell.removeTools()
  315. this.currentCell.addTools(tool)
  316. }
  317. }
  318. },
  319. changeCellStyle({attr,value}){
  320. this.valueChange({target:{id:attr,value}})
  321. },
  322. changeTextStyle({attr,value}){
  323. for(const key in value){
  324. this.currentCell.attr('label/'+key,value[key])
  325. }
  326. },
  327. //撤销/恢复
  328. handleGraphHistory(type){
  329. this.graph.history[type]()
  330. }
  331. },
  332. mounted(){
  333. },
  334. };
  335. </script>
  336. <style lang="scss">
  337. .frame-tool-bar-wrap{
  338. .tool-item{
  339. .el-input{
  340. .el-input__inner {
  341. padding:0;
  342. height:100%;
  343. }
  344. }
  345. }
  346. .el-button{
  347. padding:0;
  348. }
  349. }
  350. </style>
  351. <style scoped lang="scss">
  352. .frame-tool-bar-wrap{
  353. background-color:#F6F7F8;
  354. padding: 5px;
  355. position: absolute;
  356. height: 26px;
  357. left: 0;
  358. right:0;
  359. top:0;
  360. z-index: 100;
  361. box-sizing: border-box;
  362. .cell-style{
  363. display: flex;
  364. gap:0 20px;
  365. overflow:hidden;
  366. align-items:center;
  367. .tool-item{
  368. cursor: pointer;
  369. position: relative;
  370. .img-disabled{
  371. transform:translateY(50px);
  372. filter:drop-shadow(#C8CDD9 0px -50px 0px);
  373. }
  374. .actived{
  375. transform:translateY(50px);
  376. filter:drop-shadow(#333 0px -50px 0px);
  377. }
  378. .item-text{
  379. padding:0 2px;
  380. &.text-disabled{
  381. color:#C8CDD9;
  382. }
  383. &.text-actived{
  384. color:#333;
  385. }
  386. }
  387. .disabled {
  388. color: #bbb;
  389. /* background: rgba(0, 0, 0, 0.08); */
  390. background-color: transparent;
  391. cursor: not-allowed;
  392. position: absolute;
  393. top: 0;
  394. right: 0;
  395. left: 0;
  396. bottom: 0;
  397. z-index: 1;
  398. }
  399. }
  400. }
  401. }
  402. </style>