link-line
Version:
react 连线组件
437 lines (408 loc) • 12.6 kB
JSX
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>
)
}
}