Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 63 additions & 42 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable no-var */

module.exports = P2PGraph

var d3 = require('d3')
Expand Down Expand Up @@ -43,6 +45,9 @@ function P2PGraph (root) {
EventEmitter.call(self)

if (typeof root === 'string') root = document.querySelector(root)
if (!root || root.nodeType !== 1) {
throw new TypeError('P2PGraph: root element does not exist')
}
self._root = root

self._model = {
Expand All @@ -51,17 +56,6 @@ function P2PGraph (root) {
focused: null
}

self._model.links.forEach(function (link) {
var source = self._model.nodes[link.source]
var target = self._model.nodes[link.target]

source.children = source.children || []
source.children.push(link.target)

target.parents = target.parents || []
target.parents.push(link.source)
})

self._svg = d3.select(self._root).append('svg')

self._resize()
Expand Down Expand Up @@ -128,12 +122,20 @@ P2PGraph.prototype.remove = function (id) {
debug('remove %s', id)
var index = self._getNodeIndex(id)
if (index === -1) throw new Error('remove: node does not exist')
var node = self._model.nodes[index]

if (self._model.focused && self._model.focused.id === id) {
self._model.focused = null
self.emit('select', false)
}

for (var i = self._model.links.length - 1; i >= 0; i -= 1) {
var link = self._model.links[i]
if (link.source === node || link.target === node) {
self._model.links.splice(i, 1)
}
}

self._model.nodes.splice(index, 1)
self._update()
}
Expand All @@ -147,13 +149,13 @@ P2PGraph.prototype.connect = function (sourceId, targetId) {
var targetNode = self._getNode(targetId)
if (!targetNode) throw new Error('connect: invalid target id')

if (self.getLink(sourceNode.index, targetNode.index)) {
if (self.getLink(sourceId, targetId)) {
throw new Error('connect: cannot make duplicate connection')
}

self._model.links.push({
source: sourceNode.index,
target: targetNode.index
source: sourceNode,
target: targetNode
})
self._update()
}
Expand All @@ -167,7 +169,7 @@ P2PGraph.prototype.disconnect = function (sourceId, targetId) {
var targetNode = self._getNode(targetId)
if (!targetNode) throw new Error('disconnect: invalid target id')

var index = self.getLinkIndex(sourceNode.index, targetNode.index)
var index = self.getLinkIndex(sourceId, targetId)
if (index === -1) throw new Error('disconnect: connection does not exist')

self._model.links.splice(index, 1)
Expand All @@ -189,7 +191,7 @@ P2PGraph.prototype.hasLink = function (sourceId, targetId) {
if (!sourceNode) throw new Error('hasLink: invalid source id')
var targetNode = self._getNode(targetId)
if (!targetNode) throw new Error('hasLink: invalid target id')
return !!self.getLink(sourceNode.index, targetNode.index)
return !!self.getLink(sourceId, targetId)
}

P2PGraph.prototype.areConnected = function (sourceId, targetId) {
Expand All @@ -198,8 +200,8 @@ P2PGraph.prototype.areConnected = function (sourceId, targetId) {
if (!sourceNode) throw new Error('areConnected: invalid source id')
var targetNode = self._getNode(targetId)
if (!targetNode) throw new Error('areConnected: invalid target id')
return self.getLink(sourceNode.index, targetNode.index) ||
self.getLink(targetNode.index, sourceNode.index)
return !!(self.getLink(sourceId, targetId) ||
self.getLink(targetId, sourceId))
}

P2PGraph.prototype.unchoke = function (sourceId, targetId) {
Expand All @@ -225,12 +227,14 @@ P2PGraph.prototype.seed = function (id, isSeeding) {
P2PGraph.prototype.rate = function (sourceId, targetId, bytesRate) {
var self = this
debug('rate update:', sourceId + '<->' + targetId, 'at', bytesRate)
if (typeof bytesRate !== 'number' || bytesRate < 0) throw new Error('rate: 3th param must be a positive number')
if (typeof bytesRate !== 'number' || !isFinite(bytesRate) || bytesRate < 0) {
throw new Error('rate: 3rd param must be a finite non-negative number')
}
var sourceNode = self._getNode(sourceId)
if (!sourceNode) throw new Error('rate: invalid source id')
var targetNode = self._getNode(targetId)
if (!targetNode) throw new Error('rate: invalid target id')
var index = self.getLinkIndex(sourceNode.index, targetNode.index)
var index = self.getLinkIndex(sourceId, targetId)
if (index === -1) throw new Error('rate: connection does not exist')
self._model.links[index].rate = speedRange(bytesRate)
debug('rate:', self._model.links[index].rate)
Expand All @@ -242,12 +246,15 @@ P2PGraph.prototype.rate = function (sourceId, targetId, bytesRate) {
}
}

P2PGraph.prototype.getLink = function (source, target) {
P2PGraph.prototype.getLink = function (sourceId, targetId) {
var self = this
var sourceNode = self._getNode(sourceId)
var targetNode = self._getNode(targetId)
if (!sourceNode || !targetNode) return null

for (var i = 0, len = self._model.links.length; i < len; i += 1) {
var link = self._model.links[i]
if (link.source === self._model.nodes[source] &&
link.target === self._model.nodes[target]) {
if (link.source === sourceNode && link.target === targetNode) {
return link
}
}
Expand All @@ -257,11 +264,18 @@ P2PGraph.prototype.getLink = function (source, target) {
P2PGraph.prototype.destroy = function () {
var self = this
debug('destroy')
if (!self._root) return

self._root.remove()
window.removeEventListener('resize', self._resizeThrottled)
self._force.stop()
self._svg.remove()
self.removeAllListeners()

self._root = null
self._svg = null
self._force = null
self._node = null
self._link = null
self._resizeThrottled = null
}

Expand Down Expand Up @@ -395,34 +409,38 @@ P2PGraph.prototype._update = function () {

P2PGraph.prototype._childNodes = function (d) {
var self = this
if (!d.children) return []

return d.children
.map(function (child) {
return self._node[0][child]
return self._model.links
.filter(function (link) {
return link.source === d
})
.map(function (link) {
return self._node[0][self._model.nodes.indexOf(link.target)]
}).filter(function (child) {
return child
})
}

P2PGraph.prototype._parentNodes = function (d) {
var self = this
if (!d.parents) return []

return d.parents
.map(function (parent) {
return self._node[0][parent]
return self._model.links
.filter(function (link) {
return link.target === d
})
.map(function (link) {
return self._node[0][self._model.nodes.indexOf(link.source)]
}).filter(function (parent) {
return parent
})
}

P2PGraph.prototype._connected = function (d, o) {
return o.id === d.id ||
(d.children && d.children.indexOf(o.id) !== -1) ||
(o.children && o.children.indexOf(d.id) !== -1) ||
(o.parents && o.parents.indexOf(d.id) !== -1) ||
(d.parents && d.parents.indexOf(o.id) !== -1)
var self = this
if (o === d) return true

return self._model.links.some(function (link) {
return (link.source === d && link.target === o) ||
(link.source === o && link.target === d)
})
}

P2PGraph.prototype._getNode = function (id) {
Expand Down Expand Up @@ -467,12 +485,15 @@ P2PGraph.prototype._getNodeIndex = function (id) {
return -1
}

P2PGraph.prototype.getLinkIndex = function (source, target) {
P2PGraph.prototype.getLinkIndex = function (sourceId, targetId) {
var self = this
var sourceNode = self._getNode(sourceId)
var targetNode = self._getNode(targetId)
if (!sourceNode || !targetNode) return -1

for (var i = 0, len = self._model.links.length; i < len; i += 1) {
var link = self._model.links[i]
if (link.source === self._model.nodes[source] &&
link.target === self._model.nodes[target]) {
if (link.source === sourceNode && link.target === targetNode) {
return i
}
}
Expand Down
Loading