d3plus-network
Advanced tools
Comparing version 0.2.1 to 0.3.0
/* | ||
d3plus-network v0.2.1 | ||
d3plus-network v0.3.0 | ||
Javascript network visualizations built upon d3 modules. | ||
@@ -67,6 +67,6 @@ Copyright (c) 2018 D3plus - https://d3plus.org | ||
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-array'), require('d3-collection'), require('d3-scale'), require('d3-zoom'), require('d3plus-common'), require('d3plus-shape'), require('d3plus-viz')) : | ||
typeof define === 'function' && define.amd ? define('d3plus-network', ['exports', 'd3-array', 'd3-collection', 'd3-scale', 'd3-zoom', 'd3plus-common', 'd3plus-shape', 'd3plus-viz'], factory) : | ||
(factory((global.d3plus = {}),global.d3Array,global.d3Collection,global.scales,global.d3Zoom,global.d3plusCommon,global.shapes,global.d3plusViz)); | ||
}(this, (function (exports,d3Array,d3Collection,scales,d3Zoom,d3plusCommon,shapes,d3plusViz) { 'use strict'; | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-array'), require('d3-collection'), require('d3-scale'), require('d3-zoom'), require('d3plus-common'), require('d3plus-shape'), require('d3plus-viz'), require('d3plus-color')) : | ||
typeof define === 'function' && define.amd ? define('d3plus-network', ['exports', 'd3-array', 'd3-collection', 'd3-scale', 'd3-zoom', 'd3plus-common', 'd3plus-shape', 'd3plus-viz', 'd3plus-color'], factory) : | ||
(factory((global.d3plus = {}),global.d3Array,global.d3Collection,global.scales,global.d3Zoom,global.d3plusCommon,global.shapes,global.d3plusViz,global.d3plusColor)); | ||
}(this, (function (exports,d3Array,d3Collection,scales,d3Zoom,d3plusCommon,shapes,d3plusViz,d3plusColor) { 'use strict'; | ||
@@ -589,3 +589,583 @@ /** | ||
/** | ||
@external Viz | ||
@see https://github.com/d3plus/d3plus-viz#Viz | ||
*/ | ||
/** | ||
@class Rings | ||
@extends external:Viz | ||
@desc Creates a ring visualization based on a defined set of nodes and edges. [Click here](http://d3plus.org/examples/d3plus-network/simple-rings/) for help getting started using the Rings class. | ||
*/ | ||
var Rings = (function (Viz) { | ||
function Rings() { | ||
var this$1 = this; | ||
Viz.call(this); | ||
this._labelCutoff = 100; | ||
this._links = []; | ||
this._noDataMessage = false; | ||
this._nodes = []; | ||
this._on.mouseenter = function () {}; | ||
this._on["mouseleave.shape"] = function () { | ||
this$1.hover(false); | ||
}; | ||
this._on["mousemove.shape"] = function (d, i) { | ||
if (this$1._focus && this$1._focus === d.id) { | ||
this$1.hover(false); | ||
this$1._on.mouseenter.bind(this$1)(d, i); | ||
this$1._focus = undefined; | ||
} | ||
else { | ||
var id = this$1._nodeGroupBy && this$1._nodeGroupBy[this$1._drawDepth](d, i) ? this$1._nodeGroupBy[this$1._drawDepth](d, i) : this$1._id(d, i), | ||
links = this$1._linkLookup[id], | ||
node = this$1._nodeLookup[id]; | ||
var filterIds = [node.id]; | ||
var xDomain = [node.x - node.r, node.x + node.r], | ||
yDomain = [node.y - node.r, node.y + node.r]; | ||
links.forEach(function (l) { | ||
filterIds.push(l.id); | ||
if (l.x - l.r < xDomain[0]) { xDomain[0] = l.x - l.r; } | ||
if (l.x + l.r > xDomain[1]) { xDomain[1] = l.x + l.r; } | ||
if (l.y - l.r < yDomain[0]) { yDomain[0] = l.y - l.r; } | ||
if (l.y + l.r > yDomain[1]) { yDomain[1] = l.y + l.r; } | ||
}); | ||
this$1.hover(function (h, x) { | ||
if (h.source && h.target) { return h.source.id === node.id || h.target.id === node.id; } | ||
else { return filterIds.includes(this$1._ids(h, x)[this$1._drawDepth]); } | ||
}); | ||
} | ||
}; | ||
this._on["click.shape"] = function (d) { | ||
this$1._center = d.id; | ||
this$1._draw(); | ||
}; | ||
this._sizeMin = 5; | ||
this._sizeScale = "sqrt"; | ||
this._shape = d3plusCommon.constant("Circle"); | ||
this._shapeConfig = d3plusCommon.assign(this._shapeConfig, { | ||
labelConfig: { | ||
duration: 0, | ||
fontMin: 1, | ||
fontResize: true, | ||
labelPadding: 0, | ||
textAnchor: "middle", | ||
verticalAlign: "middle" | ||
}, | ||
Path: { | ||
fill: "none", | ||
label: false, | ||
stroke: "#eee", | ||
strokeWidth: 1 | ||
} | ||
}); | ||
} | ||
if ( Viz ) Rings.__proto__ = Viz; | ||
Rings.prototype = Object.create( Viz && Viz.prototype ); | ||
Rings.prototype.constructor = Rings; | ||
/** | ||
Extends the draw behavior of the abstract Viz class. | ||
@private | ||
*/ | ||
Rings.prototype._draw = function _draw (callback) { | ||
var this$1 = this; | ||
Viz.prototype._draw.call(this, callback); | ||
var data = this._filteredData.reduce(function (obj, d, i) { | ||
obj[this$1._id(d, i)] = d; | ||
return obj; | ||
}, {}); | ||
var nodes = this._nodes; | ||
if (!this._nodes.length && this._links.length) { | ||
var nodeIds = Array.from(new Set(this._links.reduce(function (ids, link) { return ids.concat([link.source, link.target]); }, []))); | ||
nodes = nodeIds.map(function (node) { return typeof node === "object" ? node : {id: node}; }); | ||
} | ||
nodes = nodes.reduce(function (obj, d, i) { | ||
obj[this$1._nodeGroupBy ? this$1._nodeGroupBy[this$1._drawDepth](d, i) : this$1._id(d, i)] = d; | ||
return obj; | ||
}, {}); | ||
nodes = Array.from(new Set(Object.keys(data).concat(Object.keys(nodes)))).map(function (id, i) { | ||
var d = data[id], | ||
n = nodes[id]; | ||
if (n === undefined) { return false; } | ||
return { | ||
__d3plus__: true, | ||
data: d || n, | ||
i: i, id: id, | ||
node: n, | ||
shape: d !== undefined && this$1._shape(d) !== undefined ? this$1._shape(d) : this$1._shape(n) | ||
}; | ||
}).filter(function (n) { return n; }); | ||
var nodeLookup = this._nodeLookup = nodes.reduce(function (obj, d) { | ||
obj[d.id] = d; | ||
return obj; | ||
}, {}); | ||
var links = this._links.map(function (link) { | ||
var check = ["source", "target"]; | ||
return check.reduce(function (result, check) { | ||
result[check] = typeof link[check] === "number" ? nodes[link[check]] : nodeLookup[link[check].id || link[check]]; | ||
return result; | ||
}, {}); | ||
}); | ||
var linkMap = links.reduce(function (map, link) { | ||
if (!map[link.source.id]) { | ||
map[link.source.id] = []; | ||
} | ||
map[link.source.id].push(link); | ||
if (!map[link.target.id]) { | ||
map[link.target.id] = []; | ||
} | ||
map[link.target.id].push(link); | ||
return map; | ||
}, {}); | ||
var height = this._height - this._margin.top - this._margin.bottom, | ||
transform = "translate(" + (this._margin.left) + ", " + (this._margin.top) + ")", | ||
transition = this._transition, | ||
width = this._width - this._margin.left - this._margin.right; | ||
var edges = [], | ||
radius = d3Array.min([height, width]) / 2, | ||
ringWidth = radius / 3; | ||
var primaryRing = ringWidth, | ||
secondaryRing = ringWidth * 2; | ||
var center = nodeLookup[this._center]; | ||
center.x = width / 2; | ||
center.y = height / 2; | ||
center.r = this._sizeMin ? d3Array.max([this._sizeMin, primaryRing * .65]) : this._sizeMax ? d3Array.min([this._sizeMax, primaryRing * .65]) : primaryRing * .65; | ||
var claimed = [center], | ||
primaries = []; | ||
linkMap[this._center].forEach(function (edge) { | ||
var node = edge.source.id === this$1._center ? edge.target : edge.source; | ||
node.edges = linkMap[node.id].filter(function (link) { return link.source.id !== this$1._center || link.target.id !== this$1._center; }); | ||
node.edge = edge; | ||
claimed.push(node); | ||
primaries.push(node); | ||
}); | ||
primaries.sort(function (a, b) { return a.edges.length - b.edges.length; }); | ||
var secondaries = []; | ||
var totalEndNodes = 0; | ||
primaries.forEach(function (p) { | ||
var primaryId = p.id; | ||
p.edges = p.edges.filter(function (edge) { return !claimed.includes(edge.source) && edge.target.id === primaryId || | ||
!claimed.includes(edge.target) && edge.source.id === primaryId; }); | ||
totalEndNodes += p.edges.length || 1; | ||
p.edges.forEach(function (edge) { | ||
var source = edge.source; | ||
var target = edge.target; | ||
var claim = target.id === primaryId ? source : target; | ||
claimed.push(claim); | ||
}); | ||
}); | ||
var tau = Math.PI * 2; | ||
var offset = 0; | ||
primaries.forEach(function (p, i) { | ||
var children = p.edges.length || 1; | ||
var space = tau / totalEndNodes * children; | ||
if (i === 0) { | ||
offset -= space / 2; | ||
} | ||
var angle = offset + space / 2 - tau / 4; | ||
p.radians = angle; | ||
p.x = width / 2 + primaryRing * Math.cos(angle); | ||
p.y = height / 2 + primaryRing * Math.sin(angle); | ||
offset += space; | ||
p.edges.forEach(function (edge, i) { | ||
var node = edge.source.id === p.id ? edge.target : edge.source; | ||
var s = tau / totalEndNodes; | ||
var a = angle - s * children / 2 + s / 2 + s * i; | ||
node.radians = a; | ||
node.x = width / 2 + secondaryRing * Math.cos(a); | ||
node.y = height / 2 + secondaryRing * Math.sin(a); | ||
secondaries.push(node); | ||
}); | ||
}); | ||
var primaryDistance = ringWidth / 2; | ||
var secondaryDistance = ringWidth / 4; | ||
var primaryMax = primaryDistance / 2 - 4; | ||
if (primaryDistance / 2 - 4 < 8) { | ||
primaryMax = d3Array.min([primaryDistance / 2, 8]); | ||
} | ||
var secondaryMax = secondaryDistance / 2 - 4; | ||
if (secondaryDistance / 2 - 4 < 4) { | ||
secondaryMax = d3Array.min([secondaryDistance / 2, 4]); | ||
} | ||
if (secondaryMax > ringWidth / 10) { | ||
secondaryMax = ringWidth / 10; | ||
} | ||
if (secondaryMax > primaryMax && secondaryMax > 10) { | ||
secondaryMax = primaryMax * .75; | ||
} | ||
if (primaryMax > secondaryMax * 1.5) { | ||
primaryMax = secondaryMax * 1.5; | ||
} | ||
primaryMax = Math.floor(primaryMax); | ||
secondaryMax = Math.floor(secondaryMax); | ||
var radiusFn; | ||
if (this._size) { | ||
var domain = d3Array.extent(data, function (d) { return d.size; }); | ||
if (domain[0] === domain[1]) { | ||
domain[0] = 0; | ||
} | ||
radiusFn = scales.scaleLinear() | ||
.domain(domain) | ||
.rangeRound([3, d3Array.min([primaryMax, secondaryMax])]); | ||
var val = center.size; | ||
center.r = radiusFn(val); | ||
} | ||
else { | ||
radiusFn = scales.scaleLinear() | ||
.domain([1, 2]) | ||
.rangeRound([primaryMax, secondaryMax]); | ||
} | ||
secondaries.forEach(function (s) { | ||
s.ring = 2; | ||
var val = this$1._size ? s.size : 2; | ||
s.r = this$1._sizeMin ? d3Array.max([this$1._sizeMin, radiusFn(val)]) : this$1._sizeMax ? d3Array.min([this$1._sizeMax, radiusFn(val)]) : radiusFn(val); | ||
}); | ||
primaries.forEach(function (p) { | ||
p.ring = 1; | ||
var val = this$1._size ? p.size : 1; | ||
p.r = this$1._sizeMin ? d3Array.max([this$1._sizeMin, radiusFn(val)]) : this$1._sizeMax ? d3Array.min([this$1._sizeMax, radiusFn(val)]) : radiusFn(val); | ||
}); | ||
nodes = [center].concat(primaries).concat(secondaries); | ||
primaries.forEach(function (p) { | ||
var check = ["source", "target"]; | ||
var edge = p.edge; | ||
check.forEach(function (node) { | ||
edge[node] = nodes.find(function (n) { return n.id === edge[node].id; }); | ||
}); | ||
edges.push(edge); | ||
linkMap[p.id].forEach(function (edge) { | ||
var node = edge.source.id === p.id ? edge.target : edge.source; | ||
if (node.id !== center.id) { | ||
var target = secondaries.find(function (s) { return s.id === node.id; }); | ||
if (!target) { | ||
target = primaries.find(function (s) { return s.id === node.id; }); | ||
} | ||
if (target) { | ||
edge.spline = true; | ||
var centerX = width / 2; | ||
var centerY = height / 2; | ||
var middleRing = primaryRing + (secondaryRing - primaryRing) * 0.5; | ||
var check = ["source", "target"]; | ||
check.forEach(function (node, i) { | ||
edge[(node + "X")] = edge[node].x + Math.cos(edge[node].ring === 2 ? edge[node].radians + Math.PI : edge[node].radians) * edge[node].r; | ||
edge[(node + "Y")] = edge[node].y + Math.sin(edge[node].ring === 2 ? edge[node].radians + Math.PI : edge[node].radians) * edge[node].r; | ||
edge[(node + "BisectX")] = centerX + middleRing * Math.cos(edge[node].radians); | ||
edge[(node + "BisectY")] = centerY + middleRing * Math.sin(edge[node].radians); | ||
edge[node] = nodes.find(function (n) { return n.id === edge[node].id; }); | ||
if (edge[node].edges === undefined) { edge[node].edges = {}; } | ||
var oppId = i === 0 ? edge.target.id : edge.source.id; | ||
if (edge[node].id === p.id) { | ||
edge[node].edges[oppId] = { | ||
angle: p.radians + Math.PI, | ||
radius: ringWidth / 2 | ||
}; | ||
} | ||
else { | ||
edge[node].edges[oppId] = { | ||
angle: target.radians, | ||
radius: ringWidth / 2 | ||
}; | ||
} | ||
}); | ||
edges.push(edge); | ||
} | ||
} | ||
}); | ||
}); | ||
nodes.forEach(function (node) { | ||
if (node.id !== this$1._center) { | ||
var fontSize = this$1._shapeConfig.labelConfig.fontSize && this$1._shapeConfig.labelConfig.fontSize(node) || 11; | ||
var lineHeight = fontSize * 1.4; | ||
var height = lineHeight * 2; | ||
var padding = 5; | ||
var width = ringWidth - node.r; | ||
var angle = node.radians * (180 / Math.PI); | ||
var x = node.r + padding; | ||
var textAnchor = "start"; | ||
if (angle < -90 || angle > 90) { | ||
x = -node.r - width - padding; | ||
textAnchor = "end"; | ||
angle += 180; | ||
} | ||
node.labelBounds = { | ||
x: x, | ||
y: -lineHeight / 2, | ||
width: width, | ||
height: height | ||
}; | ||
node.rotate = angle; | ||
node.textAnchor = textAnchor; | ||
} | ||
else { | ||
node.labelBounds = { | ||
x: -primaryRing / 2, | ||
y: -primaryRing / 2, | ||
width: primaryRing, | ||
height: primaryRing | ||
}; | ||
} | ||
}); | ||
this._linkLookup = links.reduce(function (obj, d) { | ||
if (!obj[d.source.id]) { obj[d.source.id] = []; } | ||
obj[d.source.id].push(d.target); | ||
if (!obj[d.target.id]) { obj[d.target.id] = []; } | ||
obj[d.target.id].push(d.source); | ||
return obj; | ||
}, {}); | ||
this._shapes.push(new shapes.Path() | ||
.config(d3plusCommon.configPrep.bind(this)(this._shapeConfig, "edge", "Path")) | ||
.id(function (d) { return ((d.source.id) + "_" + (d.target.id)); }) | ||
.d(function (d) { return d.spline ? ("M" + (d.sourceX) + "," + (d.sourceY) + "C" + (d.sourceBisectX) + "," + (d.sourceBisectY) + " " + (d.targetBisectX) + "," + (d.targetBisectY) + " " + (d.targetX) + "," + (d.targetY)) : ("M" + (d.source.x) + "," + (d.source.y) + " " + (d.target.x) + "," + (d.target.y)); }) | ||
.data(edges) | ||
.select(d3plusCommon.elem("g.d3plus-rings-links", {parent: this._select, transition: transition, enter: {transform: transform}, update: {transform: transform}}).node()) | ||
.render()); | ||
var that = this; | ||
var shapeConfig = { | ||
label: function (d) { return nodes.length <= this$1._labelCutoff || (this$1._hover && this$1._hover(d) || this$1._active && this$1._active(d)) ? this$1._drawLabel(d.data || d.node, d.i) : false; }, | ||
labelBounds: function (d) { return d.labelBounds; }, | ||
labelConfig: { | ||
fontColor: function (d) { return d.data.data.id === this$1._center ? d3plusCommon.configPrep.bind(that)(that._shapeConfig, "shape", d.key).labelConfig.fontColor(d) : d3plusColor.colorLegible(d3plusCommon.configPrep.bind(that)(that._shapeConfig, "shape", d.key).fill(d)); }, | ||
fontResize: function (d) { return d.data.data.id === this$1._center; }, | ||
padding: 0, | ||
textAnchor: function (d) { return nodeLookup[d.data.data.id].textAnchor || d3plusCommon.configPrep.bind(that)(that._shapeConfig, "shape", d.key).labelConfig.textAnchor; }, | ||
verticalAlign: function (d) { return d.data.data.id === this$1._center ? "middle" : "top"; } | ||
}, | ||
rotate: function (d) { return nodeLookup[d.id].rotate || 0; }, | ||
select: d3plusCommon.elem("g.d3plus-rings-nodes", {parent: this._select, transition: transition, enter: {transform: transform}, update: {transform: transform}}).node() | ||
}; | ||
d3Collection.nest().key(function (d) { return d.shape; }).entries(nodes).forEach(function (d) { | ||
this$1._shapes.push(new shapes[d.key]() | ||
.config(d3plusCommon.configPrep.bind(this$1)(this$1._shapeConfig, "shape", d.key)) | ||
.config(shapeConfig) | ||
.data(d.values) | ||
.render()); | ||
}); | ||
return this; | ||
}; | ||
/** | ||
@memberof Rings | ||
@desc Sets the center node to be the node with the given id. | ||
@param {String} | ||
@chainable | ||
*/ | ||
Rings.prototype.center = function center (_) { | ||
return arguments.length ? (this._center = _, this) : this._center; | ||
}; | ||
/** | ||
@memberof Rings | ||
@desc If *value* is specified, sets the hover method to the specified function and returns the current class instance. | ||
@param {Function} [*value*] | ||
@chainable | ||
*/ | ||
Rings.prototype.hover = function hover (_) { | ||
this._hover = _; | ||
this._shapes.forEach(function (s) { return s.hover(_); }); | ||
if (this._legend) { this._legendClass.hover(_); } | ||
return this; | ||
}; | ||
/** | ||
@memberof Rings | ||
@desc A predefined *Array* of edges that connect each object passed to the [node](#Rings.node) method. The `source` and `target` keys in each link need to map to the nodes in one of three ways: | ||
1. The index of the node in the nodes array (as in [this](http://d3plus.org/examples/d3plus-network/getting-started/) example). | ||
2. The actual node *Object* itself. | ||
3. A *String* value matching the `id` of the node. | ||
The value passed should either be an *Array* of data or a *String* representing a filepath or URL to be loaded. An optional formatting function can be passed as a second argument to this method. This custom function will be passed the data that has been loaded, as long as there are no errors. This function should return the final links *Array*. | ||
@param {Array|String} *links* = [] | ||
@param {Function} [*formatter*] | ||
@chainable | ||
*/ | ||
Rings.prototype.links = function links (_, f) { | ||
if (arguments.length) { | ||
var prev = this._queue.find(function (q) { return q[3] === "links"; }); | ||
var d = [d3plusViz.dataLoad.bind(this), _, f, "links"]; | ||
if (prev) { this._queue[this._queue.indexOf(prev)] = d; } | ||
else { this._queue.push(d); } | ||
return this; | ||
} | ||
return this._links; | ||
}; | ||
/** | ||
@memberof Rings | ||
@desc If *value* is specified, sets the node group accessor(s) to the specified string, function, or array of values and returns the current class instance. This method overrides the default .groupBy() function from being used with the data passed to .nodes(). If *value* is not specified, returns the current node group accessor. | ||
@param {String|Function|Array} [*value* = undefined] | ||
@chainable | ||
*/ | ||
Rings.prototype.nodeGroupBy = function nodeGroupBy (_) { | ||
var this$1 = this; | ||
if (!arguments.length) { return this._nodeGroupBy; } | ||
if (!(_ instanceof Array)) { _ = [_]; } | ||
return this._nodeGroupBy = _.map(function (k) { | ||
if (typeof k === "function") { return k; } | ||
else { | ||
if (!this$1._aggs[k]) { | ||
this$1._aggs[k] = function (a) { | ||
var v = Array.from(new Set(a)); | ||
return v.length === 1 ? v[0] : v; | ||
}; | ||
} | ||
return d3plusCommon.accessor(k); | ||
} | ||
}), this; | ||
}; | ||
/** | ||
@memberof Rings | ||
@desc The list of nodes to be used for drawing the rings network. The value passed should either be an *Array* of data or a *String* representing a filepath or URL to be loaded. | ||
Additionally, a custom formatting function can be passed as a second argument to this method. This custom function will be passed the data that has been loaded, as long as there are no errors. This function should return the final node *Array*. | ||
@param {Array|String} *nodes* = [] | ||
@param {Function} [*formatter*] | ||
@chainable | ||
*/ | ||
Rings.prototype.nodes = function nodes (_, f) { | ||
if (arguments.length) { | ||
var prev = this._queue.find(function (q) { return q[3] === "nodes"; }); | ||
var d = [d3plusViz.dataLoad.bind(this), _, f, "nodes"]; | ||
if (prev) { this._queue[this._queue.indexOf(prev)] = d; } | ||
else { this._queue.push(d); } | ||
return this; | ||
} | ||
return this._nodes; | ||
}; | ||
/** | ||
@memberof Rings | ||
@desc If *value* is specified, sets the size accessor to the specified function or data key and returns the current class instance. If *value* is not specified, returns the current size accessor. | ||
@param {Function|String} [*value*] | ||
@chainable | ||
*/ | ||
Rings.prototype.size = function size (_) { | ||
return arguments.length ? (this._size = typeof _ === "function" || !_ ? _ : d3plusCommon.accessor(_), this) : this._size; | ||
}; | ||
/** | ||
@memberof Rings | ||
@desc If *value* is specified, sets the size scale maximum to the specified number and returns the current class instance. If *value* is not specified, returns the current size scale maximum. By default, the maximum size is determined by half the distance of the two closest nodes. | ||
@param {Number} [*value*] | ||
@chainable | ||
*/ | ||
Rings.prototype.sizeMax = function sizeMax (_) { | ||
return arguments.length ? (this._sizeMax = _, this) : this._sizeMax; | ||
}; | ||
/** | ||
@memberof Rings | ||
@desc If *value* is specified, sets the size scale minimum to the specified number and returns the current class instance. If *value* is not specified, returns the current size scale minimum. | ||
@param {Number} [*value* = 5] | ||
@chainable | ||
*/ | ||
Rings.prototype.sizeMin = function sizeMin (_) { | ||
return arguments.length ? (this._sizeMin = _, this) : this._sizeMin; | ||
}; | ||
/** | ||
@memberof Rings | ||
@desc If *value* is specified, sets the size scale to the specified string and returns the current class instance. If *value* is not specified, returns the current size scale. | ||
@param {String} [*value* = "sqrt"] | ||
@chainable | ||
*/ | ||
Rings.prototype.sizeScale = function sizeScale (_) { | ||
return arguments.length ? (this._sizeScale = _, this) : this._sizeScale; | ||
}; | ||
return Rings; | ||
}(d3plusViz.Viz)); | ||
exports.Network = Network; | ||
exports.Rings = Rings; | ||
@@ -592,0 +1172,0 @@ Object.defineProperty(exports, '__esModule', { value: true }); |
/* | ||
d3plus-network v0.2.1 | ||
d3plus-network v0.3.0 | ||
Javascript network visualizations built upon d3 modules. | ||
@@ -7,2 +7,2 @@ Copyright (c) 2018 D3plus - https://d3plus.org | ||
*/ | ||
if(typeof Object.assign!=="function"){Object.defineProperty(Object,"assign",{value:function e(t){"use strict";if(t===null){throw new TypeError("Cannot convert undefined or null to object")}var r=Object(t);for(var n=1;n<arguments.length;n++){var i=arguments[n];if(i!==null){for(var o in i){if(Object.prototype.hasOwnProperty.call(i,o)){r[o]=i[o]}}}}return r},writable:true,configurable:true})}if(!Array.prototype.includes){Object.defineProperty(Array.prototype,"includes",{value:function e(t,r){var n=Object(this);var i=n.length>>>0;if(i===0)return false;var o=r|0;var s=Math.max(o>=0?o:i-Math.abs(o),0);function a(e,t){return e===t||typeof e==="number"&&typeof t==="number"&&isNaN(e)&&isNaN(t)}while(s<i){if(a(n[s],t)){return true}s++}return false}})}(function(e,t){typeof exports==="object"&&typeof module!=="undefined"?t(exports,require("d3-array"),require("d3-collection"),require("d3-scale"),require("d3-zoom"),require("d3plus-common"),require("d3plus-shape"),require("d3plus-viz")):typeof define==="function"&&define.amd?define("d3plus-network",["exports","d3-array","d3-collection","d3-scale","d3-zoom","d3plus-common","d3plus-shape","d3plus-viz"],t):t(e.d3plus={},e.d3Array,e.d3Collection,e.scales,e.d3Zoom,e.d3plusCommon,e.shapes,e.d3plusViz)})(this,function(e,L,D,P,c,S,T,o){"use strict";var t=function(j){function e(){var f=this;j.call(this);this._labelCutoff=100;this._links=[];this._noDataMessage=false;this._nodes=[];this._on["click.shape"]=function(e,t){f._tooltipClass.data([]).render();if(f._hover&&f._drawDepth>=f._groupBy.length-1){if(f._focus&&f._focus===e.id){f.active(false);f._on.mouseenter.bind(f)(e,t);f._focus=undefined;f._zoomToBounds(null)}else{f.hover(false);var r=f._nodeGroupBy&&f._nodeGroupBy[f._drawDepth](e,t)?f._nodeGroupBy[f._drawDepth](e,t):f._id(e,t),n=f._linkLookup[r],i=f._nodeLookup[r];var o=[i.id];var s=[i.x-i.r,i.x+i.r],a=[i.y-i.r,i.y+i.r];n.forEach(function(e){o.push(e.id);if(e.x-e.r<s[0]){s[0]=e.x-e.r}if(e.x+e.r>s[1]){s[1]=e.x+e.r}if(e.y-e.r<a[0]){a[0]=e.y-e.r}if(e.y+e.r>a[1]){a[1]=e.y+e.r}});f.active(function(e,t){if(e.source&&e.target){return e.source.id===i.id||e.target.id===i.id}else{return o.includes(f._ids(e,t)[f._drawDepth])}});f._focus=e.id;var u=c.zoomTransform(f._container.node());s=s.map(function(e){return e*u.k+u.x});a=a.map(function(e){return e*u.k+u.y});f._zoomToBounds([[s[0],a[0]],[s[1],a[1]]])}}};this._on["click.legend"]=function(e,t){var r=f._id(e);var n=f._ids(e);n=n[n.length-1];if(f._hover&&f._drawDepth>=f._groupBy.length-1){if(f._focus&&f._focus===r){f.active(false);f._on.mouseenter.bind(f)(e,t);f._focus=undefined;f._zoomToBounds(null)}else{f.hover(false);var i=r.map(function(e){return f._nodeLookup[e]});var o=[n];var s=[i[0].x-i[0].r,i[0].x+i[0].r],a=[i[0].y-i[0].r,i[0].y+i[0].r];i.forEach(function(e){o.push(e.id);if(e.x-e.r<s[0]){s[0]=e.x-e.r}if(e.x+e.r>s[1]){s[1]=e.x+e.r}if(e.y-e.r<a[0]){a[0]=e.y-e.r}if(e.y+e.r>a[1]){a[1]=e.y+e.r}});f.active(function(e,t){if(e.source&&e.target){return o.includes(e.source.id)&&o.includes(e.target.id)}else{var r=f._ids(e,t);return o.includes(r[r.length-1])}});f._focus=r;var u=c.zoomTransform(f._container.node());s=s.map(function(e){return e*u.k+u.x});a=a.map(function(e){return e*u.k+u.y});f._zoomToBounds([[s[0],a[0]],[s[1],a[1]]])}f._on["mousemove.legend"].bind(f)(e,t)}};this._sizeMin=5;this._sizeScale="sqrt";this._shape=S.constant("Circle");this._shapeConfig=S.assign(this._shapeConfig,{labelConfig:{duration:0,fontMin:1,fontResize:true,labelPadding:0,textAnchor:"middle",verticalAlign:"middle"},Path:{fill:"none",label:false,stroke:"#eee",strokeWidth:1}});this._x=S.accessor("x");this._y=S.accessor("y");this._zoom=true}if(j)e.__proto__=j;e.prototype=Object.create(j&&j.prototype);e.prototype.constructor=e;e.prototype._draw=function e(t){var i=this;j.prototype._draw.call(this,t);var r=this._height-this._margin.top-this._margin.bottom,n="translate("+this._margin.left+", "+this._margin.top+")",o=this._transition,s=this._width-this._margin.left-this._margin.right;var a=this._filteredData.reduce(function(e,t,r){e[i._id(t,r)]=t;return e},{});var u=this._nodes.reduce(function(e,t,r){e[i._nodeGroupBy?i._nodeGroupBy[i._drawDepth](t,r):i._id(t,r)]=t;return e},{});u=Array.from(new Set(Object.keys(a).concat(Object.keys(u)))).map(function(e,t){var r=a[e],n=u[e];if(n===undefined){return false}return{__d3plus__:true,data:r||n,i:t,id:e,fx:r!==undefined&&i._x(r)!==undefined?i._x(r):i._x(n),fy:r!==undefined&&i._y(r)!==undefined?i._y(r):i._y(n),node:n,r:i._size?r!==undefined&&i._size(r)!==undefined?i._size(r):i._size(n):i._sizeMin,shape:r!==undefined&&i._shape(r)!==undefined?i._shape(r):i._shape(n)}}).filter(function(e){return e});var f=L.extent(u.map(function(e){return e.fx})),c=L.extent(u.map(function(e){return e.fy}));var d=P.scaleLinear().domain(f).range([0,s]),h=P.scaleLinear().domain(c).range([0,r]);var l=(f[1]-f[0])/(c[1]-c[0]),_=s/r;if(l>_){var p=r*_/l;h.range([(r-p)/2,r-(r-p)/2])}else{var y=s*l/_;d.range([(s-y)/2,s-(s-y)/2])}u.forEach(function(e){e.x=d(e.fx);e.y=h(e.fy)});var g=L.extent(u.map(function(e){return e.r}));var m=this._sizeMax||L.min(L.merge(u.map(function(t){return u.map(function(e){return t===e?null:T.pointDistance([t.x,t.y],[e.x,e.y])})})))/2;var v=P["scale"+this._sizeScale.charAt(0).toUpperCase()+this._sizeScale.slice(1)]().domain(g).range([g[0]===g[1]?m:L.min([m/2,this._sizeMin]),m]),x=d.domain(),z=h.domain();var k=x[1]-x[0],b=z[1]-z[0];u.forEach(function(e){var t=v(e.r);if(x[0]>d.invert(e.x-t)){x[0]=d.invert(e.x-t)}if(x[1]<d.invert(e.x+t)){x[1]=d.invert(e.x+t)}if(z[0]>h.invert(e.y-t)){z[0]=h.invert(e.y-t)}if(z[1]<h.invert(e.y+t)){z[1]=h.invert(e.y+t)}});var w=x[1]-x[0],C=z[1]-z[0];m*=L.min([k/w,b/C]);v.range([g[0]===g[1]?m:L.min([m/2,this._sizeMin]),m]);d.domain(x);h.domain(z);u.forEach(function(e){e.x=d(e.fx);e.fx=e.x;e.y=h(e.fy);e.fy=e.y;e.r=v(e.r);e.width=e.r*2;e.height=e.r*2});var M=this._nodeLookup=u.reduce(function(e,t){e[t.id]=t;return e},{});var q=u.map(function(e){return e.node});var O=this._links.map(function(e){return{source:typeof e.source==="number"?u[q.indexOf(i._nodes[e.source])]:M[e.source.id],target:typeof e.target==="number"?u[q.indexOf(i._nodes[e.target])]:M[e.target.id]}});this._linkLookup=O.reduce(function(e,t){if(!e[t.source.id]){e[t.source.id]=[]}e[t.source.id].push(t.target);if(!e[t.target.id]){e[t.target.id]=[]}e[t.target.id].push(t.source);return e},{});this._container=this._select.selectAll("svg.d3plus-network").data([0]);this._container=this._container.enter().append("svg").attr("class","d3plus-network").attr("opacity",0).attr("width",s).attr("height",r).attr("x",this._margin.left).attr("y",this._margin.top).style("background-color","transparent").merge(this._container);this._container.transition(this._transition).attr("opacity",1).attr("width",s).attr("height",r).attr("x",this._margin.left).attr("y",this._margin.top);var B=this._container.selectAll("rect.d3plus-network-hitArea").data([0]);B.enter().append("rect").attr("class","d3plus-network-hitArea").merge(B).attr("width",s).attr("height",r).attr("fill","transparent").on("click",function(){if(i._focus){i.active(false);i._focus=undefined;i._zoomToBounds(null)}});this._zoomGroup=this._container.selectAll("g.d3plus-network-zoomGroup").data([0]);var A=this._zoomGroup=this._zoomGroup.enter().append("g").attr("class","d3plus-network-zoomGroup").merge(this._zoomGroup);this._shapes.push((new T.Path).config(this._shapeConfig).config(this._shapeConfig.Path).d(function(e){return"M"+e.source.x+","+e.source.y+" "+e.target.x+","+e.target.y}).data(O).select(S.elem("g.d3plus-network-links",{parent:A,transition:o,enter:{transform:n},update:{transform:n}}).node()).render());var G={label:function(e){return u.length<=i._labelCutoff||(i._hover&&i._hover(e)||i._active&&i._active(e))?i._drawLabel(e.data||e.node,e.i):false},select:S.elem("g.d3plus-network-nodes",{parent:A,transition:o,enter:{transform:n},update:{transform:n}}).node()};D.nest().key(function(e){return e.shape}).entries(u).forEach(function(e){i._shapes.push((new T[e.key]).config(S.configPrep.bind(i)(i._shapeConfig,"shape",e.key)).config(G).config(G[e.key]||{}).data(e.values).render())});return this};e.prototype.labelCutoff=function e(t){return arguments.length?(this._labelCutoff=t,this):this._labelCutoff};e.prototype.links=function e(t,r){if(arguments.length){var n=this._queue.find(function(e){return e[3]==="links"});var i=[o.dataLoad.bind(this),t,r,"links"];if(n){this._queue[this._queue.indexOf(n)]=i}else{this._queue.push(i)}return this}return this._links};e.prototype.nodeGroupBy=function e(t){var r=this;if(!arguments.length){return this._nodeGroupBy}if(!(t instanceof Array)){t=[t]}return this._nodeGroupBy=t.map(function(e){if(typeof e==="function"){return e}else{if(!r._aggs[e]){r._aggs[e]=function(e){var t=Array.from(new Set(e));return t.length===1?t[0]:t}}return S.accessor(e)}}),this};e.prototype.nodes=function e(t,r){if(arguments.length){var n=this._queue.find(function(e){return e[3]==="nodes"});var i=[o.dataLoad.bind(this),t,r,"nodes"];if(n){this._queue[this._queue.indexOf(n)]=i}else{this._queue.push(i)}return this}return this._nodes};e.prototype.size=function e(t){return arguments.length?(this._size=typeof t==="function"||!t?t:S.accessor(t),this):this._size};e.prototype.sizeMax=function e(t){return arguments.length?(this._sizeMax=t,this):this._sizeMax};e.prototype.sizeMin=function e(t){return arguments.length?(this._sizeMin=t,this):this._sizeMin};e.prototype.sizeScale=function e(t){return arguments.length?(this._sizeScale=t,this):this._sizeScale};e.prototype.x=function e(t){if(arguments.length){if(typeof t==="function"){this._x=t}else{this._x=S.accessor(t);if(!this._aggs[t]){this._aggs[t]=function(e){return L.mean(e)}}}return this}else{return this._x}};e.prototype.y=function e(t){if(arguments.length){if(typeof t==="function"){this._y=t}else{this._y=S.accessor(t);if(!this._aggs[t]){this._aggs[t]=function(e){return L.mean(e)}}}return this}else{return this._y}};return e}(o.Viz);e.Network=t;Object.defineProperty(e,"__esModule",{value:true})}); | ||
if(typeof Object.assign!=="function"){Object.defineProperty(Object,"assign",{value:function e(t){"use strict";if(t===null){throw new TypeError("Cannot convert undefined or null to object")}var r=Object(t);for(var i=1;i<arguments.length;i++){var n=arguments[i];if(n!==null){for(var o in n){if(Object.prototype.hasOwnProperty.call(n,o)){r[o]=n[o]}}}}return r},writable:true,configurable:true})}if(!Array.prototype.includes){Object.defineProperty(Array.prototype,"includes",{value:function e(t,r){var i=Object(this);var n=i.length>>>0;if(n===0)return false;var o=r|0;var s=Math.max(o>=0?o:n-Math.abs(o),0);function a(e,t){return e===t||typeof e==="number"&&typeof t==="number"&&isNaN(e)&&isNaN(t)}while(s<n){if(a(i[s],t)){return true}s++}return false}})}(function(e,t){typeof exports==="object"&&typeof module!=="undefined"?t(exports,require("d3-array"),require("d3-collection"),require("d3-scale"),require("d3-zoom"),require("d3plus-common"),require("d3plus-shape"),require("d3plus-viz"),require("d3plus-color")):typeof define==="function"&&define.amd?define("d3plus-network",["exports","d3-array","d3-collection","d3-scale","d3-zoom","d3plus-common","d3plus-shape","d3plus-viz","d3plus-color"],t):t(e.d3plus={},e.d3Array,e.d3Collection,e.scales,e.d3Zoom,e.d3plusCommon,e.shapes,e.d3plusViz,e.d3plusColor)})(this,function(e,j,S,D,d,T,R,o,X){"use strict";var t=function(G){function e(){var f=this;G.call(this);this._labelCutoff=100;this._links=[];this._noDataMessage=false;this._nodes=[];this._on["click.shape"]=function(e,t){f._tooltipClass.data([]).render();if(f._hover&&f._drawDepth>=f._groupBy.length-1){if(f._focus&&f._focus===e.id){f.active(false);f._on.mouseenter.bind(f)(e,t);f._focus=undefined;f._zoomToBounds(null)}else{f.hover(false);var r=f._nodeGroupBy&&f._nodeGroupBy[f._drawDepth](e,t)?f._nodeGroupBy[f._drawDepth](e,t):f._id(e,t),i=f._linkLookup[r],n=f._nodeLookup[r];var o=[n.id];var s=[n.x-n.r,n.x+n.r],a=[n.y-n.r,n.y+n.r];i.forEach(function(e){o.push(e.id);if(e.x-e.r<s[0]){s[0]=e.x-e.r}if(e.x+e.r>s[1]){s[1]=e.x+e.r}if(e.y-e.r<a[0]){a[0]=e.y-e.r}if(e.y+e.r>a[1]){a[1]=e.y+e.r}});f.active(function(e,t){if(e.source&&e.target){return e.source.id===n.id||e.target.id===n.id}else{return o.includes(f._ids(e,t)[f._drawDepth])}});f._focus=e.id;var u=d.zoomTransform(f._container.node());s=s.map(function(e){return e*u.k+u.x});a=a.map(function(e){return e*u.k+u.y});f._zoomToBounds([[s[0],a[0]],[s[1],a[1]]])}}};this._on["click.legend"]=function(e,t){var r=f._id(e);var i=f._ids(e);i=i[i.length-1];if(f._hover&&f._drawDepth>=f._groupBy.length-1){if(f._focus&&f._focus===r){f.active(false);f._on.mouseenter.bind(f)(e,t);f._focus=undefined;f._zoomToBounds(null)}else{f.hover(false);var n=r.map(function(e){return f._nodeLookup[e]});var o=[i];var s=[n[0].x-n[0].r,n[0].x+n[0].r],a=[n[0].y-n[0].r,n[0].y+n[0].r];n.forEach(function(e){o.push(e.id);if(e.x-e.r<s[0]){s[0]=e.x-e.r}if(e.x+e.r>s[1]){s[1]=e.x+e.r}if(e.y-e.r<a[0]){a[0]=e.y-e.r}if(e.y+e.r>a[1]){a[1]=e.y+e.r}});f.active(function(e,t){if(e.source&&e.target){return o.includes(e.source.id)&&o.includes(e.target.id)}else{var r=f._ids(e,t);return o.includes(r[r.length-1])}});f._focus=r;var u=d.zoomTransform(f._container.node());s=s.map(function(e){return e*u.k+u.x});a=a.map(function(e){return e*u.k+u.y});f._zoomToBounds([[s[0],a[0]],[s[1],a[1]]])}f._on["mousemove.legend"].bind(f)(e,t)}};this._sizeMin=5;this._sizeScale="sqrt";this._shape=T.constant("Circle");this._shapeConfig=T.assign(this._shapeConfig,{labelConfig:{duration:0,fontMin:1,fontResize:true,labelPadding:0,textAnchor:"middle",verticalAlign:"middle"},Path:{fill:"none",label:false,stroke:"#eee",strokeWidth:1}});this._x=T.accessor("x");this._y=T.accessor("y");this._zoom=true}if(G)e.__proto__=G;e.prototype=Object.create(G&&G.prototype);e.prototype.constructor=e;e.prototype._draw=function e(t){var n=this;G.prototype._draw.call(this,t);var r=this._height-this._margin.top-this._margin.bottom,i="translate("+this._margin.left+", "+this._margin.top+")",o=this._transition,s=this._width-this._margin.left-this._margin.right;var a=this._filteredData.reduce(function(e,t,r){e[n._id(t,r)]=t;return e},{});var u=this._nodes.reduce(function(e,t,r){e[n._nodeGroupBy?n._nodeGroupBy[n._drawDepth](t,r):n._id(t,r)]=t;return e},{});u=Array.from(new Set(Object.keys(a).concat(Object.keys(u)))).map(function(e,t){var r=a[e],i=u[e];if(i===undefined){return false}return{__d3plus__:true,data:r||i,i:t,id:e,fx:r!==undefined&&n._x(r)!==undefined?n._x(r):n._x(i),fy:r!==undefined&&n._y(r)!==undefined?n._y(r):n._y(i),node:i,r:n._size?r!==undefined&&n._size(r)!==undefined?n._size(r):n._size(i):n._sizeMin,shape:r!==undefined&&n._shape(r)!==undefined?n._shape(r):n._shape(i)}}).filter(function(e){return e});var f=j.extent(u.map(function(e){return e.fx})),d=j.extent(u.map(function(e){return e.fy}));var c=D.scaleLinear().domain(f).range([0,s]),h=D.scaleLinear().domain(d).range([0,r]);var l=(f[1]-f[0])/(d[1]-d[0]),_=s/r;if(l>_){var p=r*_/l;h.range([(r-p)/2,r-(r-p)/2])}else{var g=s*l/_;c.range([(s-g)/2,s-(s-g)/2])}u.forEach(function(e){e.x=c(e.fx);e.y=h(e.fy)});var v=j.extent(u.map(function(e){return e.r}));var y=this._sizeMax||j.min(j.merge(u.map(function(t){return u.map(function(e){return t===e?null:R.pointDistance([t.x,t.y],[e.x,e.y])})})))/2;var m=D["scale"+this._sizeScale.charAt(0).toUpperCase()+this._sizeScale.slice(1)]().domain(v).range([v[0]===v[1]?y:j.min([y/2,this._sizeMin]),y]),x=c.domain(),z=h.domain();var b=x[1]-x[0],k=z[1]-z[0];u.forEach(function(e){var t=m(e.r);if(x[0]>c.invert(e.x-t)){x[0]=c.invert(e.x-t)}if(x[1]<c.invert(e.x+t)){x[1]=c.invert(e.x+t)}if(z[0]>h.invert(e.y-t)){z[0]=h.invert(e.y-t)}if(z[1]<h.invert(e.y+t)){z[1]=h.invert(e.y+t)}});var M=x[1]-x[0],w=z[1]-z[0];y*=j.min([b/M,k/w]);m.range([v[0]===v[1]?y:j.min([y/2,this._sizeMin]),y]);c.domain(x);h.domain(z);u.forEach(function(e){e.x=c(e.fx);e.fx=e.x;e.y=h(e.fy);e.fy=e.y;e.r=m(e.r);e.width=e.r*2;e.height=e.r*2});var C=this._nodeLookup=u.reduce(function(e,t){e[t.id]=t;return e},{});var B=u.map(function(e){return e.node});var q=this._links.map(function(e){return{source:typeof e.source==="number"?u[B.indexOf(n._nodes[e.source])]:C[e.source.id],target:typeof e.target==="number"?u[B.indexOf(n._nodes[e.target])]:C[e.target.id]}});this._linkLookup=q.reduce(function(e,t){if(!e[t.source.id]){e[t.source.id]=[]}e[t.source.id].push(t.target);if(!e[t.target.id]){e[t.target.id]=[]}e[t.target.id].push(t.source);return e},{});this._container=this._select.selectAll("svg.d3plus-network").data([0]);this._container=this._container.enter().append("svg").attr("class","d3plus-network").attr("opacity",0).attr("width",s).attr("height",r).attr("x",this._margin.left).attr("y",this._margin.top).style("background-color","transparent").merge(this._container);this._container.transition(this._transition).attr("opacity",1).attr("width",s).attr("height",r).attr("x",this._margin.left).attr("y",this._margin.top);var A=this._container.selectAll("rect.d3plus-network-hitArea").data([0]);A.enter().append("rect").attr("class","d3plus-network-hitArea").merge(A).attr("width",s).attr("height",r).attr("fill","transparent").on("click",function(){if(n._focus){n.active(false);n._focus=undefined;n._zoomToBounds(null)}});this._zoomGroup=this._container.selectAll("g.d3plus-network-zoomGroup").data([0]);var P=this._zoomGroup=this._zoomGroup.enter().append("g").attr("class","d3plus-network-zoomGroup").merge(this._zoomGroup);this._shapes.push((new R.Path).config(this._shapeConfig).config(this._shapeConfig.Path).d(function(e){return"M"+e.source.x+","+e.source.y+" "+e.target.x+","+e.target.y}).data(q).select(T.elem("g.d3plus-network-links",{parent:P,transition:o,enter:{transform:i},update:{transform:i}}).node()).render());var E={label:function(e){return u.length<=n._labelCutoff||(n._hover&&n._hover(e)||n._active&&n._active(e))?n._drawLabel(e.data||e.node,e.i):false},select:T.elem("g.d3plus-network-nodes",{parent:P,transition:o,enter:{transform:i},update:{transform:i}}).node()};S.nest().key(function(e){return e.shape}).entries(u).forEach(function(e){n._shapes.push((new R[e.key]).config(T.configPrep.bind(n)(n._shapeConfig,"shape",e.key)).config(E).config(E[e.key]||{}).data(e.values).render())});return this};e.prototype.labelCutoff=function e(t){return arguments.length?(this._labelCutoff=t,this):this._labelCutoff};e.prototype.links=function e(t,r){if(arguments.length){var i=this._queue.find(function(e){return e[3]==="links"});var n=[o.dataLoad.bind(this),t,r,"links"];if(i){this._queue[this._queue.indexOf(i)]=n}else{this._queue.push(n)}return this}return this._links};e.prototype.nodeGroupBy=function e(t){var r=this;if(!arguments.length){return this._nodeGroupBy}if(!(t instanceof Array)){t=[t]}return this._nodeGroupBy=t.map(function(e){if(typeof e==="function"){return e}else{if(!r._aggs[e]){r._aggs[e]=function(e){var t=Array.from(new Set(e));return t.length===1?t[0]:t}}return T.accessor(e)}}),this};e.prototype.nodes=function e(t,r){if(arguments.length){var i=this._queue.find(function(e){return e[3]==="nodes"});var n=[o.dataLoad.bind(this),t,r,"nodes"];if(i){this._queue[this._queue.indexOf(i)]=n}else{this._queue.push(n)}return this}return this._nodes};e.prototype.size=function e(t){return arguments.length?(this._size=typeof t==="function"||!t?t:T.accessor(t),this):this._size};e.prototype.sizeMax=function e(t){return arguments.length?(this._sizeMax=t,this):this._sizeMax};e.prototype.sizeMin=function e(t){return arguments.length?(this._sizeMin=t,this):this._sizeMin};e.prototype.sizeScale=function e(t){return arguments.length?(this._sizeScale=t,this):this._sizeScale};e.prototype.x=function e(t){if(arguments.length){if(typeof t==="function"){this._x=t}else{this._x=T.accessor(t);if(!this._aggs[t]){this._aggs[t]=function(e){return j.mean(e)}}}return this}else{return this._x}};e.prototype.y=function e(t){if(arguments.length){if(typeof t==="function"){this._y=t}else{this._y=T.accessor(t);if(!this._aggs[t]){this._aggs[t]=function(e){return j.mean(e)}}}return this}else{return this._y}};return e}(o.Viz);var r=function(L){function e(){var u=this;L.call(this);this._labelCutoff=100;this._links=[];this._noDataMessage=false;this._nodes=[];this._on.mouseenter=function(){};this._on["mouseleave.shape"]=function(){u.hover(false)};this._on["mousemove.shape"]=function(e,t){if(u._focus&&u._focus===e.id){u.hover(false);u._on.mouseenter.bind(u)(e,t);u._focus=undefined}else{var r=u._nodeGroupBy&&u._nodeGroupBy[u._drawDepth](e,t)?u._nodeGroupBy[u._drawDepth](e,t):u._id(e,t),i=u._linkLookup[r],n=u._nodeLookup[r];var o=[n.id];var s=[n.x-n.r,n.x+n.r],a=[n.y-n.r,n.y+n.r];i.forEach(function(e){o.push(e.id);if(e.x-e.r<s[0]){s[0]=e.x-e.r}if(e.x+e.r>s[1]){s[1]=e.x+e.r}if(e.y-e.r<a[0]){a[0]=e.y-e.r}if(e.y+e.r>a[1]){a[1]=e.y+e.r}});u.hover(function(e,t){if(e.source&&e.target){return e.source.id===n.id||e.target.id===n.id}else{return o.includes(u._ids(e,t)[u._drawDepth])}})}};this._on["click.shape"]=function(e){u._center=e.id;u._draw()};this._sizeMin=5;this._sizeScale="sqrt";this._shape=T.constant("Circle");this._shapeConfig=T.assign(this._shapeConfig,{labelConfig:{duration:0,fontMin:1,fontResize:true,labelPadding:0,textAnchor:"middle",verticalAlign:"middle"},Path:{fill:"none",label:false,stroke:"#eee",strokeWidth:1}})}if(L)e.__proto__=L;e.prototype=Object.create(L&&L.prototype);e.prototype.constructor=e;e.prototype._draw=function e(t){var f=this;L.prototype._draw.call(this,t);var n=this._filteredData.reduce(function(e,t,r){e[f._id(t,r)]=t;return e},{});var d=this._nodes;if(!this._nodes.length&&this._links.length){var r=Array.from(new Set(this._links.reduce(function(e,t){return e.concat([t.source,t.target])},[])));d=r.map(function(e){return typeof e==="object"?e:{id:e}})}d=d.reduce(function(e,t,r){e[f._nodeGroupBy?f._nodeGroupBy[f._drawDepth](t,r):f._id(t,r)]=t;return e},{});d=Array.from(new Set(Object.keys(n).concat(Object.keys(d)))).map(function(e,t){var r=n[e],i=d[e];if(i===undefined){return false}return{__d3plus__:true,data:r||i,i:t,id:e,node:i,shape:r!==undefined&&f._shape(r)!==undefined?f._shape(r):f._shape(i)}}).filter(function(e){return e});var i=this._nodeLookup=d.reduce(function(e,t){e[t.id]=t;return e},{});var o=this._links.map(function(r){var e=["source","target"];return e.reduce(function(e,t){e[t]=typeof r[t]==="number"?d[r[t]]:i[r[t].id||r[t]];return e},{})});var s=o.reduce(function(e,t){if(!e[t.source.id]){e[t.source.id]=[]}e[t.source.id].push(t);if(!e[t.target.id]){e[t.target.id]=[]}e[t.target.id].push(t);return e},{});var c=this._height-this._margin.top-this._margin.bottom,a="translate("+this._margin.left+", "+this._margin.top+")",u=this._transition,h=this._width-this._margin.left-this._margin.right;var l=[],_=j.min([c,h])/2,p=_/3;var g=p,v=p*2;var y=i[this._center];y.x=h/2;y.y=c/2;y.r=this._sizeMin?j.max([this._sizeMin,g*.65]):this._sizeMax?j.min([this._sizeMax,g*.65]):g*.65;var m=[y],x=[];s[this._center].forEach(function(e){var t=e.source.id===f._center?e.target:e.source;t.edges=s[t.id].filter(function(e){return e.source.id!==f._center||e.target.id!==f._center});t.edge=e;m.push(t);x.push(t)});x.sort(function(e,t){return e.edges.length-t.edges.length});var z=[];var b=0;x.forEach(function(e){var n=e.id;e.edges=e.edges.filter(function(e){return!m.includes(e.source)&&e.target.id===n||!m.includes(e.target)&&e.source.id===n});b+=e.edges.length||1;e.edges.forEach(function(e){var t=e.source;var r=e.target;var i=r.id===n?t:r;m.push(i)})});var k=Math.PI*2;var M=0;x.forEach(function(o,e){var s=o.edges.length||1;var t=k/b*s;if(e===0){M-=t/2}var a=M+t/2-k/4;o.radians=a;o.x=h/2+g*Math.cos(a);o.y=c/2+g*Math.sin(a);M+=t;o.edges.forEach(function(e,t){var r=e.source.id===o.id?e.target:e.source;var i=k/b;var n=a-i*s/2+i/2+i*t;r.radians=n;r.x=h/2+v*Math.cos(n);r.y=c/2+v*Math.sin(n);z.push(r)})});var w=p/2;var C=p/4;var B=w/2-4;if(w/2-4<8){B=j.min([w/2,8])}var q=C/2-4;if(C/2-4<4){q=j.min([C/2,4])}if(q>p/10){q=p/10}if(q>B&&q>10){q=B*.75}if(B>q*1.5){B=q*1.5}B=Math.floor(B);q=Math.floor(q);var A;if(this._size){var P=j.extent(n,function(e){return e.size});if(P[0]===P[1]){P[0]=0}A=D.scaleLinear().domain(P).rangeRound([3,j.min([B,q])]);var E=y.size;y.r=A(E)}else{A=D.scaleLinear().domain([1,2]).rangeRound([B,q])}z.forEach(function(e){e.ring=2;var t=f._size?e.size:2;e.r=f._sizeMin?j.max([f._sizeMin,A(t)]):f._sizeMax?j.min([f._sizeMax,A(t)]):A(t)});x.forEach(function(e){e.ring=1;var t=f._size?e.size:1;e.r=f._sizeMin?j.max([f._sizeMin,A(t)]):f._sizeMax?j.min([f._sizeMax,A(t)]):A(t)});d=[y].concat(x).concat(z);x.forEach(function(u){var e=["source","target"];var r=u.edge;e.forEach(function(t){r[t]=d.find(function(e){return e.id===r[t].id})});l.push(r);s[u.id].forEach(function(i){var t=i.source.id===u.id?i.target:i.source;if(t.id!==y.id){var n=z.find(function(e){return e.id===t.id});if(!n){n=x.find(function(e){return e.id===t.id})}if(n){i.spline=true;var o=h/2;var s=c/2;var a=g+(v-g)*.5;var e=["source","target"];e.forEach(function(t,e){i[t+"X"]=i[t].x+Math.cos(i[t].ring===2?i[t].radians+Math.PI:i[t].radians)*i[t].r;i[t+"Y"]=i[t].y+Math.sin(i[t].ring===2?i[t].radians+Math.PI:i[t].radians)*i[t].r;i[t+"BisectX"]=o+a*Math.cos(i[t].radians);i[t+"BisectY"]=s+a*Math.sin(i[t].radians);i[t]=d.find(function(e){return e.id===i[t].id});if(i[t].edges===undefined){i[t].edges={}}var r=e===0?i.target.id:i.source.id;if(i[t].id===u.id){i[t].edges[r]={angle:u.radians+Math.PI,radius:p/2}}else{i[t].edges[r]={angle:n.radians,radius:p/2}}});l.push(i)}}})});d.forEach(function(e){if(e.id!==f._center){var t=f._shapeConfig.labelConfig.fontSize&&f._shapeConfig.labelConfig.fontSize(e)||11;var r=t*1.4;var i=r*2;var n=5;var o=p-e.r;var s=e.radians*(180/Math.PI);var a=e.r+n;var u="start";if(s<-90||s>90){a=-e.r-o-n;u="end";s+=180}e.labelBounds={x:a,y:-r/2,width:o,height:i};e.rotate=s;e.textAnchor=u}else{e.labelBounds={x:-g/2,y:-g/2,width:g,height:g}}});this._linkLookup=o.reduce(function(e,t){if(!e[t.source.id]){e[t.source.id]=[]}e[t.source.id].push(t.target);if(!e[t.target.id]){e[t.target.id]=[]}e[t.target.id].push(t.source);return e},{});this._shapes.push((new R.Path).config(T.configPrep.bind(this)(this._shapeConfig,"edge","Path")).id(function(e){return e.source.id+"_"+e.target.id}).d(function(e){return e.spline?"M"+e.sourceX+","+e.sourceY+"C"+e.sourceBisectX+","+e.sourceBisectY+" "+e.targetBisectX+","+e.targetBisectY+" "+e.targetX+","+e.targetY:"M"+e.source.x+","+e.source.y+" "+e.target.x+","+e.target.y}).data(l).select(T.elem("g.d3plus-rings-links",{parent:this._select,transition:u,enter:{transform:a},update:{transform:a}}).node()).render());var G=this;var O={label:function(e){return d.length<=f._labelCutoff||(f._hover&&f._hover(e)||f._active&&f._active(e))?f._drawLabel(e.data||e.node,e.i):false},labelBounds:function(e){return e.labelBounds},labelConfig:{fontColor:function(e){return e.data.data.id===f._center?T.configPrep.bind(G)(G._shapeConfig,"shape",e.key).labelConfig.fontColor(e):X.colorLegible(T.configPrep.bind(G)(G._shapeConfig,"shape",e.key).fill(e))},fontResize:function(e){return e.data.data.id===f._center},padding:0,textAnchor:function(e){return i[e.data.data.id].textAnchor||T.configPrep.bind(G)(G._shapeConfig,"shape",e.key).labelConfig.textAnchor},verticalAlign:function(e){return e.data.data.id===f._center?"middle":"top"}},rotate:function(e){return i[e.id].rotate||0},select:T.elem("g.d3plus-rings-nodes",{parent:this._select,transition:u,enter:{transform:a},update:{transform:a}}).node()};S.nest().key(function(e){return e.shape}).entries(d).forEach(function(e){f._shapes.push((new R[e.key]).config(T.configPrep.bind(f)(f._shapeConfig,"shape",e.key)).config(O).data(e.values).render())});return this};e.prototype.center=function e(t){return arguments.length?(this._center=t,this):this._center};e.prototype.hover=function e(t){this._hover=t;this._shapes.forEach(function(e){return e.hover(t)});if(this._legend){this._legendClass.hover(t)}return this};e.prototype.links=function e(t,r){if(arguments.length){var i=this._queue.find(function(e){return e[3]==="links"});var n=[o.dataLoad.bind(this),t,r,"links"];if(i){this._queue[this._queue.indexOf(i)]=n}else{this._queue.push(n)}return this}return this._links};e.prototype.nodeGroupBy=function e(t){var r=this;if(!arguments.length){return this._nodeGroupBy}if(!(t instanceof Array)){t=[t]}return this._nodeGroupBy=t.map(function(e){if(typeof e==="function"){return e}else{if(!r._aggs[e]){r._aggs[e]=function(e){var t=Array.from(new Set(e));return t.length===1?t[0]:t}}return T.accessor(e)}}),this};e.prototype.nodes=function e(t,r){if(arguments.length){var i=this._queue.find(function(e){return e[3]==="nodes"});var n=[o.dataLoad.bind(this),t,r,"nodes"];if(i){this._queue[this._queue.indexOf(i)]=n}else{this._queue.push(n)}return this}return this._nodes};e.prototype.size=function e(t){return arguments.length?(this._size=typeof t==="function"||!t?t:T.accessor(t),this):this._size};e.prototype.sizeMax=function e(t){return arguments.length?(this._sizeMax=t,this):this._sizeMax};e.prototype.sizeMin=function e(t){return arguments.length?(this._sizeMin=t,this):this._sizeMin};e.prototype.sizeScale=function e(t){return arguments.length?(this._sizeScale=t,this):this._sizeScale};return e}(o.Viz);e.Network=t;e.Rings=r;Object.defineProperty(e,"__esModule",{value:true})}); |
export {default as Network} from "./src/Network"; | ||
export {default as Rings} from "./src/Rings"; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "d3plus-network", | ||
"version": "0.2.1", | ||
"version": "0.3.0", | ||
"description": "Javascript network visualizations built upon d3 modules.", | ||
@@ -29,5 +29,5 @@ "main": "build/d3plus-network.js", | ||
"d3-scale": "^2.0.0", | ||
"d3plus-common": "^0.6.34", | ||
"d3plus-shape": "^0.14.2", | ||
"d3plus-viz": "^0.11.5" | ||
"d3plus-common": "^0.6.35", | ||
"d3plus-shape": "^0.14.4", | ||
"d3plus-viz": "^0.11.8" | ||
}, | ||
@@ -34,0 +34,0 @@ "scripts": { |
130
README.md
# d3plus-network | ||
[![NPM Release](http://img.shields.io/npm/v/d3plus-network.svg?style=flat)](https://www.npmjs.org/package/d3plus-network) [![Build Status](https://travis-ci.org/d3plus/d3plus-network.svg?branch=master)](https://travis-ci.org/d3plus/d3plus-network) [![Dependency Status](http://img.shields.io/david/d3plus/d3plus-network.svg?style=flat)](https://david-dm.org/d3plus/d3plus-network) [![Gitter](https://img.shields.io/badge/-chat_on_gitter-brightgreen.svg?style=flat&logo=gitter-white)](https://gitter.im/d3plus/) [![1.0 progress](https://img.shields.io/badge/1.0_progress-0%25-red.svg?style=flat)](https://github.com/d3plus/d3plus-network/projects/1) | ||
[![NPM Release](http://img.shields.io/npm/v/d3plus-network.svg?style=flat)](https://www.npmjs.org/package/d3plus-network) [![Build Status](https://travis-ci.org/d3plus/d3plus-network.svg?branch=master)](https://travis-ci.org/d3plus/d3plus-network) [![Dependency Status](http://img.shields.io/david/d3plus/d3plus-network.svg?style=flat)](https://david-dm.org/d3plus/d3plus-network) [![Gitter](https://img.shields.io/badge/-chat_on_gitter-brightgreen.svg?style=flat&logo=gitter-white)](https://gitter.im/d3plus/) [![1.0 progress](https://img.shields.io/badge/1.0_progress-50%25-orange.svg?style=flat)](https://github.com/d3plus/d3plus-network/projects/1) | ||
@@ -12,3 +12,3 @@ Javascript network visualizations built upon d3 modules. | ||
```html | ||
<script src="https://d3plus.org/js/d3plus-network.v0.2.full.min.js"></script> | ||
<script src="https://d3plus.org/js/d3plus-network.v0.3.full.min.js"></script> | ||
``` | ||
@@ -63,5 +63,6 @@ | ||
### More Examples | ||
* [Simple Rings](http://d3plus.org/examples/d3plus-network/simple-rings/)<sup> ***New***</sup> | ||
## API Reference | ||
@@ -71,2 +72,3 @@ | ||
* [Network](#Network) | ||
* [Rings](#Rings) | ||
@@ -204,4 +206,124 @@ --- | ||
<a name="Rings"></a> | ||
#### **Rings** [<>](https://github.com/d3plus/d3plus-network/blob/master/src/Rings.js#L15) | ||
###### <sub>Documentation generated on Tue, 10 Apr 2018 13:38:43 GMT</sub> | ||
This is a global class, and extends all of the methods and functionality of [<code>Viz</code>](https://github.com/d3plus/d3plus-viz#Viz). | ||
* [Rings](#Rings) ⇐ [<code>Viz</code>](https://github.com/d3plus/d3plus-viz#Viz) | ||
* [new Rings()](#new_Rings_new) | ||
* [.center(_)](#Rings.center) ↩︎ | ||
* [.hover([*value*])](#Rings.hover) ↩︎ | ||
* [.links(*links*, [*formatter*])](#Rings.links) ↩︎ | ||
* [.nodeGroupBy([*value*])](#Rings.nodeGroupBy) ↩︎ | ||
* [.nodes(*nodes*, [*formatter*])](#Rings.nodes) ↩︎ | ||
* [.size([*value*])](#Rings.size) ↩︎ | ||
* [.sizeMax([*value*])](#Rings.sizeMax) ↩︎ | ||
* [.sizeMin([*value*])](#Rings.sizeMin) ↩︎ | ||
* [.sizeScale([*value*])](#Rings.sizeScale) ↩︎ | ||
<a name="new_Rings_new" href="#new_Rings_new">#</a> new **Rings**() | ||
Creates a ring visualization based on a defined set of nodes and edges. [Click here](http://d3plus.org/examples/d3plus-network/simple-rings/) for help getting started using the Rings class. | ||
<a name="Rings.center" href="#Rings.center">#</a> Rings.**center**(_) [<>](https://github.com/d3plus/d3plus-network/blob/master/src/Rings.js#L456) | ||
Sets the center node to be the node with the given id. | ||
This is a static method of [<code>Rings</code>](#Rings), and is chainable with other methods of this Class. | ||
<a name="Rings.hover" href="#Rings.hover">#</a> Rings.**hover**([*value*]) [<>](https://github.com/d3plus/d3plus-network/blob/master/src/Rings.js#L466) | ||
If *value* is specified, sets the hover method to the specified function and returns the current class instance. | ||
This is a static method of [<code>Rings</code>](#Rings), and is chainable with other methods of this Class. | ||
<a name="Rings.links" href="#Rings.links">#</a> Rings.**links**(*links*, [*formatter*]) [<>](https://github.com/d3plus/d3plus-network/blob/master/src/Rings.js#L487) | ||
A predefined *Array* of edges that connect each object passed to the [node](#Rings.node) method. The `source` and `target` keys in each link need to map to the nodes in one of three ways: | ||
1. The index of the node in the nodes array (as in [this](http://d3plus.org/examples/d3plus-network/getting-started/) example). | ||
2. The actual node *Object* itself. | ||
3. A *String* value matching the `id` of the node. | ||
The value passed should either be an *Array* of data or a *String* representing a filepath or URL to be loaded. An optional formatting function can be passed as a second argument to this method. This custom function will be passed the data that has been loaded, as long as there are no errors. This function should return the final links *Array*. | ||
This is a static method of [<code>Rings</code>](#Rings), and is chainable with other methods of this Class. | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| *links* | <code>Array</code> \| <code>String</code> | = [] | | ||
| [*formatter*] | <code>function</code> | | | ||
<a name="Rings.nodeGroupBy" href="#Rings.nodeGroupBy">#</a> Rings.**nodeGroupBy**([*value*]) [<>](https://github.com/d3plus/d3plus-network/blob/master/src/Rings.js#L504) | ||
If *value* is specified, sets the node group accessor(s) to the specified string, function, or array of values and returns the current class instance. This method overrides the default .groupBy() function from being used with the data passed to .nodes(). If *value* is not specified, returns the current node group accessor. | ||
This is a static method of [<code>Rings</code>](#Rings), and is chainable with other methods of this Class. | ||
<a name="Rings.nodes" href="#Rings.nodes">#</a> Rings.**nodes**(*nodes*, [*formatter*]) [<>](https://github.com/d3plus/d3plus-network/blob/master/src/Rings.js#L530) | ||
The list of nodes to be used for drawing the rings network. The value passed should either be an *Array* of data or a *String* representing a filepath or URL to be loaded. | ||
Additionally, a custom formatting function can be passed as a second argument to this method. This custom function will be passed the data that has been loaded, as long as there are no errors. This function should return the final node *Array*. | ||
This is a static method of [<code>Rings</code>](#Rings), and is chainable with other methods of this Class. | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| *nodes* | <code>Array</code> \| <code>String</code> | = [] | | ||
| [*formatter*] | <code>function</code> | | | ||
<a name="Rings.size" href="#Rings.size">#</a> Rings.**size**([*value*]) [<>](https://github.com/d3plus/d3plus-network/blob/master/src/Rings.js#L547) | ||
If *value* is specified, sets the size accessor to the specified function or data key and returns the current class instance. If *value* is not specified, returns the current size accessor. | ||
This is a static method of [<code>Rings</code>](#Rings), and is chainable with other methods of this Class. | ||
<a name="Rings.sizeMax" href="#Rings.sizeMax">#</a> Rings.**sizeMax**([*value*]) [<>](https://github.com/d3plus/d3plus-network/blob/master/src/Rings.js#L557) | ||
If *value* is specified, sets the size scale maximum to the specified number and returns the current class instance. If *value* is not specified, returns the current size scale maximum. By default, the maximum size is determined by half the distance of the two closest nodes. | ||
This is a static method of [<code>Rings</code>](#Rings), and is chainable with other methods of this Class. | ||
<a name="Rings.sizeMin" href="#Rings.sizeMin">#</a> Rings.**sizeMin**([*value*]) [<>](https://github.com/d3plus/d3plus-network/blob/master/src/Rings.js#L567) | ||
If *value* is specified, sets the size scale minimum to the specified number and returns the current class instance. If *value* is not specified, returns the current size scale minimum. | ||
This is a static method of [<code>Rings</code>](#Rings), and is chainable with other methods of this Class. | ||
<a name="Rings.sizeScale" href="#Rings.sizeScale">#</a> Rings.**sizeScale**([*value*]) [<>](https://github.com/d3plus/d3plus-network/blob/master/src/Rings.js#L577) | ||
If *value* is specified, sets the size scale to the specified string and returns the current class instance. If *value* is not specified, returns the current size scale. | ||
This is a static method of [<code>Rings</code>](#Rings), and is chainable with other methods of this Class. | ||
--- | ||
###### <sub>Documentation generated on Thu, 10 May 2018 21:41:30 GMT</sub> |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
284012
12
1901
326
Updatedd3plus-common@^0.6.35
Updatedd3plus-shape@^0.14.4
Updatedd3plus-viz@^0.11.8