Skip to content

Instantly share code, notes, and snippets.

@sergeysova
Forked from SergProduction/d3Graff.html
Last active February 6, 2017 08:19
Show Gist options
  • Select an option

  • Save sergeysova/9a9f04bfc3e6451c96e1a04857fec032 to your computer and use it in GitHub Desktop.

Select an option

Save sergeysova/9a9f04bfc3e6451c96e1a04857fec032 to your computer and use it in GitHub Desktop.
<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>
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()
@sergeysova

Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment