vue手写多对多关联图,连线用leader-line

效果如图

 鼠标滑动效果

关联性效果

 

 

<template ><div class="main" ref="predecessor"><div class="search"><div class="search-item"><div class="search-item-label">部门</div><Treeselect v-model="dept":options="deptOptions"show-countplaceholder="请选择部门"@change="changeDept()"/><!-- <el-cascader v-model="dept" clearable placeholder="请选择部门" ><el-option v-for="item in deptOptions" :key="item.id" :label="item.label" :value="item.id"></el-option></el-cascader> --></div><div class="search-item"><div class="search-item-label">周期</div><el-cascader v-model="TypeSelectValue" :options="cycleTypeSelect" :props="{checkStrictly: true,expandTrigger: 'hover'}" @change="handleChange" /></div></div><div class="main-predecessor"><div v-for="(item, index) in predecessorList" :key="'father' + index" class="father-predecessor"><div v-for="(itm, idx) in item" :key="itm.id"><div v-if="itm.status === 0 && itm.display === true" :id="itm.id" class="children-predecessor-big"@mouseenter="enter(index, idx)" @mouseleave="leave()":style="changeCardList.indexOf(itm.id) === -1 ? '' : 'background:rgba(206, 210, 232, 0.87)'"@click="clickDownsize(index, idx)"><div class="caption">{{ itm.okrUserOrDept }}</div><Vptip :content="itm.okrOContent" :width="'100%'" style="max-width: 500px;margin-bottom: 10px;"><span class="O-list" :style="changeOList.indexOf(itm.id) === -1 ? '' : 'color:#8198fe;font-weight: 700;'">O:{{`${itm.okrOContent}` }}</span></Vptip><div v-for="(im, indx) in itm.okrKrConfigList"><Vptip :content="im.okrKrContent" :width="'100%'" style="max-width: 500px;"><span class="kr-list":style="changeKrList.indexOf(im.id) === -1 ? '' : 'color:#8198fe;font-weight: 700;'">KR{{ indx + 1 }}: {{ `${im.okrKrContent}` }}</span></Vptip></div><div class="button"><el-button type="text" class="open" v-if="itm.isHeader && !itm.buttonDisplay" :disabled="timeout !== 0"@click.stop="commencementAll(index, itm.id, idx)" icon="el-icon-caret-bottom" /><el-button type="text" class="open" v-if="itm.isHeader && itm.buttonDisplay" :disabled="timeout !== 0"@click.stop="implicitAll(index, itm.id, idx)" icon="el-icon-caret-top" /></div></div><div v-if="itm.status === 1 && itm.display === true" :id="itm.id" class="children-predecessor-middle"@mouseenter="enter(index, idx)" @mouseleave="leave()":style="changeCardList.indexOf(itm.id) === -1 ? '' : 'background:rgba(206, 210, 232, 0.87)'"@click="clickDownsize(index, idx)"><div class="caption">{{ itm.okrUserOrDept }}</div><Vptip :content="itm.okrOContent" :width="'100%'" style="max-width: 500px;"><span class="O-list" :style="changeOList.indexOf(itm.id) === -1 ? '' : 'color:#8198fe;font-weight: 700;'">O:{{`${itm.okrOContent}` }}</span></Vptip><div class="button"><el-button type="text" class="open" v-if="itm.isHeader && !itm.buttonDisplay" :disabled="timeout !== 0"@click.stop="commencementAll(index, itm.id, idx)" icon="el-icon-caret-bottom" /><el-button type="text" class="open" v-if="itm.isHeader && itm.buttonDisplay" :disabled="timeout !== 0"@click.stop="implicitAll(index, itm.id, idx)" icon="el-icon-caret-top" /></div></div><div v-if="itm.status === 2 && itm.display === true" :id="itm.id" class="children-predecessor-small"@mouseenter="enter(index, idx)" @mouseleave="leave()":style="changeCardList.indexOf(itm.id) === -1 ? '' : 'background:rgba(206, 210, 232, 0.87)'"@click="clickDownsize(index, idx)"><div class="caption">{{ itm.okrUserOrDept }}</div><div class="button"><el-button type="text" class="open" v-if="itm.isHeader && !itm.buttonDisplay" :disabled="timeout !== 0"@click.stop="commencementAll(index, itm.id, idx)" icon="el-icon-caret-bottom" /><el-button type="text" class="open" v-if="itm.isHeader && itm.buttonDisplay" :disabled="timeout !== 0"@click.stop="implicitAll(index, itm.id, idx)" icon="el-icon-caret-top" /></div></div></div></div></div></div>
</template><script >
import { deptTreeSelect } from '@/api/system/user'
import okrConstant from '@/utils/okr/okrConstant'
import { getOkrPredecessor } from '@/api/okr/okrPredecessor'
import LeaderLine from 'leader-line'
import Vptip from "@/components/vptip" // 自定义Tooltip 文字提示
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
export default {name: 'okrPredecessor',components: {Vptip,Treeselect},data() {return {// 级联选择器下拉框selectOKrForm: {// 年份搜索值okrCycleYear: okrConstant.yearDecade()[0].value,// 季度搜索值okrCycleQuarter: okrConstant.currentMonthIsQuarter(),// 月份搜索值okrCycleMonth: '',},TypeSelectValue: okrConstant.currentMonthIsQuarter(),cycleTypeSelect: okrConstant.yearDecade(),// 部门列表deptOptions: [],// 部门数据dept: undefined,// 控制按钮的倒计时timeout: 0,// 线条的数组lineList: {},// 接口返回的循环数据predecessorListAll: [],// 继承的渲染数据predecessorList: [// [//   {//     id: 0,//     // 展开还是缩小状态//     status: 0,//     // 能否展开或者缩小下一级//     isHeader: true,//     // 目前在显示还是隐藏//     display: true,//     // 当前按钮是展开还是隐藏//     buttonDisplay: true,//     // 父级相关的id合集//     fatherUserId: []//   }// ]],// 所有的线条allLineList: [],// 应该画出来的线drawLineList: [],// 隐藏的数组listdisplayList: [],// 变色的卡片IDchangeCardList: [],// 变色的KRIDchangeKrList: [],// 变色的OIDchangeOList: [],// 变色的线段changeDrawLineList: []}},watch:{dept(){this.search()}},// 注册监听mounted() {// 获取部门列表this.getDept()window.addEventListener('resize', this.getScroll)// 监听div滚动事件let scrollView = this.$refs.predecessorscrollView.addEventListener("scroll", this.positionLine);document.body.style.overflow = 'hidden'this.search()},// 销毁前beforeDestroy() {document.body.style.overflow = ''// 销毁线条this.removeLines()},// 销毁监听,防止内存泄露destroyed() {window.removeEventListener('resize', this.getScroll)},methods: {// 获取部门列表getDept() {deptTreeSelect().then(response => {this.deptOptions = response.data[0].children})},// 鼠标移出事件(将O和KR两个数组归0)leave() {// 变色的KRIDthis.changeKrList = []// 变色的OIDthis.changeOList = []// 变色的卡片IDthis.changeCardList = []// 线段颜色恢复this.resumption()// 特殊线段归0this.changeDrawLineList = []},// 鼠标移入事件enter(index, idx) {// 变色的KRIDthis.changeKrList = []// 变色的OIDthis.changeOList = []// 变色的卡片IDthis.changeCardList = []// 获取到第一层DIV之后首先对上下紧挨的关系层进行循环// 寻找相关的父级this.findFatherList(index, idx)// 寻找相关的子集this.findChildrenList(index, idx)// 先将他本身的数据push进去if (this.predecessorList[index][idx].okrKrConfigList) {for (let i = 0; i < this.predecessorList[index][idx].okrKrConfigList.length; i++) {this.changeKrList.push(this.predecessorList[index][idx].okrKrConfigList[i].id)}}this.changeOList.push(this.predecessorList[index][idx].id)this.changeCardList.push(this.predecessorList[index][idx].id)// 获取线段变化线段this.getChangeLine()// 更改相关线段this.changeLineColor()},// 获取相关需要更改线段getChangeLine() {this.changeDrawLineList = []// 判断开头结尾都在变色的卡片之中for (let j = 0; j < this.drawLineList.length; j++) {if (this.changeCardList.indexOf(Number(this.drawLineList[j].start)) !== -1 && this.changeCardList.indexOf(Number(this.drawLineList[j].end)) !== -1) {this.changeDrawLineList.push(this.drawLineList[j])}}},// 恢复相关线段颜色resumption() {for (let i = 0; i < this.changeDrawLineList.length; i++) {this.twiceGetLine(this.changeDrawLineList[i].start, this.changeDrawLineList[i].end, i)}},// 更改相关线段颜色changeLineColor() {for (let i = 0; i < this.changeDrawLineList.length; i++) {this.changeGetLine(this.changeDrawLineList[i].start, this.changeDrawLineList[i].end, i)}},// 寻找相关的子集findChildrenList(index, idx) {// 对所有的线段进行遍历(因为只有O能够继承,所以子集直接往下找,只要有就是要变色)for (let i = 0; i < this.drawLineList.length; i++) {// 寻找到以此为开头的数据if (this.drawLineList[i].start === String(this.predecessorList[index][idx].id)) {// 对页面数据进行遍历寻找出此ID的位置,为后续获取KR做准备for (let x = 0; x < this.predecessorList.length; x++) {if (this.predecessorList[x]) {for (let y = 0; y < this.predecessorList[x].length; y++) {// 寻找到线段结束点位的内容if (String(this.predecessorList[x][y].id) === this.drawLineList[i].end) {// 变色的OIDthis.changeOList.push(this.predecessorList[x][y].id)// 变色的卡片IDthis.changeCardList.push(this.predecessorList[x][y].id)//  对KRLIST进行遍历,渲染KRLISTfor (let z = 0; z < this.predecessorList[x][y].okrKrConfigList.length; z++) {// 将所有相关kr进行pushthis.changeKrList.push(this.predecessorList[x][y].okrKrConfigList[z].id)}// 删除递归根节点功能// this.findChildrenList(x, y)}}}}}}},// 寻找相关的父级findFatherList(index, idx) {let fatherList = this.predecessorList[index][idx].extendsKrs// 对FATHERlIST进行遍历for (let i = 0; i < fatherList.length; i++) {// 只要是存在的Oid卡片就跟随变色(需要两点之间还存在连线关系)for (let j = 0; j < this.drawLineList.length; j++) {if (this.drawLineList[j].start === String(fatherList[i].okrId) && this.drawLineList[j].end === String(this.predecessorList[index][idx].id)) {this.changeCardList.push(fatherList[i].okrId)// 如果继承的是KR(O不变色,但是KR需要变色)if (fatherList[i].krId !== null) {this.changeKrList.push(fatherList[i].krId)} else {// 如果继承的是O,那么OKR全部变色,并且继续寻找上一层的OKR// 将变色Opush进入O的数组this.changeOList.push(fatherList[i].okrId)// 将变色O所对应的KR全部push进入数组(遍历寻找对应O)for (let x = 0; x < this.predecessorList.length; x++) {if (this.predecessorList[x]) {for (let y = 0; y < this.predecessorList[x].length; y++) {// 找出对应的IDif (fatherList[i].okrId === this.predecessorList[x][y].id) {// 对ID中的OKR进行循环pushfor (let z = 0; z < this.predecessorList[x][y].okrKrConfigList.length; z++) {// 将所有相关kr进行pushthis.changeKrList.push(this.predecessorList[x][y].okrKrConfigList[z].id)}// 寻找完O之后,将后生成的O继续进行上层寻找循环// 删除递归根节点功能// this.findFatherList(x, y)}}}}}}}}},// 级联改变方法handleChange(value) {this.selectOKrForm.okrCycleYear = ''this.selectOKrForm.okrCycleQuarter = ''this.selectOKrForm.okrCycleMonth = ''value.forEach((element, index) => {switch (index) {case 0: this.selectOKrForm.okrCycleYear = element; breakcase 1: this.selectOKrForm.okrCycleQuarter = element; breakcase 2: this.selectOKrForm.okrCycleMonth = element; break}})this.search()},// 搜索search() {let params = {okrUserDept: this.dept,okrCycleYear: this.selectOKrForm.okrCycleYear,okrCycleQuarter: this.selectOKrForm.okrCycleQuarter,okrCycleMonth: this.selectOKrForm.okrCycleMonth}// 跑接口之前销毁所有线条this.removeLines()// 获取继承关系详细数据getOkrPredecessor(params).then(res => {// 所有的线条this.allLineList = []// 应该画出来的线this.drawLineList = []// 页面渲染数据this.predecessorList = []this.predecessorListAll = res.data// 递归逻辑for (let i = 0; i < this.predecessorListAll.length; i++) {for (let j = 0; j < this.predecessorListAll[i].inheritedToOkrId.length; j++) {let level = this.predecessorListAll[i].levellet fatherUserId = []// 获取fatherListfor (let x = 0; x < this.predecessorListAll[i].inheritedToOkrId[j].extendsKrs.length; x++) {if (fatherUserId.indexOf(this.predecessorListAll[i].inheritedToOkrId[j].extendsKrs[x].okrId) === -1) {fatherUserId.push(this.predecessorListAll[i].inheritedToOkrId[j].extendsKrs[x].okrId)}}// 如果此层级还不存在先重置层级if (!this.predecessorList[level]) {this.predecessorList[level] = []}this.predecessorList[level].push(this.predecessorListAll[i].inheritedToOkrId[j])this.predecessorList[level][this.predecessorList[level].length - 1].fatherUserId = fatherUserIdthis.predecessorList[level][this.predecessorList[level].length - 1].status = 2this.predecessorList[level][this.predecessorList[level].length - 1].isHeader = falsethis.predecessorList[level][this.predecessorList[level].length - 1].display = truethis.predecessorList[level][this.predecessorList[level].length - 1].buttonDisplay = true}}// 寻找父子关系的连线this.findLineList()// 更改header属性判断是否可以当标头this.whetherIsHeader()// 刷新数组变化导致的数据更改this.$forceUpdate()// 画线(页面加载有一个动画,需要等动画完毕再开始加载线条保证线条的稳定性)setTimeout(() => { this.drawLine() }, 500)})},// 判断是否可以当标头,是否含有展开收起属性whetherIsHeader() {// 对二维数组进行遍历for (let x = 0; x < this.predecessorList.length; x++) {// 判断此层级中是否有内容if (this.predecessorList[x]) {for (let y = 0; y < this.predecessorList[x].length; y++) {// 对当前所有连线进行遍历for (let i = 0; i < this.allLineList.length; i++) {// 如果存在以此ID为开头的线段,证明为header,isHeader属性为trueif (String(this.predecessorList[x][y].id) === this.allLineList[i].start) {this.predecessorList[x][y].isHeader = true}}}}}},// 寻找父子关系的连线findLineList() {// 对二维数组进行循环for (let i = 0; i < this.predecessorList.length; i++) {if (this.predecessorList[i]) {for (let j = 0; j < this.predecessorList[i].length; j++) {// 对父级进行循环if (this.predecessorList[i][j].fatherUserId) {for (let x = 0; x < this.predecessorList[i][j].fatherUserId.length; x++) {if (this.existent(this.predecessorList[i][j].fatherUserId[x], this.predecessorList[i][j].id)) {this.allLineList.push({start: String(this.predecessorList[i][j].fatherUserId[x]),end: String(this.predecessorList[i][j].id)})}}}}}}// 将数据同步到渲染的线段中,默认全部显示this.drawLineList = JSON.parse(JSON.stringify(this.allLineList))},// 验证是否存在该条数据existent(start, end) {// 对二维数组进行遍历for (let i = 0; i < this.predecessorList.length; i++) {if (this.predecessorList[i]) {for (let j = 0; j < this.predecessorList[i].length; j++) {if (this.predecessorList[i][j].id === start) {// 如果开始符合,看结束是否存在for (let x = 0; x < this.predecessorList.length; x++) {if (this.predecessorList[x]) {for (let y = 0; y < this.predecessorList[x].length; y++) {if (this.predecessorList[x][y].id === end) {return true}}}}}}}}return false},// 点击展开// 准备开始展开递归将所有关联的数据进行处理commencementAll(index, id, idx) {this.timeout = 1// 防抖setTimeout(() => {this.timeout = 0}, 500)// 更改按钮let changeIndexfor (let i = 0; i < this.predecessorList[index].length; i++) {if (this.predecessorList[index][i].id === id) {changeIndex = i}}// 更改按钮状态this.predecessorList[index][changeIndex].buttonDisplay = true// 目前已经确认隐藏的id标题// 把跟原标题有关的数据全都找出来再进行删除let oldIdList = this.displayList//  所有可以改回状态的IDlet deleteIdList = [id]// 新的ID集合let newIdList = []// 进行遍历寻找不需要删除的数组for (let i = index; i < this.predecessorList.length; i++) {if (this.predecessorList[i]) {for (let j = 0; j < this.predecessorList[i].length; j++) {if (this.arbitrarily(deleteIdList, this.predecessorList[i][j].fatherUserId)) {deleteIdList.push(this.predecessorList[i][j].id)}}}}//  生成新数组for (let i = 0; i < oldIdList.length; i++) {let haveId = truefor (let j = 0; j < deleteIdList.length; j++) {if (deleteIdList[j] === oldIdList[i]) {haveId = false}}if (haveId) {newIdList.push(oldIdList[i])}}// 当前禁止当头的数据 this.displayListthis.displayList = [...newIdList]// 更改页面this.commencement(index, id)// 更改页面显示this.enter(index, idx)},// 点击收起implicitAll(index, id, idx) {this.timeout = 1// 防抖setTimeout(() => {this.timeout = 0}, 1000)// 更改按钮let changeIndexfor (let i = 0; i < this.predecessorList[index].length; i++) {if (this.predecessorList[index][i].id === id) {changeIndex = i}}// 更改按钮状态this.predecessorList[index][changeIndex].buttonDisplay = false// 寻找子集this.findImplicit(index, id)// 更改页面this.implicit(index, id)// 更改页面显示this.enter(index, idx)},// 展开隐藏后续内容commencement(index, id) {// 操作线条// 销毁线条this.removeLines()// 线条数组清零let newDrawLineList = []// 对目前所有线条进行循环for (let i = 0; i < this.allLineList.length; i++) {let remain = falsefor (let j = 0; j < this.displayList.length; j++) {if (this.allLineList[i].start === String(this.displayList[j])) {remain = true}}if (remain === false) {newDrawLineList.push(this.allLineList[i])}}// 操作卡片// 寻找各个子集,并且观察子集是不是只有这一个fatherUserIdfor (let i = index; i < this.predecessorList.length; i++) {if (this.predecessorList[i]) {for (let j = 0; j < this.predecessorList[i].length; j++) {// 如果先前的隐藏那么展开后按钮状态为打开if (this.predecessorList[i][j].display === false) {this.predecessorList[i][j].buttonDisplay = true}// 只有从无到有的才进行回显this.predecessorList[i][j].display = trueif (this.including(this.displayList, this.predecessorList[i][j].fatherUserId)) {this.predecessorList[i][j].display = false}}}}// 验证画线数据结尾是否实际存在let trueLineList = []for (let i = 0; i < newDrawLineList.length; i++) {if (this.trueDiv(newDrawLineList[i].end)) {trueLineList.push(newDrawLineList[i])}}// 新的画线数据this.drawLineList = trueLineList// 重新画线setTimeout(() => { this.drawLine() }, 50)},// 隐藏后续内容implicit(index, id) {// 操作线条// 销毁线条this.removeLines()// 线条数组清零let newDrawLineList = []// 对目前所有线条进行循环for (let i = 0; i < this.allLineList.length; i++) {let remain = falsefor (let j = 0; j < this.displayList.length; j++) {if (this.allLineList[i].start === String(this.displayList[j])) {remain = true}}if (remain === false) {newDrawLineList.push(this.allLineList[i])}}// 操作卡片// 寻找各个子集,并且观察子集是不是只有这一个fatherUserIdfor (let i = index; i < this.predecessorList.length; i++) {if (this.predecessorList[i]) {for (let j = 0; j < this.predecessorList[i].length; j++) {if (this.including(this.displayList, this.predecessorList[i][j].fatherUserId)) {this.predecessorList[i][j].display = false}}}}// 验证画线数据结尾是否实际存在let trueLineList = []for (let i = 0; i < newDrawLineList.length; i++) {if (this.trueDiv(newDrawLineList[i].end)) {trueLineList.push(newDrawLineList[i])}}// 新的画线数据this.drawLineList = trueLineList// 重新画线setTimeout(() => { this.drawLine() }, 50)},// div节点是否是实际存在的trueDiv(id) {for (let i = 0; i < this.predecessorList.length; i++) {if (this.predecessorList[i]) {for (let j = 0; j < this.predecessorList[i].length; j++) {if (String(this.predecessorList[i][j].id) === id && this.predecessorList[i][j].display === true) {return true}}}}return false},// 寻找子集findImplicit(index, id) {// 目前已经确认隐藏的id标题this.displayList.push(id)// 进行遍历寻找for (let i = index; i < this.predecessorList.length; i++) {if (this.predecessorList[i]) {for (let j = 0; j < this.predecessorList[i].length; j++) {if (this.including(this.displayList, this.predecessorList[i][j].fatherUserId)) {this.displayList.push(this.predecessorList[i][j].id)}}}}let newArr = [];for (let i = 0; i < this.displayList.length; i++) {if (!newArr.includes(this.displayList[i])) {newArr.push(this.displayList[i])}}// 隐藏的数组数据: this.displayListthis.displayList = [...newArr]},// 判断子数组中是否存在任意包含关系,不需要全等,只要有一个就行arbitrarily(list, fatherUserId) {let x = 0for (let i = 0; i < list.length; i++) {for (let j = 0; j < fatherUserId.length; j++) {if (list[i] === fatherUserId[j]) {x++}}}if (x !== 0) {return true}return false},// 判断子数组中是否存在包含关系including(list, fatherUserId) {let x = 0for (let i = 0; i < list.length; i++) {for (let j = 0; j < fatherUserId.length; j++) {if (list[i] === fatherUserId[j]) {x++}}}if (x === fatherUserId.length && fatherUserId.length !== 0) {return true}return false},// 重新定位各线positionLine() {for (let i = 0; i < this.drawLineList.length; i++) {let nameLine = this.drawLineList[i].start + '' + this.drawLineList[i].end// 判断线段是否真实存在if (this.lineList[nameLine] !== undefined) {this.lineList[nameLine].position()}}},// 开始画线drawLine() {for (let i = 0; i < this.drawLineList.length; i++) {this.getLine(this.drawLineList[i].start, this.drawLineList[i].end, i)}},// 点击展开缩小重新定位线条hideLines() {for (let i = 0; i < this.drawLineList.length; i++) {let nameLine = this.drawLineList[i].start + '' + this.drawLineList[i].endthis.lineList[nameLine].position()}},// 隐藏线条hideLine(start, end) {let nameLine = start + endthis.lineList[nameLine].hide()},// 销毁线条removeLines() {for (let i = 0; i < this.drawLineList.length; i++) {let nameLine = this.drawLineList[i].start + '' + this.drawLineList[i].endthis.lineList[nameLine].remove()}},// 点击展开clickDownsize(index, idx) {// 卡片三种状态互相切换if (this.predecessorList[index][idx].status === 0) {this.predecessorList[index][idx].status = 1} else if (this.predecessorList[index][idx].status === 1) {this.predecessorList[index][idx].status = 2} else {this.predecessorList[index][idx].status = 0}let predecessor = JSON.parse(JSON.stringify(this.predecessorList))this.predecessorList = []this.predecessorList = JSON.parse(JSON.stringify(predecessor))setTimeout(() => { this.positionLine() }, 50)},// 画线changeGetLine(start, end, i) {let lineStart = document.getElementById(start)let lineEnd = document.getElementById(end)let styleOption = {color: 'red', // 指引线颜色endPlug: '', // 指引线结束点的样式 hand,discsize: 2, // 线条尺寸startSocket: 'bottom', //在指引线开始的地方从元素左侧开始endSocket: 'top', //在指引线开始的地方从元素右侧结束// hide: true, // 绘制时隐藏,默认为false,在初始化时可能会出现闪烁的线条// startPlugColor: '#ff3792', // 渐变色开始色// endPlugColor: '#fff386', // 渐变色结束色gradient: false, // 使用渐变色outLineColor: 'blue',path: 'fluid', // straight,arc,fluid,magnet,grid// dash: {//   // 虚线样式//   animation: true // 让线条滚动起来// },hide: true,}let nameLine = start + endthis.lineList[nameLine].setOptions(styleOption)/** 显示效果*  draw 绘制线条*  fade 淡入*  none 无效果,即直接显示*/// let showEffectName = 'draw'// // 动画参数// let animOptions = {//   // duration: 1000, //持续时长//   // timing: 'ease-in' // 动画函数// }// this.lineList[nameLine].show()// this.lineList[nameLine].position()},// 恢复线段twiceGetLine(start, end, i) {let lineStart = document.getElementById(start)let lineEnd = document.getElementById(end)let styleOption = {color: '#6a6a6a', // 指引线颜色endPlug: '', // 指引线结束点的样式 hand,discsize: 2, // 线条尺寸startSocket: 'bottom', //在指引线开始的地方从元素左侧开始endSocket: 'top', //在指引线开始的地方从元素右侧结束// hide: true, // 绘制时隐藏,默认为false,在初始化时可能会出现闪烁的线条// startPlugColor: '#ff3792', // 渐变色开始色// endPlugColor: '#fff386', // 渐变色结束色gradient: false, // 使用渐变色outLineColor: '#6a6a6a',path: 'fluid', // straight,arc,fluid,magnet,grid// dash: {//   // 虚线样式//   animation: true // 让线条滚动起来// },hide: true,}let nameLine = start + endthis.lineList[nameLine].setOptions(styleOption)},// 画线getLine(start, end, i) {let lineStart = document.getElementById(start)let lineEnd = document.getElementById(end)let styleOption = {color: '#6a6a6a', // 指引线颜色endPlug: '', // 指引线结束点的样式 hand,discsize: 2, // 线条尺寸startSocket: 'bottom', //在指引线开始的地方从元素左侧开始endSocket: 'top', //在指引线开始的地方从元素右侧结束// hide: true, // 绘制时隐藏,默认为false,在初始化时可能会出现闪烁的线条// startPlugColor: '#ff3792', // 渐变色开始色// endPlugColor: '#fff386', // 渐变色结束色gradient: false, // 使用渐变色outLineColor: '#6a6a6a',path: 'fluid', // straight,arc,fluid,magnet,grid// dash: {//   // 虚线样式//   animation: true // 让线条滚动起来// },hide: true,}let nameLine = start + endthis.$set(this.lineList, `${nameLine}`, null)this.lineList[nameLine] = new LeaderLine(lineStart, lineEnd, styleOption)/** 显示效果*  draw 绘制线条*  fade 淡入*  none 无效果,即直接显示*/// let showEffectName = 'draw'// // 动画参数// let animOptions = {//   // duration: 1000, //持续时长//   // timing: 'ease-in' // 动画函数// }this.lineList[nameLine].show()this.lineList[nameLine].position()},}
}
</script>
<style>
.leader-line {z-index: -1
}
</style>
<style lang="scss" scoped >
.search-item-label {width: 30%;font-size: 14px;color: #333;font-weight: 600;
}.search-item {width: 40%;display: flex;align-items: center;margin-right: 5%;
}
.vue-treeselect{width: 80%;
}
.search {margin-left: 20px;margin-top: 20px;width: 500px;display: flex;justify-content: space-between;.el-button+.el-button {margin-left: 0px;}
}.main {height: calc(100vh - 84px);overflow-x: scroll;overflow-y: scroll;
}.main-predecessor {min-width: 1100px;width: fit-content;min-height: calc(100vh - 94px);}.father-predecessor {display: flex;justify-content: space-around;align-items: flex-start;
}.children-predecessor-big {width: 250px;height: 200px;border: 1px solid #f8f8f8;margin: 60px 10px;border-radius: 6px;box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;background-color: rgba(255, 255, 255, 0.95);position: relative;}.children-predecessor-middle {width: 200px;height: 80px;border: 1px solid #f8f8f8;margin: 60px 10px;border-radius: 6px;box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;background-color: rgba(255, 255, 255, 0.95);position: relative;
}.children-predecessor-small {width: 130px;height: 50px;border: 1px solid #f8f8f8;margin: 60px 10px;border-radius: 6px;box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;background-color: rgba(255, 255, 255, 0.95);position: relative;
}.button {position: absolute;text-align: center;bottom: -10px;left: 0;width: 100%;height: 20px;}.caption {text-align: center;line-height: 30px;
}.icon {cursor: pointer;float: right;font-size: 20px;line-height: 30px;color: #158BBB;margin-right: 10px;
}::v-deep .open {padding: 0 !important;border: 1px solid #b4b4b4;box-shadow: rgba(135, 138, 141, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;background-color: rgba(255, 255, 255, 0.95);border-radius: 50%;
}.O-list {margin-left: 10px;font-size: 18px;
}.kr-list {margin-left: 10px;font-size: 16px;
}::v-deep .small-select {.el-input__inner {width: 120px;}
}
</style>

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/85996.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++——关于命名空间

写c项目时&#xff0c;大家常用到的一句话就是&#xff1a; using namespace std; 怎么具体解析这句话呢&#xff1f; 命名冲突&#xff1a; 在c语言中&#xff0c;我们有变量的命名规范&#xff0c;如果一个变量名或者函数名和某个库里面自带的库函数或者某个关键字重名&…

涛思数据联合长虹佳华、阿里云 Marketplace 正式发布 TDengine Cloud

近日&#xff0c;涛思数据联合长虹佳华&#xff0c;正式在阿里云 Marketplace 发布全托管的时序数据云平台 TDengine Cloud&#xff0c;为用户提供更加丰富的订购渠道。目前用户可通过阿里云 Marketplace 轻松实现 TDengine Cloud 的订阅与部署&#xff0c;以最低的成本搭建最高…

【数学建模】--灰色关联分析

系统分析: 一般的抽象系统&#xff0c;如社会系统&#xff0c;经济系统&#xff0c;农业系统&#xff0c;生态系统&#xff0c;教育系统等都包含有许多种因素&#xff0c;多种因素共同作用的结果决定了该系统的发展态势。人们常常希望知道在众多的因素中&#xff0c;哪些是主要…

3.6 Spring MVC文件上传

1. 文件上传到本地 实现方式 Spring MVC使用commons-fileupload实现文件上传&#xff0c;注意事项如下&#xff1a; l HTTP请求方法是POST。 l HTTP请求头的Content-Type是multipart/form-data。 SpringMVC配置 配置commons-fileupload插件的文件上传解析器CommonsMultip…

vue二进制下载

封装axios&#xff0c;/api/request import axios from axios import store from /store import Vue from vue import { Message, MessageBox } from element-uiimport { getToken } from /utils/authaxios.defaults.headers[Content-Type] application/json;charsetutf-8 co…

如何选择适合自己的文件传输工具

随着互联网的发展&#xff0c;人们处理文件的需求也随之增加。不管是工作还是生活中&#xff0c;文件传输都是一个非常常见的问题。因此&#xff0c;如何选择适合自己的文件传输工具也越来越重要。在本文中&#xff0c;我将从以下几个方面进行分析和总结&#xff0c;希望能为大…

面试攻略,Java 基础面试 100 问(七)

String 是最基本的数据类型吗? 不是。Java 中的基本数据类型只有 8 个&#xff1a;byte、short、int、long、float、 double、char、boolean&#xff1b;除了基本类型&#xff08;primitive type&#xff09;和枚举类型&#xff08;enumeration type&#xff09;&#xff0c…

Android图形-合成与显示-SurfaceTestDemo

目录 引言&#xff1a; 主程序代码&#xff1a; 结果呈现&#xff1a; 小结&#xff1a; 引言&#xff1a; 通过一个最简单的测试程序直观Android系统的native层Surface的渲染显示过程。 主程序代码&#xff1a; #include <cutils/memory.h> #include <utils/L…

干货 | 详述 Elasticsearch 向量检索发展史

1. 引言 向量检索已经成为现代搜索和推荐系统的核心组件。 通过将复杂的对象&#xff08;例如文本、图像或声音&#xff09;转换为数值向量&#xff0c;并在多维空间中进行相似性搜索&#xff0c;它能够实现高效的查询匹配和推荐。 图片来自&#xff1a;向量数据库技术鉴赏【上…

AI绘画网站都有哪些比较好用?

人工智能绘画网站是一种利用人工智能技术进行图像处理和创作的网站。这些绘画网站通常可以帮助艺术家以人工智能绘画的形式快速生成有趣、美丽和独特的绘画作品。无论你是专业的艺术家还是对人工智能绘画感兴趣的普通人&#xff0c;人工智能绘画网站都可以为你提供新的创作灵感…

优思学院|6西格玛标准值水平是多少?

在质量管理和统计学领域&#xff0c;"6西格玛" 是一个重要的概念&#xff0c;它与产品和流程的质量有着密切的关系。本文将解释"6西格玛"标准值水平是什么&#xff0c;以及它在各个行业中的应用。 什么是6西格玛标准值水平&#xff1f; 理解西格玛 西格…

9.2.1Socket(UDP)

一.传输层: 1.UDP:无连接,不可靠,面向数据报,全双工. 2.TCP:有连接,可靠,面向字节流,全双工. 注意:这里的可不可靠是相对的,并且和安不安全无关. 二.UDP数据报套接字编程: 1.socket文件:表示网卡的这类文件. 2.DatagramPacket:表示一个UDP数据报. 三.代码实现: 1.回显服务…

webstorm debug调试vue项目

1.运行npm&#xff0c;然后控制台会打印下图中的地址&#xff0c;复制local的地址 2.run–>Edit Configuration&#xff0c;如下图 3.设置测试项 4.在你需要的js段打好断点 5.在上边框的工具栏里面有debug运行&#xff0c;点击debug运行的图标运行即可

【网络编程】实现一个简单多线程版本TCP服务器(附源码)

TCP多线程 &#x1f335;预备知识&#x1f384; Accept函数&#x1f332;字节序转换函数&#x1f333;listen函数 &#x1f334;代码&#x1f331;Log.hpp&#x1f33f;Makefile☘️TCPClient.cc&#x1f340;TCPServer.cc&#x1f38d; util.hpp &#x1f335;预备知识 &…

Nevron Vision for .NET Crack

Nevron Vision for .NET Crack NET Vision是一个用于创建具有数据可视化功能的强大数据表示应用程序的套件。该套件具有用于.NET的Nevron Chart、用于.NET的Nevron Diagram和用于.NET的Nevron User Interface。精心设计的对象模型、众多功能和高质量的演示使复杂数据的可视化变…

【Linux操作系统】深入理解Linux系统编程中的open函数

在Linux系统编程中&#xff0c;open函数是一个非常重要的系统调用函数&#xff0c;它用于打开或创建一个文件&#xff0c;并返回一个文件描述符。本文将详细介绍open函数的用法&#xff0c;并给出具体的代码示例。 文章目录 1. 函数原型2. 函数参数2.1 flags参数2.2 mode参数 …

编译Linux的时候出现 Restart config...

环境 buildroot 问题 在buildroot路径下执行 make linux-rebuild 出现了Restart config… 的问题 原因 我在修改linux源码的时候&#xff0c;在没有指定ARCH架构的情况下&#xff0c; 直接去linux源码目录(output/build/linux/)下执行了 make menuconfig并覆盖了原来的.c…

使用jasypt对Spring Boot配置文件中的配置项加密

在Spring Boot中&#xff0c;有很多口令需要加密&#xff0c;如数据库连接密码、访问第三方接口的Token等。常见的方法就是用jasypt对口令进行加密。 实际上&#xff0c;jasypt可以对配置文件中任意配置项的值进行加密&#xff0c;不局限于对密码的加密。 1.在pom.xml中添加ja…

wpf 3d 坐标系和基本三角形复习

wpf 3d 坐标系的描述见此&#xff0c; WPF 3d坐标系和基本三角形_wpf 坐标系_bcbobo21cn的博客-CSDN博客 X轴正向向右&#xff0c;Y轴正向向上&#xff1b;Z轴&#xff0c;正向是从屏幕里边出来&#xff0c;负向是往屏幕里边去&#xff1b;坐标原点是在呈现区域的中心&#x…

元宇宙核能发电VR模拟仿真实训教学为建设新型电力系统提供重要支撑

随着“碳达峰、碳中和”目标与建设新型能源体系的提出&#xff0c;在元宇宙环境下建设电力系统是未来发展的趋势。以物联网、区块链、数字孪生、混合现实等技术为主要代表的元宇宙技术体系及其在电力和能源系统中的应用&#xff0c;将会促进智能电网的发展&#xff0c;为建设新…