UNPKG

link-line

Version:

react 连线组件

437 lines (408 loc) 12.6 kB
import React from 'react' import '../assets/LinkLine.scss' import SVG from 'svg.js' export default class LinkLine extends React.Component { constructor(props) { super(props) this.state = { lineArr: [], currentInfo: null, draw: {}, } // this.draw = null // this.lineArr = [] this.drawBox = React.createRef() this.sourceListDom = React.createRef() this.targetListDom = React.createRef() } componentDidMount() { this.initSVG() //窗口变化时,重新画线 window.addEventListener('resize', ()=>{ console.log('resize'); this.state.lineArr.forEach(lineItem=>{ if(lineItem.visible && lineItem.beginDom && lineItem.endDom){ this.drawLine(lineItem) } }) }) this.testLine() } componentDidUpdate(prevProps, prevState){ let relationsStr = JSON.stringify(this.props.dataSource.relations) let preRelationStr = JSON.stringify(prevProps.dataSource.relations) if(relationsStr!=preRelationStr){ console.log('pros',this.props.dataSource.relations); this.initSVG() } } initSVG = (info) => { let { source, target, relations} = this.props.dataSource let sourceListDomHeight = this.sourceListDom.current.offsetHeight let targetListDomHeight = this.targetListDom.current.offsetHeight let maxLength = sourceListDomHeight> targetListDomHeight ? sourceListDomHeight : targetListDomHeight this.draw = SVG('link-line').size('100%', maxLength) // 元素高40,宽100 let lineArr = [] // 遍历DOM节点 name 对应 li dom元素 let sourceDomDic = {} this.sourceListDom.current.querySelectorAll('li').forEach(sourceDomItem=>{ console.log(sourceDomItem); sourceDomDic[sourceDomItem.getAttribute('data-name')] = sourceDomItem }) let targetDomDic = {} this.targetListDom.current.querySelectorAll('li').forEach(targetDomItem=>{ targetDomDic[targetDomItem.getAttribute('data-name')] = targetDomItem }) console.log(this.sourceListDom.current.querySelectorAll('li')); source.forEach((item, index) => { let obj = { beginValue: item.name, index: index, beginDom: sourceDomDic[item.name], begin:{}, endDom:null, visible: false, line: this.createLine(), } if(index==0){ obj.line.plot(100,100,150,150) obj.line.show() } // 初始化,关联关系 // 遍历DOM节点 relations.forEach(relationItem=>{ if(relationItem.source==item.name){ obj.endDom = targetDomDic[relationItem.target] obj.visible = true obj.line=this.createLine('end') this.drawLine(obj) } }) lineArr.push(obj) }) this.setState({ lineArr }) } // 初始化,显示一条线 drawLine = (currentInfo)=>{ currentInfo.begin = { x: currentInfo.beginDom.offsetWidth, y: currentInfo.beginDom.offsetTop+currentInfo.beginDom.offsetHeight/2 } currentInfo.end = { x: currentInfo.endDom.offsetLeft , // 箭头-2 y: currentInfo.endDom.offsetTop + currentInfo.endDom.offsetHeight/2, } currentInfo.line.show() currentInfo.line.plot( currentInfo.begin.x, currentInfo.begin.y, currentInfo.end.x, currentInfo.end.y ) } testLine = () => { let lineTest = this.draw.line() lineTest.stroke({ color: '#67C23A', width: 10, opacity: 1, linecap: 'round', }) lineTest.plot(100, 100, 200, 100) var arrow = this.draw.marker(12, 12, function (add) { add.path('M2,2 L2,10 L10,6 L2,2') add.style({ fill: '#1890ff', }) }) lineTest.stroke({ color: '#67C23A', width: 1, linecap: 'round', }) lineTest.marker('end',arrow) lineTest.mouseover(function(){ console.log(2342); }) lineTest.show() } mousedown = (type, event) => { if(event.target.parentNode!=this.sourceListDom.current){ return } let { lineArr } = this.state let currentDom = event.target let parentDom = event.target.parentNode let x, y, current = {} lineArr.forEach((item) => { if (item.beginDom == event.target) { current = item } }) // current.line = this.createLine() // console.log('current', current) // console.log('currentDom=', currentDom, 'parentDom=', parentDom) current.begin = {} current.beginElement = currentDom let beginX = this.sourceListDom.current.offsetWidth let beginY = event.target.offsetTop+event.target.offsetHeight/2 current.beginDom = event.target current.begin.x = beginX current.begin.y = beginY current.line.remove() current.line = this.createLine() current.line.show() current.line.stroke({ color: '#1890ff', }) let mousePos = this.getMousePos(event) current.line.plot(current.begin.x, current.begin.y, mousePos.x, mousePos.y) this.setState({ currentInfo: current }) } mousemove = (event) => { event.preventDefault() let { currentInfo } = this.state if (currentInfo) { let end = {} // console.log('event', event) end.x = this.getMousePos(event).x end.y = this.getMousePos(event).y currentInfo.line.plot( currentInfo.begin.x, currentInfo.begin.y, end.x, end.y ) this.setState({ currentInfo }) } } mouseleave = (event) => { let { currentInfo } = this.state currentInfo && currentInfo.line.hide() } parentLiNode = (elementNode)=>{ console.log(elementNode.parentNode); if(!elementNode.parentNode){ return null } if(elementNode.parentNode.tagName==='LI'){ return elementNode.parentNode } else{ return this.parentLiNode(elementNode.parentNode) } } mouseup = (event) => { event.preventDefault() let { lineArr, currentInfo } = this.state if(!currentInfo){ return } console.log('current', event.target, event.target.parentNode) console.log('current', event.target.offsetLeft, event.target.offsetTop) // console.log('currentDom=', currentDom, 'parentDom=', parentDom) // 删除于该目标点连接的其他线 lineArr.forEach(lineItem=>{ if(lineItem.endDom==event.target && lineItem!=currentInfo){ lineItem.visible = false // lineItem.beginDom = null lineItem.endDom = null lineItem.line.hide() } }) let elementLiNode ; if(event.target.tagName==='LI'){ elementLiNode = event.target }else{ elementLiNode = this.parentLiNode(event.target) } if(!elementLiNode ||elementLiNode.getAttribute('class').indexOf('list-header')>=0){ currentInfo.line.hide() return } console.log(elementLiNode.tagName); console.log(elementLiNode.getAttribute('class')); //在目标节点抬起鼠标 if (event.target.parentNode == this.targetListDom.current ) { // 连到目标节点中间 currentInfo.end = { x: event.target.offsetLeft , // 箭头-2 y: event.target.offsetTop + event.target.offsetHeight/2, } currentInfo.endDom = event.target currentInfo.visible = true currentInfo.line.remove() currentInfo.line = this.createLine('end') currentInfo.line.show() currentInfo.line.plot( currentInfo.begin.x, currentInfo.begin.y, currentInfo.end.x, currentInfo.end.y ) // currentInfo.line.marker.remove() // currentInfo.line.hide() // var lineInfo = Object.assign({},currentInfo) // var newLine = this.createLine('end') // newLine.end = { // x: event.target.offsetLeft , // 箭头-2 // y: event.target.offsetTop + event.target.offsetHeight/2, // } // newLine.plot( // currentInfo.begin.x, // currentInfo.begin.y, // currentInfo.end.x, // currentInfo.end.y // ) // newLine.show() // newLine.endDom = event.target // newLine.visible = true // lineInfo.line = newLine // lineArr.push(lineInfo) } else { console.log('current', event.target, event.target.parentNode) currentInfo.line && currentInfo.line.hide() } console.log(lineArr); this.setState({ currentInfo: null, lineArr }) } getMousePos = (event) => { let pos = { x: event.nativeEvent.offsetX, y: event.nativeEvent.offsetY, } if (event.target !== this.drawBox.current) { pos.x += event.target.offsetLeft pos.y += event.target.offsetTop } return pos } boxClick = (event) => { // console.log(event.nativeEvent.offsetX,event.nativeEvent.offsetY); // console.log(event); // if(event.target==this.drawBox){ // console.log('aa'); // } // console.log(this.getMousePos(event)); } createLine = (type) => { let line = this.draw.line() let endPos = type=='end' ? 28 : 12 var arrow = this.draw.marker(endPos, 12, function (add) { add.path('M2,2 L2,10 L10,6 L2,2') add.style({ fill: '#1890ff', }) }) line.stroke({ color: '#1890ff', width: 1, linecap: 'round', }) line.marker('end',arrow) line.mouseover(function(){ console.log('mouseover'); }) line.mousemove((e) => { console.log(e); let { lineArr } = this.state let current = lineArr.find((el) => { return el.line.node == e.target }) if (current && current.endValue) { let left, top left = (current.end.x + current.begin.x - 20) / 2 + 'px' top = (current.end.y + current.begin.y - 15) / 2 + 'px' this.setState({ deleteShow: true, top, left, removeLine: e.target }) } }) line.mouseout((e) => { this.setState({ deleteShow: false }) }) line.hide() return line } render() { let dataSource = this.props.dataSource let { lineArr } = this.state console.log(this.props.children); return ( <div className="link-line" id="link-line"> <div id="svg-box" ref={this.drawBox} className="link-line-body" onMouseMove={this.mousemove} onMouseLeave={this.mouseleave} onMouseUp={this.mouseup} onClick={this.boxClick} > <ul className="source-list" ref={this.sourceListDom} > <li className="list-item"> { Object.keys(dataSource.source[0]).map((keyItem)=>{ return ( <span key={keyItem}>{keyItem}</span> ) }) } </li> {dataSource.source.map((sourceItem) => { return ( <li className="list-item" key={sourceItem.name} data-name={sourceItem.name} onMouseDown={(e) => this.mousedown('source', e)} > { Object.keys(sourceItem).map((keyItem)=>{ return ( <span key={sourceItem[keyItem]}>{sourceItem[keyItem]}</span> ) }) } <div className="list-item-point"></div> </li> ) })} </ul> <ul className="target-list" ref={this.targetListDom} > <li className="list-item list-header"> { Object.keys(dataSource.target[0]).map((keyItem)=>{ return ( <span key={keyItem}>{keyItem}</span> ) }) } </li> { dataSource.target.map((targetItem) => { return <li className="list-item" key={targetItem.name} data-name={targetItem.name}> { Object.keys(targetItem).map((keyItem)=>{ return ( <span key={targetItem[keyItem]}>{targetItem[keyItem]}</span> ) }) } <div className="list-item-point"></div> </li> }) } </ul> </div> </div> ) } }