in src/visual.ts [625:801]
private setVisualData(
svg: d3.Selection<any>,
colorPalette: IColorPalette,
colorHelper: ColorHelper,
): void {
this.paths = svg.selectAll(ForceGraph.LinkSelector.selectorName)
.data(this.forceLayout.links())
.enter()
.append("path")
.attr("id", (d, i) => "linkid_" + this.uniqieId + i)
.attr("stroke-width", (link: ForceGraphLink) => {
return this.settings.links.thickenLink
? this.scale1to10(link.weight)
: ForceGraph.DefaultLinkThickness;
})
.classed(ForceGraph.LinkSelector.className, true)
.style("stroke", (link: ForceGraphLink) => {
return this.getLinkColor(link, colorPalette, colorHelper);
})
.style("fill", (link: ForceGraphLink) => {
if (this.settings.links.showArrow && link.source !== link.target) {
return this.getLinkColor(link, colorPalette, colorHelper);
}
})
.on("mouseover", () => {
return this.fadePath(
ForceGraph.HoverOpacity,
colorHelper.getHighContrastColor("foreground", ForceGraph.DefaultLinkHighlightColor),
colorHelper.getHighContrastColor("foreground", ForceGraph.DefaultLinkColor)
);
})
.on("mouseout", () => {
return this.fadePath(
ForceGraph.DefaultOpacity,
colorHelper.getHighContrastColor("foreground", ForceGraph.DefaultLinkColor),
colorHelper.getHighContrastColor("foreground", ForceGraph.DefaultLinkColor)
);
});
this.tooltipServiceWrapper.addTooltip(this.paths, (eventArgs: TooltipEventArgs<ForceGraphLink>) => {
return eventArgs.data.tooltipInfo;
});
if (this.settings.links.showLabel) {
let linklabelholderUpdate: d3.selection.Update<ForceGraphLink> = svg
.selectAll(ForceGraph.LinkLabelHolderSelector.selectorName)
.data(this.forceLayout.links());
linklabelholderUpdate.enter()
.append("g")
.classed(ForceGraph.LinkLabelHolderSelector.className, true)
.append("text")
.classed(ForceGraph.LinkLabelSelector.className, true)
.attr("dy", (link: ForceGraphLink) => {
return this.settings.links.thickenLink
? -this.scale1to10(link.weight) + this.defaultYOffset
: this.defaultYPosition;
})
.attr("text-anchor", ForceGraph.LinkTextAnchor)
.style("fill", colorHelper.getHighContrastColor("foreground", ForceGraph.DefaultLinkFillColor))
.append("textPath")
.attr("xlink:href", (link: ForceGraphLink, index: number) => {
return ForceGraph.Href + "#linkid_" + this.uniqieId + index;
})
.attr("startOffset", ForceGraph.StartOffset)
.text((link: ForceGraphLink) => {
return this.settings.links.colorLink === LinkColorType.ByLinkType
? link.linkType
: link.formattedWeight;
});
linklabelholderUpdate
.exit()
.remove();
}
let nodesNum: number = Object.keys(this.data.nodes).length;
let selectionManager = this.selectionManager;
// define the nodes
this.nodes = svg.selectAll(ForceGraph.NodeSelector.selectorName)
.data(this.forceLayout.nodes())
.enter()
.append("g")
.attr("drag-resize-disabled", true)
.classed(ForceGraph.NodeSelector.className, true)
.on("mouseover", (node: ForceGraphNode) => {
node.isOver = true;
this.fadeNode(node);
})
.on("mouseout", (node: ForceGraphNode) => {
node.isOver = false;
this.fadeNode(node);
})
.on("click", function (d) {
selectionManager.select(d.identity);
(<Event>d3.event).stopPropagation();
});
if (nodesNum <= ForceGraph.NoAnimationLimit) {
this.nodes.call(this.forceLayout.drag);
}
// render without animation
if (!this.settings.animation.show || nodesNum > ForceGraph.NoAnimationLimit) {
const viewport: IViewport = this.viewportIn;
let maxWidth: number = viewport.width * ForceGraph.ResolutionFactor,
maxHeight: number = viewport.height * ForceGraph.ResolutionFactor,
limitX = x => Math.max((viewport.width - maxWidth) / 2, Math.min((viewport.width + maxWidth) / 2, x)),
limitY = y => Math.max((viewport.height - maxHeight) / 2, Math.min((viewport.height + maxHeight) / 2, y));
this.paths.attr("d", (link: ForceGraphLink) => {
link.source.x = limitX(link.source.x);
link.source.y = limitY(link.source.y);
link.target.x = limitX(link.target.x);
link.target.y = limitY(link.target.y);
return this.settings && this.settings.links && this.settings.links.showArrow
? this.getPathWithArrow(link)
: this.getPathWithoutArrow(link);
});
this.nodes.attr("transform", (node: ForceGraphNode) => translate(limitX(node.x), limitY(node.y)));
}
// add the nodes
if (this.settings.nodes.displayImage) {
this.nodes.append("image")
.attr("x", PixelConverter.toString(ForceGraph.ImagePosition))
.attr("y", PixelConverter.toString(ForceGraph.ImagePosition))
.attr("width", PixelConverter.toString(ForceGraph.ImageViewport.width))
.attr("height", PixelConverter.toString(ForceGraph.ImageViewport.height))
.attr("xlink:href", (node: ForceGraphNode) => {
if (node.image) {
return this.getImage(node.image);
} else if (this.settings.nodes.defaultImage) {
return this.getImage(this.settings.nodes.defaultImage);
}
return ForceGraph.DefaultImage;
})
.attr("title", (node: ForceGraphNode) => node.name);
} else {
this.nodes
.append("circle")
.attr("r", (node: ForceGraphNode) => {
return isNaN(node.weight) || node.weight < ForceGraph.MinNodeWeight
? ForceGraph.MinNodeWeight
: node.weight;
})
.style("fill", this.settings.nodes.fill)
.style("stroke", this.settings.nodes.stroke);
}
// add the text
if (this.settings.labels.show) {
this.nodes.append("text")
.attr("x", ForceGraph.DefaultLabelX)
.attr("dy", ForceGraph.DefaultLabelDy)
.style("fill", this.settings.labels.color)
.style("font-size", PixelConverter.fromPoint(this.settings.labels.fontSize))
.text((node: ForceGraphNode) => {
if (node.name) {
if (node.name.length > this.settings.nodes.nameMaxLength) {
return node.name.substr(0, this.settings.nodes.nameMaxLength);
} else {
return node.name;
}
} else {
return ForceGraph.DefaultLabelText;
}
});
}
}