-
-
Save sergeysova/9a9f04bfc3e6451c96e1a04857fec032 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.4.3/d3.js"></script> | |
| <style> | |
| svg line{ | |
| stroke: grey; | |
| stroke-width: 2; | |
| } | |
| svg path{ | |
| stroke: #808080; | |
| stroke-width: 2; | |
| fill: none; | |
| } | |
| .Node{ | |
| border: 1px solid #b00082; | |
| border-radius: 5px; | |
| } | |
| ul{ | |
| margin: 0; | |
| padding: 0 5px; | |
| list-style-type: none; | |
| } | |
| li{ | |
| border-bottom: 1px solid #000; | |
| } | |
| .node-head{ | |
| width: 100%; | |
| background: #b00082; | |
| height: 25px; | |
| color: #fff; | |
| padding: 0 0 0 5px; | |
| text-align: center; | |
| } | |
| </style> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const width = document.documentElement.clientWidth - 100 | |
| const height = document.documentElement.clientHeight - 100 | |
| const paths = [] | |
| const addNodeButt = d3.select("body") | |
| .append('button') | |
| .text('add Node') | |
| const nodeNameInput = d3.select("body") | |
| .append('input') | |
| .attr('type','text') | |
| .attr('placeholder','name Node') | |
| d3.select("body").append('br') | |
| const svg = d3.select("body").append("svg") | |
| .attr("height", height) | |
| .attr("width", width) | |
| .style('border','1px solid #ddd') | |
| // функция, создающая по массиву точек линии | |
| const line = d3.line() | |
| .x( d => d.x ) | |
| .y( d => d.y ) | |
| .curve(d3.curveMonotoneX) | |
| addNodeButt.on('click', () => addNode()) | |
| function addNode() { | |
| const nodeName = nodeNameInput.property('value') | |
| nodeNameInput.property('value', '') | |
| paths.push({ id: nodeName }) | |
| const fo = svg.append('foreignObject') | |
| .attr('x', 20) | |
| .attr('y', 20) | |
| .attr('width', 120) | |
| .attr('height', 200) | |
| .attr('class', 'Node') | |
| const body = fo.append('xhtml:body') | |
| const head = body.append('div') | |
| .classed('node-head', true) | |
| head.call( | |
| d3.drag() | |
| .subject(differencePosition) | |
| .container(() => svg.node()) | |
| .filter(() => d3.event.target == head.node()) | |
| .on('start', moveNode) | |
| ) | |
| function differencePosition() { | |
| const x = parseInt(fo.attr('x'), 10) | |
| const y = parseInt(fo.attr('y'), 10) | |
| return { x, y } | |
| } | |
| function moveNode() { | |
| const { x, y } = d3.event.subject | |
| const x1 = d3.event.x - x | |
| const y1 = d3.event.y - y | |
| const id = paths.findIndex(el => el.id == nodeName) | |
| if (paths[id].sigin) { | |
| const parentId = paths.findIndex(el => el.id == parentId) | |
| const data = paths[parentId].data | |
| const d2x = data[2].x - d3.event.x | |
| const d2y = data[2].y - d3.event.y | |
| const d3x = data[3].x - d3.event.x | |
| const d3y = data[3].y - d3.event.y | |
| } | |
| if (paths[id].data) { | |
| const data = paths[id].data | |
| const d0x = data[0].x - d3.event.x | |
| const d0y = data[0].y - d3.event.y | |
| const d1x = data[1].x - d3.event.x | |
| const d1y = data[1].y - d3.event.y | |
| } | |
| d3.event.on('drag', () => { | |
| const x2 = x1 + d3.event.x | |
| const y2 = y1 + d3.event.y | |
| fo.attr('x', x2) | |
| .attr('y', y2) | |
| if(paths[id].sigin) { | |
| const parentId = paths.findIndex(el => el.id == parentId) | |
| const data = paths[parentId].data | |
| data[2] = { x: d2x + d3.event.x, y: d2y + d3.event.y } | |
| data[3] = { x: d3x + d3.event.x, y: d3y + d3.event.y } | |
| const path = paths[parentId].path | |
| path.attr('d', line(data)) | |
| } | |
| if (paths[id].data) { | |
| const data = paths[id].data | |
| data[0] = { x: d0x + d3.event.x, y: d0y + d3.event.y } | |
| data[1] = { x: d1x + d3.event.x, y: d1y + d3.event.y } | |
| const path = paths[id].path | |
| path.attr('d', line(data)) | |
| } | |
| }) | |
| } | |
| head.text( nodeName ) | |
| const sigin = head.append('span') | |
| .classed('glyphicon glyphicon-log-in', true) | |
| .attr('data-in', nodeName) | |
| .style('float','left') | |
| .style('margin','3px 5px 0 0'); | |
| const add = head.append('span') | |
| .classed('glyphicon glyphicon-plus-sign', true) | |
| .style('color', '#fff') | |
| .style('margin', '5px') | |
| .style('float', 'right') | |
| const input = body.append('input') | |
| .attr('type', 'text') | |
| .attr('placeholder','name line') | |
| .style('width', '100%') | |
| .style('border-width', '0 0 1px 0') | |
| .style('padding', '0 5px') | |
| add.on('click', () => { | |
| if(!input.property('value')) { | |
| return | |
| } | |
| const li = ul.append('li') | |
| .text(input.property('value')) | |
| input.property('value', '') | |
| const addCurve = li.append('span') | |
| .classed('glyphicon glyphicon-log-out', true) | |
| .style('float','right') | |
| .style('margin-top','3px') | |
| addCurve.call( | |
| d3.drag() | |
| .container(() => svg.node()) | |
| .on('start', newConnect) | |
| ) | |
| function newConnect() { | |
| const data = [ | |
| { | |
| x: d3.event.x, | |
| y: d3.event.y, | |
| }, | |
| { | |
| x: d3.event.x + 40, | |
| y: d3.event.y, | |
| }, | |
| { | |
| x: d3.event.x + 40, | |
| y: d3.event.y, | |
| }, | |
| { | |
| x: d3.event.x + 40, | |
| y: d3.event.y, | |
| }, | |
| ] | |
| id = paths.findIndex(el => el.id == nodeName) | |
| paths[id].data = data | |
| const active = svg.append('path').attr('d', line(data)) | |
| d3.event.on('drag', () => { | |
| data[2] = { x: d3.event.x - 40, y: d3.event.y } | |
| data[3] = { x: d3.event.x, y: d3.event.y } | |
| active.attr('d', line(data)) | |
| }) | |
| d3.event.on('end', () => { | |
| const source = d3.select(d3.event.sourceEvent.target) | |
| if (source.attr('data-in')) { | |
| const child = paths.findIndex(el => el.id === source.attr('data-in')) | |
| paths[child].sigin = nodeName | |
| paths[id].path = active | |
| } | |
| else { | |
| delete paths[ id ].data | |
| active.remove() | |
| } | |
| }) | |
| } | |
| }) | |
| const ul = body.append('ul') | |
| } | |
| addNode() |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://jsfiddle.net/Lptw05hq/3/