function
netGobrechtsD3Force(domContainerId, options, apexPluginId, apexPageItemsToSubmit) {
"use strict"
;
var
v = {
"conf"
: {},
"confDefaults"
: {},
"data"
: {},
"dom"
: {},
"events"
: {},
"lib"
: {},
"main"
: {},
"status"
: {},
"tools"
: {},
"version"
:
"x.x.x"
};
var
graph = {};
v.main.init =
function
() {
v.dom.containerId = domContainerId ||
"D3Force"
+ Math.floor(Math.random() * 1000000);
v.confUser = options || {};
v.status.apexPluginId = apexPluginId;
v.status.apexPageItemsToSubmit = (!apexPageItemsToSubmit || apexPageItemsToSubmit ===
""
?
false
:
apexPageItemsToSubmit.replace(/\s/g,
""
).split(
","
));
v.main.setupConfiguration();
v.main.setupDom();
v.main.setupFunctionReferences();
};
v.main.setupConfiguration =
function
() {
v.conf.debug = (v.status.apexPluginId && apex.jQuery(
"#pdebug"
).length === 1);
v.status.debugPrefix =
"D3 Force in DOM container #"
+ v.dom.containerId +
": "
;
v.status.customize =
false
;
v.status.customizeCurrentMenu =
"nodes"
;
v.status.customizeCurrentTabPosition =
null
;
v.status.forceTickCounter = 0;
v.status.forceStartTime = 0;
v.status.forceRunning =
false
;
v.status.graphStarted =
false
;
v.status.graphRendering =
false
;
v.status.graphReady =
false
;
v.status.graphOldPositions =
null
;
v.status.sampleData =
false
;
v.status.wrapLabelsOnNextTick =
false
;
v.status.labelFontSize =
null
;
v.confDefaults.minNodeRadius = {
"display"
:
true
,
"relation"
:
"node"
,
"type"
:
"number"
,
"val"
: 6,
"options"
: [12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
};
v.confDefaults.maxNodeRadius = {
"display"
:
true
,
"relation"
:
"node"
,
"type"
:
"number"
,
"val"
: 18,
"options"
: [36, 34, 32, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12]
};
v.confDefaults.colorScheme = {
"display"
:
true
,
"relation"
:
"node"
,
"type"
:
"text"
,
"val"
:
"color20"
,
"options"
: [
"color20"
,
"color20b"
,
"color20c"
,
"color10"
,
"direct"
]
};
v.confDefaults.dragMode = {
"display"
:
true
,
"relation"
:
"node"
,
"type"
:
"bool"
,
"val"
:
true
,
"options"
: [
true
,
false
]
};
v.confDefaults.pinMode = {
"display"
:
true
,
"relation"
:
"node"
,
"type"
:
"bool"
,
"val"
:
false
,
"options"
: [
true
,
false
]
};
v.confDefaults.nodeEventToStopPinMode = {
"display"
:
true
,
"relation"
:
"node"
,
"type"
:
"text"
,
"val"
:
"contextmenu"
,
"options"
: [
"none"
,
"dblclick"
,
"contextmenu"
]
};
v.confDefaults.onNodeContextmenuPreventDefault = {
"display"
:
true
,
"relation"
:
"node"
,
"type"
:
"bool"
,
"val"
:
false
,
"options"
: [
true
,
false
]
};
v.confDefaults.nodeEventToOpenLink = {
"display"
:
true
,
"relation"
:
"node"
,
"type"
:
"text"
,
"val"
:
"dblclick"
,
"options"
: [
"none"
,
"click"
,
"dblclick"
,
"contextmenu"
]
};
v.confDefaults.nodeLinkTarget = {
"display"
:
true
,
"relation"
:
"node"
,
"type"
:
"text"
,
"val"
:
"_blank"
,
"options"
: [
"none"
,
"_blank"
,
"nodeID"
,
"domContainerID"
]
};
v.confDefaults.showLabels = {
"display"
:
true
,
"relation"
:
"label"
,
"type"
:
"bool"
,
"val"
:
true
,
"options"
: [
true
,
false
]
};
v.confDefaults.wrapLabels = {
"display"
:
true
,
"relation"
:
"label"
,
"type"
:
"bool"
,
"val"
:
false
,
"options"
: [
true
,
false
]
};
v.confDefaults.wrappedLabelWidth = {
"display"
:
true
,
"relation"
:
"label"
,
"type"
:
"number"
,
"val"
: 80,
"options"
: [200, 190, 180, 170, 160, 150, 140, 130, 120, 110, 100, 90, 80, 70, 60, 50, 40]
};
v.confDefaults.wrappedLabelLineHeight = {
"display"
:
true
,
"relation"
:
"label"
,
"type"
:
"number"
,
"val"
: 1.2,
"options"
: [1.5, 1.4, 1.3, 1.2, 1.1, 1.0]
};
v.confDefaults.labelsCircular = {
"display"
:
true
,
"relation"
:
"label"
,
"type"
:
"bool"
,
"val"
:
false
,
"options"
: [
true
,
false
]
};
v.confDefaults.labelDistance = {
"display"
:
true
,
"relation"
:
"label"
,
"type"
:
"number"
,
"val"
: 12,
"options"
: [30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2]
};
v.confDefaults.preventLabelOverlappingOnForceEnd = {
"display"
:
true
,
"relation"
:
"label"
,
"type"
:
"bool"
,
"val"
:
false
,
"options"
: [
true
,
false
]
};
v.confDefaults.labelPlacementIterations = {
"display"
:
true
,
"relation"
:
"label"
,
"type"
:
"number"
,
"val"
: 250,
"options"
: [2000, 1000, 500, 250, 125]
};
v.confDefaults.showTooltips = {
"display"
:
true
,
"relation"
:
"node"
,
"type"
:
"bool"
,
"val"
:
true
,
"options"
: [
true
,
false
]
};
v.confDefaults.tooltipPosition = {
"display"
:
true
,
"relation"
:
"node"
,
"type"
:
"text"
,
"val"
:
"svgTopRight"
,
"options"
: [
"node"
,
"svgTopLeft"
,
"svgTopRight"
]
};
v.confDefaults.alignFixedNodesToGrid = {
"display"
:
true
,
"relation"
:
"node"
,
"type"
:
"bool"
,
"val"
:
false
,
"options"
: [
true
,
false
]
};
v.confDefaults.gridSize = {
"display"
:
true
,
"relation"
:
"node"
,
"type"
:
"number"
,
"val"
: 50,
"options"
: [150, 140, 130, 120, 110, 100, 90, 80, 70, 60, 50, 40, 30, 20, 10]
};
v.confDefaults.linkDistance = {
"display"
:
true
,
"relation"
:
"link"
,
"type"
:
"number"
,
"val"
: 80,
"options"
: [120, 110, 100, 90, 80, 70, 60, 50, 40, 30, 20]
};
v.confDefaults.showLinkDirection = {
"display"
:
true
,
"relation"
:
"link"
,
"type"
:
"bool"
,
"val"
:
true
,
"options"
: [
true
,
false
]
};
v.confDefaults.showSelfLinks = {
"display"
:
true
,
"relation"
:
"link"
,
"type"
:
"bool"
,
"val"
:
true
,
"options"
: [
true
,
false
]
};
v.confDefaults.selfLinkDistance = {
"display"
:
true
,
"relation"
:
"link"
,
"type"
:
"number"
,
"val"
: 20,
"options"
: [30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8]
};
v.confDefaults.useDomParentWidth = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"bool"
,
"val"
:
false
,
"options"
: [
true
,
false
]
};
v.confDefaults.width = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"number"
,
"val"
: 500,
"options"
: [1200, 1150, 1100, 1050, 1000, 950, 900, 850, 800, 750, 700, 650, 600, 550, 500, 450, 400, 350,
300
]
};
v.confDefaults.height = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"number"
,
"val"
: 500,
"options"
: [1200, 1150, 1100, 1050, 1000, 950, 900, 850, 800, 750, 700, 650, 600, 550, 500, 450, 400, 350,
300
]
};
v.confDefaults.setDomParentPaddingToZero = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"bool"
,
"val"
:
false
,
"options"
: [
true
,
false
]
};
v.confDefaults.showBorder = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"bool"
,
"val"
:
true
,
"options"
: [
true
,
false
]
};
v.confDefaults.showLegend = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"bool"
,
"val"
:
true
,
"options"
: [
true
,
false
]
};
v.confDefaults.showLoadingIndicatorOnAjaxCall = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"bool"
,
"val"
:
true
,
"options"
: [
true
,
false
]
};
v.confDefaults.lassoMode = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"bool"
,
"val"
:
false
,
"options"
: [
true
,
false
]
};
v.confDefaults.zoomMode = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"bool"
,
"val"
:
false
,
"options"
: [
true
,
false
]
};
v.confDefaults.minZoomFactor = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"number"
,
"val"
: 0.2,
"options"
: [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1]
};
v.confDefaults.maxZoomFactor = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"number"
,
"val"
: 5,
"options"
: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
};
v.confDefaults.transform = {
"display"
:
false
,
"relation"
:
"graph"
,
"type"
:
"object"
,
"val"
: {
"translate"
: [0, 0],
"scale"
: 1
}
};
v.confDefaults.zoomToFitOnForceEnd = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"bool"
,
"val"
:
false
,
"options"
: [
true
,
false
]
};
v.confDefaults.autoRefresh = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"bool"
,
"val"
:
false
,
"options"
: [
true
,
false
]
};
v.confDefaults.refreshInterval = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"number"
,
"val"
: 5000,
"options"
: [60000, 30000, 15000, 10000, 5000, 2500]
};
v.confDefaults.chargeDistance = {
"display"
:
false
,
"relation"
:
"graph"
,
"type"
:
"number"
,
"val"
: Infinity,
"options"
: [Infinity, 25600, 12800, 6400, 3200, 1600, 800, 400, 200, 100],
"internal"
:
true
};
v.confDefaults.charge = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"number"
,
"val"
: -350,
"options"
: [-1000, -950, -900, -850, -800, -750, -700, -650, -600, -550, -500, -450, -400, -350, -300, -250, -200, -150, -100, -50, 0],
"internal"
:
true
};
v.confDefaults.gravity = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"number"
,
"val"
: 0.1,
"options"
: [1.00, 0.95, 0.90, 0.85, 0.80, 0.75, 0.70, 0.65, 0.60, 0.55, 0.50, 0.45, 0.40, 0.35, 0.30, 0.25,
0.20, 0.15, 0.1, 0.05, 0.00
],
"internal"
:
true
};
v.confDefaults.linkStrength = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"number"
,
"val"
: 1,
"options"
: [1.00, 0.95, 0.90, 0.85, 0.80, 0.75, 0.70, 0.65, 0.60, 0.55, 0.50, 0.45, 0.40, 0.35, 0.30, 0.25,
0.20, 0.15, 0.10, 0.05, 0.00
],
"internal"
:
true
};
v.confDefaults.friction = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"number"
,
"val"
: 0.9,
"options"
: [1.00, 0.95, 0.90, 0.85, 0.80, 0.75, 0.70, 0.65, 0.60, 0.55, 0.50, 0.45, 0.40, 0.35, 0.30, 0.25,
0.20, 0.15, 0.10, 0.05, 0.00
],
"internal"
:
true
};
v.confDefaults.theta = {
"display"
:
true
,
"relation"
:
"graph"
,
"type"
:
"number"
,
"val"
: 0.8,
"options"
: [1, 0.95, 0.9, 0.85, 0.8, 0.75, 0.7, 0.65, 0.6, 0.55, 0.5, 0.45, 0.4, 0.35, 0.3, 0.25, 0.2, 0.15,
0.1, 0.05, 0
],
"internal"
:
true
};
v.conf.debug = (
typeof
v.confUser.debug !==
"undefined"
? v.tools.parseBool(v.confUser.debug) :
false
);
v.conf.minNodeRadius = v.confUser.minNodeRadius || v.confDefaults.minNodeRadius.val;
v.conf.maxNodeRadius = v.confUser.maxNodeRadius || v.confDefaults.maxNodeRadius.val;
v.conf.colorScheme = v.confUser.colorScheme || v.confDefaults.colorScheme.val;
v.conf.dragMode = (
typeof
v.confUser.dragMode !==
"undefined"
? v.tools.parseBool(v.confUser.dragMode) :
v.confDefaults.dragMode.val);
v.conf.pinMode = (
typeof
v.confUser.pinMode !==
"undefined"
? v.tools.parseBool(v.confUser.pinMode) :
v.confDefaults.pinMode.val);
v.conf.nodeEventToStopPinMode = v.confUser.nodeEventToStopPinMode || v.confDefaults.nodeEventToStopPinMode.val;
v.conf.onNodeContextmenuPreventDefault = (
typeof
v.confUser.onNodeContextmenuPreventDefault !==
"undefined"
?
v.tools.parseBool(v.confUser.onNodeContextmenuPreventDefault) :
v.confDefaults.onNodeContextmenuPreventDefault.val);
v.conf.nodeEventToOpenLink = v.confUser.nodeEventToOpenLink || v.confDefaults.nodeEventToOpenLink.val;
v.conf.nodeLinkTarget = v.confUser.nodeLinkTarget || v.confDefaults.nodeLinkTarget.val;
v.conf.showLabels = (
typeof
v.confUser.showLabels !==
"undefined"
? v.tools.parseBool(v.confUser.showLabels) :
v.confDefaults.showLabels.val);
v.conf.wrapLabels = (
typeof
v.confUser.wrapLabels !==
"undefined"
? v.tools.parseBool(v.confUser.wrapLabels) :
v.confDefaults.wrapLabels.val);
v.conf.wrappedLabelWidth = v.confUser.wrappedLabelWidth || v.confDefaults.wrappedLabelWidth.val;
v.conf.wrappedLabelLineHeight = v.confUser.wrappedLabelLineHeight || v.confDefaults.wrappedLabelLineHeight.val;
v.conf.labelsCircular = (
typeof
v.confUser.labelsCircular !==
"undefined"
?
v.tools.parseBool(v.confUser.labelsCircular) : v.confDefaults.labelsCircular.val);
v.conf.labelDistance = v.confUser.labelDistance || v.confDefaults.labelDistance.val;
v.conf.preventLabelOverlappingOnForceEnd =
(
typeof
v.confUser.preventLabelOverlappingOnForceEnd !==
"undefined"
?
v.tools.parseBool(v.confUser.preventLabelOverlappingOnForceEnd) :
v.confDefaults.preventLabelOverlappingOnForceEnd.val);
v.conf.labelPlacementIterations = v.confUser.labelPlacementIterations ||
v.confDefaults.labelPlacementIterations.val;
v.conf.showTooltips = (
typeof
v.confUser.showTooltips !==
"undefined"
?
v.tools.parseBool(v.confUser.showTooltips) : v.confDefaults.showTooltips.val);
v.conf.tooltipPosition = v.confUser.tooltipPosition || v.confDefaults.tooltipPosition.val;
v.conf.alignFixedNodesToGrid = (
typeof
v.confUser.alignFixedNodesToGrid !==
"undefined"
?
v.tools.parseBool(v.confUser.alignFixedNodesToGrid) : v.confDefaults.alignFixedNodesToGrid.val);
v.conf.gridSize = (v.confUser.gridSize && v.confUser.gridSize > 0 ?
v.confUser.gridSize : v.confDefaults.gridSize.val);
v.conf.linkDistance = v.confUser.linkDistance || v.confDefaults.linkDistance.val;
v.conf.showLinkDirection = (
typeof
v.confUser.showLinkDirection !==
"undefined"
?
v.tools.parseBool(v.confUser.showLinkDirection) : v.confDefaults.showLinkDirection.val);
v.conf.showSelfLinks = (
typeof
v.confUser.showSelfLinks !==
"undefined"
?
v.tools.parseBool(v.confUser.showSelfLinks) : v.confDefaults.showSelfLinks.val);
v.conf.selfLinkDistance = v.confUser.selfLinkDistance || v.confDefaults.selfLinkDistance.val;
v.conf.useDomParentWidth = (
typeof
v.confUser.useDomParentWidth !==
"undefined"
?
v.tools.parseBool(v.confUser.useDomParentWidth) : v.confDefaults.useDomParentWidth.val);
v.conf.width = v.confUser.width || v.confDefaults.width.val;
v.conf.height = v.confUser.height || v.confDefaults.height.val;
v.conf.setDomParentPaddingToZero = (
typeof
v.confUser.setDomParentPaddingToZero !==
"undefined"
?
v.tools.parseBool(v.confUser.setDomParentPaddingToZero) : v.confDefaults.setDomParentPaddingToZero.val);
v.conf.showBorder = (
typeof
v.confUser.showBorder !==
"undefined"
? v.tools.parseBool(v.confUser.showBorder) :
v.confDefaults.showBorder.val);
v.conf.showLegend = (
typeof
v.confUser.showLegend !==
"undefined"
? v.tools.parseBool(v.confUser.showLegend) :
v.confDefaults.showLegend.val);
v.conf.showLoadingIndicatorOnAjaxCall = (
typeof
v.confUser.showLoadingIndicatorOnAjaxCall !==
"undefined"
?
v.tools.parseBool(v.confUser.showLoadingIndicatorOnAjaxCall) :
v.confDefaults.showLoadingIndicatorOnAjaxCall.val);
v.conf.lassoMode = (
typeof
v.confUser.lassoMode !==
"undefined"
? v.tools.parseBool(v.confUser.lassoMode) :
v.confDefaults.lassoMode.val);
v.conf.zoomMode = (
typeof
v.confUser.zoomMode !==
"undefined"
? v.tools.parseBool(v.confUser.zoomMode) :
v.confDefaults.zoomMode.val);
v.conf.minZoomFactor = v.confUser.minZoomFactor || v.confDefaults.minZoomFactor.val;
v.conf.maxZoomFactor = v.confUser.maxZoomFactor || v.confDefaults.maxZoomFactor.val;
v.conf.transform = v.confUser.transform || v.confDefaults.transform.val;
v.conf.zoomToFitOnForceEnd = (
typeof
v.confUser.zoomToFitOnForceEnd !==
"undefined"
? v.tools.parseBool(v.confUser.zoomToFitOnForceEnd) :
v.confDefaults.zoomToFitOnForceEnd.val);
v.conf.autoRefresh = (
typeof
v.confUser.autoRefresh !==
"undefined"
?
v.tools.parseBool(v.confUser.autoRefresh) : v.confDefaults.autoRefresh.val);
v.conf.refreshInterval = v.confUser.refreshInterval || v.confDefaults.refreshInterval.val;
v.conf.chargeDistance = v.confUser.chargeDistance || Infinity;
v.conf.charge = v.confUser.charge || v.confDefaults.charge.val;
v.conf.gravity = v.confUser.gravity || v.confDefaults.gravity.val;
v.conf.linkStrength = v.confUser.linkStrength || v.confDefaults.linkStrength.val;
v.conf.friction = v.confUser.friction || v.confDefaults.friction.val;
v.conf.theta = v.confUser.theta || v.confDefaults.theta.val;
v.conf.onNodeMouseenterFunction = v.confUser.onNodeMouseenterFunction ||
null
;
v.conf.onNodeMouseleaveFunction = v.confUser.onNodeMouseleaveFunction ||
null
;
v.conf.onNodeClickFunction = v.confUser.onNodeClickFunction ||
null
;
v.conf.onNodeDblclickFunction = v.confUser.onNodeDblclickFunction ||
null
;
v.conf.onNodeContextmenuFunction = v.confUser.onNodeContextmenuFunction ||
null
;
v.conf.onLinkClickFunction = v.confUser.onLinkClickFunction ||
null
;
v.conf.onLassoStartFunction = v.confUser.onLassoStartFunction ||
null
;
v.conf.onLassoEndFunction = v.confUser.onLassoEndFunction ||
null
;
v.data.sampleData =
'<data>'
+
'<nodes ID="7839" LABEL="KING is THE KING, you know?" LABELCIRCULAR="true" COLORVALUE="10" '
+
'INFOSTRING="This visualization is based on the well known emp table." />'
+
'<nodes ID="7698" LABEL="BLAKE" COLORVALUE="30" COLORLABEL="Sales" SIZEVALUE="2850" />'
+
'<nodes ID="7782" LABEL="CLARK" COLORVALUE="10" COLORLABEL="Accounting" SIZEVALUE="2450" />'
+
'<nodes ID="7566" LABEL="JONES" COLORVALUE="20" COLORLABEL="Research" SIZEVALUE="2975" />'
+
'<nodes ID="7788" LABEL="SCOTT with a very long label" '
+
'COLORVALUE="20" COLORLABEL="Research" SIZEVALUE="3000" />'
+
'<nodes ID="7902" LABEL="FORD" COLORVALUE="20" COLORLABEL="Research" SIZEVALUE="3000" />'
+
'<nodes ID="7369" LABEL="SMITH" COLORVALUE="20" COLORLABEL="Research" SIZEVALUE="800" />'
+
'<nodes ID="7499" LABEL="ALLEN" COLORVALUE="30" COLORLABEL="Sales" SIZEVALUE="1600" />'
+
'<nodes ID="7521" LABEL="WARD" COLORVALUE="30" COLORLABEL="Sales" SIZEVALUE="1250" />'
+
'<nodes ID="7654" LABEL="MARTIN" COLORVALUE="30" COLORLABEL="Sales" SIZEVALUE="1250" />'
+
'<nodes ID="7844" LABEL="TURNER" COLORVALUE="30" COLORLABEL="Sales" SIZEVALUE="1500" />'
+
'<nodes ID="7876" LABEL="ADAMS" COLORVALUE="20" COLORLABEL="Research" SIZEVALUE="1100" />'
+
'<nodes ID="7900" LABEL="JAMES" COLORVALUE="30" COLORLABEL="Sales" SIZEVALUE="950" />'
+
'<nodes ID="7934" LABEL="MILLER" COLORVALUE="10" COLORLABEL="Accounting" SIZEVALUE="1300" />'
+
'<nodes ID="8888" LABEL="Who am I?" COLORVALUE="green" COLORLABEL="unspecified" SIZEVALUE="2000" '
+
'INFOSTRING="This is a good question. Think about it." />'
+
'<nodes ID="9999" LABEL="Where I am?" COLORVALUE="#f00" COLORLABEL="unspecified" SIZEVALUE="1000" '
+
'INFOSTRING="This is a good question. What do you think?" />'
+
'<links FROMID="7839" TOID="7839" STYLE="dotted" COLOR="blue" '
+
'INFOSTRING="This is a self link (same source and target node) rendered along a path with the STYLE '
+
'attribute set to dotted and COLOR attribute set to blue." />'
+
'<links FROMID="7698" TOID="7839" STYLE="dashed" />'
+
'<links FROMID="7782" TOID="7839" STYLE="dashed" COLOR="red" INFOSTRING="This is a link with the STYLE '
+
'attribute set to dashed and COLOR attribute set to red." />'
+
'<links FROMID="7566" TOID="7839" STYLE="dashed" />'
+
'<links FROMID="7788" TOID="7566" STYLE="solid" />'
+
'<links FROMID="7902" TOID="7566" STYLE="solid" />'
+
'<links FROMID="7369" TOID="7902" STYLE="solid" />'
+
'<links FROMID="7499" TOID="7698" STYLE="solid" />'
+
'<links FROMID="7521" TOID="7698" STYLE="solid" />'
+
'<links FROMID="7654" TOID="7698" STYLE="solid" />'
+
'<links FROMID="7844" TOID="7698" STYLE="solid" />'
+
'<links FROMID="7876" TOID="7788" STYLE="solid" />'
+
'<links FROMID="7900" TOID="7698" STYLE="solid" />'
+
'<links FROMID="7934" TOID="7782" STYLE="solid" />'
+
'</data>'
;
v.status.userAgent = navigator.userAgent;
v.status.userAgentIe9To11 =
false
;
if
(navigator.appVersion.indexOf(
"MSIE 9"
) !== -1 ||
navigator.appVersion.indexOf(
"MSIE 10"
) !== -1 ||
v.status.userAgent.indexOf(
"Trident"
) !== -1 && v.status.userAgent.indexOf(
"rv:11"
) !== -1) {
v.status.userAgentIe9To11 =
true
;
v.tools.logError(
"Houston, we have a problem - user agent is IE 9, 10 or 11 - we have to provide a fix "
+
"for markers: "
+
}
};
v.main.setupDom =
function
() {
v.dom.body = d3.select(
"body"
);
if
(document.querySelector(
"#"
+ v.dom.containerId) ===
null
) {
v.dom.container = v.dom.body.append(
"div"
)
.attr(
"id"
, v.dom.containerId);
}
else
{
v.dom.container = d3.select(
"#"
+ v.dom.containerId);
d3.selectAll(
"#"
+ v.dom.containerId +
"_customizing"
).remove();
}
if
(document.querySelector(
"#"
+ v.dom.containerId +
" svg"
) ===
null
) {
v.dom.svg = v.dom.container.append(
"svg"
);
}
else
{
v.dom.svg = d3.select(
"#"
+ v.dom.containerId +
" svg"
);
d3.selectAll(
"#"
+ v.dom.containerId +
" svg *"
).remove();
}
v.dom.svgParent = d3.select(v.dom.svg.node().parentNode);
if
(v.conf.setDomParentPaddingToZero) {
v.dom.svgParent.style(
"padding"
,
"0"
);
}
v.dom.svg
.attr(
"class"
,
"net_gobrechts_d3_force"
)
.classed(
"border"
, v.conf.showBorder)
.attr(
"width"
, v.conf.width)
.attr(
"height"
, v.conf.height);
v.dom.containerWidth = v.tools.getSvgParentInnerWidth();
if
(v.conf.useDomParentWidth) {
v.dom.svg.attr(
"width"
, v.dom.containerWidth);
}
v.dom.defs = v.dom.svg.append(
"defs"
);
v.dom.graphOverlay = v.dom.svg.append(
"g"
).attr(
"class"
,
"graphOverlay"
);
v.dom.graphOverlaySizeHelper = v.dom.graphOverlay.append(
"rect"
).attr(
"class"
,
"graphOverlaySizeHelper"
);
v.dom.graph = v.dom.graphOverlay.append(
"g"
).attr(
"class"
,
"graph"
);
v.dom.legend = v.dom.svg.append(
"g"
).attr(
"class"
,
"legend"
);
v.dom.loading = v.dom.svg.append(
"svg:g"
)
.attr(
"class"
,
"loading"
)
.style(
"display"
,
"none"
);
v.dom.loadingRect = v.dom.loading
.append(
"svg:rect"
)
.attr(
"width"
, v.tools.getGraphWidth())
.attr(
"height"
, v.conf.height);
v.dom.loadingText = v.dom.loading
.append(
"svg:text"
)
.attr(
"x"
, v.tools.getGraphWidth() / 2)
.attr(
"y"
, v.conf.height / 2)
.text(
"Loading..."
);
v.dom.defs
.append(
"svg:marker"
)
.attr(
"id"
, v.dom.containerId +
"_highlighted"
)
.attr(
"class"
,
"highlighted"
)
.attr(
"viewBox"
,
"0 0 10 10"
)
.attr(
"refX"
, 10)
.attr(
"refY"
, 5)
.attr(
"markerWidth"
, 5)
.attr(
"markerHeight"
, 5)
.attr(
"orient"
,
"auto"
)
.attr(
"markerUnits"
,
"strokeWidth"
)
.append(
"svg:path"
)
.attr(
"d"
,
"M0,0 L10,5 L0,10"
);
v.dom.defs
.append(
"svg:marker"
)
.attr(
"id"
, v.dom.containerId +
"_normal"
)
.attr(
"class"
,
"normal"
)
.attr(
"viewBox"
,
"0 0 10 10"
)
.attr(
"refX"
, 10)
.attr(
"refY"
, 5)
.attr(
"markerWidth"
, 5)
.attr(
"markerHeight"
, 5)
.attr(
"orient"
,
"auto"
)
.attr(
"markerUnits"
,
"strokeWidth"
)
.append(
"svg:path"
)
.attr(
"d"
,
"M0,0 L10,5 L0,10"
);
if
(document.querySelector(
"#"
+ v.dom.containerId +
"_tooltip"
) ===
null
) {
v.dom.tooltip = v.dom.body.append(
"div"
)
.attr(
"id"
, v.dom.containerId +
"_tooltip"
)
.attr(
"class"
,
"net_gobrechts_d3_force_tooltip"
)
.style(
"top"
,
"0px"
)
.style(
"left"
,
"0px"
);
}
else
{
v.dom.tooltip = d3.select(
"#"
+ v.dom.containerId +
"_tooltip"
);
}
};
v.main.setupFunctionReferences =
function
() {
v.main.force = d3.layout.force()
.on(
"start"
,
function
() {
v.tools.log(
"Force started."
);
if
(v.status.customize && v.dom.customizePositions) {
v.dom.customizePositions.text(
"Force started - wait for end event to show positions..."
);
}
v.status.forceTickCounter = 0;
v.status.forceStartTime =
new
Date().getTime();
v.status.forceRunning =
true
;
})
.on(
"tick"
,
function
() {
v.status.forceTickCounter += 1;
if
(v.status.userAgentIe9To11 && v.conf.showLinkDirection) {
v.main.links.each(
function
() {
this
.parentNode.insertBefore(
this
,
this
);
});
v.main.selfLinks.each(
function
() {
this
.parentNode.insertBefore(
this
,
this
);
});
}
v.main.selfLinks
.attr(
"transform"
,
function
(l) {
return
"translate("
+ l.source.x +
","
+ l.source.y +
")"
;
});
v.main.links
.attr(
"x1"
,
function
(l) {
return
v.tools.adjustSourceX(l);
})
.attr(
"y1"
,
function
(l) {
return
v.tools.adjustSourceY(l);
})
.attr(
"x2"
,
function
(l) {
return
v.tools.adjustTargetX(l);
})
.attr(
"y2"
,
function
(l) {
return
v.tools.adjustTargetY(l);
});
if
(v.conf.showLabels) {
v.main.labels
.attr(
"x"
,
function
(l) {
return
l.x;
})
.attr(
"y"
,
function
(l) {
return
l.y - l.radius - v.conf.labelDistance;
});
if
(v.status.wrapLabelsOnNextTick) {
v.main.labels.call(v.tools.wrapLabels, v.conf.wrappedLabelWidth);
v.status.wrapLabelsOnNextTick =
false
;
}
if
(v.conf.wrapLabels) {
v.main.labels.each(
function
() {
var
label = d3.select(
this
);
var
y = label.attr(
"y"
) - (label.attr(
"lines"
) - 1) *
v.status.labelFontSize * v.conf.wrappedLabelLineHeight;
label.attr(
"y"
, y)
.selectAll(
"tspan"
)
.attr(
"x"
, label.attr(
"x"
))
.attr(
"y"
, y);
});
}
v.main.labelPaths
.attr(
"transform"
,
function
(n) {
return
"translate("
+ n.x +
","
+ n.y +
")"
;
});
}
v.main.nodes
.attr(
"cx"
,
function
(n) {
return
n.x;
})
.attr(
"cy"
,
function
(n) {
return
n.y;
});
})
.on(
"end"
,
function
() {
if
(v.conf.showLabels && v.conf.preventLabelOverlappingOnForceEnd) {
v.data.simulatedAnnealingLabels = [];
v.data.simulatedAnnealingAnchors = [];
v.main.labels.each(
function
(node, i) {
var
label = d3.select(
this
);
v.data.simulatedAnnealingLabels[i] = {
width:
this
.getBBox().width,
height:
this
.getBBox().height,
x: node.x,
y: label.attr(
"y"
) - (label.attr(
"lines"
) - 1) *
v.status.labelFontSize * v.conf.wrappedLabelLineHeight
};
});
v.main.nodes.filter(
function
(n) {
return
!n.LABELCIRCULAR && !v.conf.labelsCircular;
}).each(
function
(node, i) {
v.data.simulatedAnnealingAnchors[i] = {
x: node.x,
y: node.y - node.radius - v.conf.labelDistance,
r: 0.5
};
});
v.lib.labelerPlugin()
.label(v.data.simulatedAnnealingLabels)
.anchor(v.data.simulatedAnnealingAnchors)
.width(v.tools.getGraphWidth())
.height(v.conf.height)
.start(v.conf.labelPlacementIterations);
v.main.labels.each(
function
(node, i) {
var
label = d3.select(
this
),
x = v.data.simulatedAnnealingLabels[i].x,
y = v.data.simulatedAnnealingLabels[i].y;
if
(v.conf.wrapLabels) {
y = y - (label.attr(
"lines"
) - 1) * v.status.labelFontSize * v.conf.wrappedLabelLineHeight;
label
.transition()
.duration(800)
.attr(
"x"
, x)
.attr(
"y"
, y)
.selectAll(
"tspan"
)
.attr(
"x"
, x)
.attr(
"y"
, y);
}
else
{
label
.transition()
.duration(800)
.attr(
"x"
, x)
.attr(
"y"
, y);
}
});
}
if
(v.conf.zoomToFitOnForceEnd && v.conf.zoomMode) {
graph.zoomToFit();
}
v.status.forceRunning =
false
;
var
milliseconds =
new
Date().getTime() - v.status.forceStartTime;
var
seconds = (milliseconds / 1000).toFixed(1);
var
ticksPerSecond = Math.round(v.status.forceTickCounter / (milliseconds / 1000));
var
millisecondsPerTick = Math.round(milliseconds / v.status.forceTickCounter);
if
(v.status.customize && v.dom.customizePositions) {
v.dom.customizePositions.text(JSON.stringify(graph.positions()));
}
v.tools.log(
"Force ended."
);
v.tools.log(seconds +
" seconds, "
+ v.status.forceTickCounter +
" ticks to cool down ("
+
ticksPerSecond +
" ticks/s, "
+ millisecondsPerTick +
" ms/tick)."
);
});
v.main.drag = v.main.force.drag();
v.main.lasso = v.lib.lassoPlugin()
.closePathDistance(100)
.closePathSelect(
true
)
.hoverSelect(
true
)
.area(v.dom.graphOverlay)
.pathContainer(v.dom.svg);
v.main.zoom = d3.behavior.zoom();
v.main.zoomed =
function
() {
v.conf.transform = {
"translate"
: v.main.zoom.translate(),
"scale"
: v.main.zoom.scale()
};
v.dom.graph.attr(
"transform"
,
"translate("
+ v.main.zoom.translate() +
")scale("
+
v.main.zoom.scale() +
")"
);
v.tools.writeConfObjectIntoWizard();
};
v.main.interpolateZoom =
function
(translate, scale, duration) {
if
(v.conf.zoomMode && v.status.graphStarted) {
if
(scale < v.conf.minZoomFactor) {
scale = v.conf.minZoomFactor;
}
else
if
(scale > v.conf.maxZoomFactor) {
scale = v.conf.maxZoomFactor;
}
return
d3.transition().duration(duration).tween(
"zoom"
,
function
() {
var
iTranslate = d3.interpolate(v.main.zoom.translate(), translate),
iScale = d3.interpolate(v.main.zoom.scale(), scale);
return
function
(t) {
v.main.zoom
.scale(iScale(t))
.translate(iTranslate(t));
v.main.zoomed();
};
});
}
};
};
v.tools.parseBool =
function
(value) {
switch
(String(value).trim().toLowerCase()) {
case
"true"
:
case
"yes"
:
case
"1"
:
return
true
;
case
"false"
:
case
"no"
:
case
"0"
:
case
""
:
return
false
;
default
:
return
false
;
}
};
v.tools.parseXml =
function
(xml) {
var
dom =
null
;
if
(xml) {
if
(window.DOMParser) {
try
{
dom = (
new
DOMParser()).parseFromString(xml,
"text/xml"
);
}
catch
(e) {
dom =
null
;
v.tools.logError(
"DOMParser - unable to parse XML: "
+ e.message);
}
}
else
if
(window.ActiveXObject) {
try
{
dom =
new
ActiveXObject(
"Microsoft.XMLDOM"
);
dom.async =
false
;
if
(!dom.loadXML(xml)) {
v.tools.logError(
"Microsoft.XMLDOM - unable to parse XML: "
+ dom.parseError.reason +
dom.parseError.srcText);
}
}
catch
(e) {
dom =
null
;
v.tools.logError(
"Microsoft.XMLDOM - unable to parse XML: "
+ e.message);
}
}
}
return
dom;
};
v.tools.xmlToJson =
function
(xml) {
var
obj =
null
,
subobj, item, subItem, nodeName, attribute;
var
convertItemToJson =
function
(item) {
subobj = {};
if
(item.attributes.length > 0) {
for
(
var
i = 0; i < item.attributes.length; i++) {
attribute = item.attributes.item(i);
subobj[attribute.nodeName] = attribute.nodeValue;
}
}
if
(item.hasChildNodes()) {
for
(
var
j = 0; j < item.childNodes.length; j++) {
subItem = item.childNodes.item(j);
if
(subItem.hasChildNodes()) {
subobj[subItem.nodeName] = subItem.childNodes.item(0).nodeValue;
}
else
{
subobj[subItem.nodeName] =
""
;
}
}
}
return
subobj;
};
if
(xml) {
obj = {};
obj.data = {};
obj.data.nodes = [];
obj.data.links = [];
if
(xml.childNodes.item(0).hasChildNodes()) {
for
(
var
i = 0; i < xml.childNodes.item(0).childNodes.length; i++) {
subobj =
null
;
item = xml.childNodes.item(0).childNodes.item(i);
nodeName = item.nodeName;
if
(nodeName ===
"nodes"
|| nodeName ===
"node"
) {
obj.data.nodes.push(convertItemToJson(item));
}
else
if
(nodeName ===
"links"
|| nodeName ===
"link"
) {
obj.data.links.push(convertItemToJson(item));
}
}
}
}
return
obj;
};
v.tools.getSvgParentInnerWidth =
function
() {
return
parseInt(v.dom.svgParent.style(
"width"
)) -
parseInt(v.dom.svgParent.style(
"padding-left"
)) -
parseInt(v.dom.svgParent.style(
"padding-right"
)) -
(v.dom.svg.style(
"border-width"
) ? parseInt(v.dom.svg.style(
"border-width"
)) : 1) * 2;
};
v.tools.getGraphWidth =
function
() {
return
(v.conf.useDomParentWidth ? v.dom.containerWidth : v.conf.width);
};
v.tools.log =
function
(message, omitDebugPrefix) {
if
(v.conf.debug) {
if
(omitDebugPrefix) {
console.log(message);
}
else
{
console.log(v.status.debugPrefix + message);
}
}
if
(v.status.customize && v.dom.customizeLog) {
v.dom.customizeLog.text(message +
"\n"
+ v.dom.customizeLog.text());
}
};
v.tools.logError =
function
(message) {
console.log(v.status.debugPrefix +
"ERROR: "
+ message);
if
(v.status.customize && v.dom.customizeLog) {
v.dom.customizeLog.text(
"ERROR: "
+ message +
"\n"
+ v.dom.customizeLog.text());
}
};
v.tools.triggerApexEvent =
function
(domNode, event, data) {
if
(v.status.apexPluginId) {
apex.event.trigger(domNode, event, data);
}
};
v.tools.setRadiusFunction =
function
() {
v.tools.radius = d3.scale.sqrt()
.range([v.conf.minNodeRadius, v.conf.maxNodeRadius])
.domain(d3.extent(v.data.nodes,
function
(n) {
return
parseFloat(n.SIZEVALUE);
}));
};
v.tools.setColorFunction =
function
() {
if
(v.conf.colorScheme ===
"color20"
) {
v.tools.color = d3.scale.category20();
}
else
if
(v.conf.colorScheme ===
"color20b"
) {
v.tools.color = d3.scale.category20b();
}
else
if
(v.conf.colorScheme ===
"color20c"
) {
v.tools.color = d3.scale.category20c();
}
else
if
(v.conf.colorScheme ===
"color10"
) {
v.tools.color = d3.scale.category10();
}
else
if
(v.conf.colorScheme ===
"direct"
) {
v.tools.color =
function
(d) {
return
d;
};
}
else
{
v.conf.colorScheme =
"color20"
;
v.tools.color = d3.scale.category20();
}
};
v.tools.neighboring =
function
(a, b) {
return
(v.data.neighbors.indexOf(a.ID +
":"
+ b.ID) > -1 ||
v.data.neighbors.indexOf(b.ID +
":"
+ a.ID) > -1);
};
v.tools.getNearestGridPosition =
function
(currentPos, maxPos) {
var
offset, position;
if
(v.conf.zoomMode) {
offset = currentPos % v.conf.gridSize;
position = (offset > v.conf.gridSize / 2 ? currentPos - offset + v.conf.gridSize : currentPos - offset);
}
else
{
if
(currentPos >= maxPos) {
offset = maxPos % v.conf.gridSize;
position = maxPos - offset;
if
(position === maxPos) {
position = position - v.conf.gridSize;
}
}
else
if
(currentPos <= v.conf.gridSize / 2) {
position = v.conf.gridSize;
}
else
{
offset = currentPos % v.conf.gridSize;
position = (offset > v.conf.gridSize / 2 ? currentPos - offset + v.conf.gridSize : currentPos - offset);
if
(position >= maxPos) {
position = position - v.conf.gridSize;
}
}
}
return
position;
};
v.tools.adjustSourceX =
function
(l) {
return
l.source.x + Math.cos(v.tools.calcAngle(l)) * (l.source.radius);
};
v.tools.adjustSourceY =
function
(l) {
return
l.source.y + Math.sin(v.tools.calcAngle(l)) * (l.source.radius);
};
v.tools.adjustTargetX =
function
(l) {
return
l.target.x - Math.cos(v.tools.calcAngle(l)) * (l.target.radius);
};
v.tools.adjustTargetY =
function
(l) {
return
l.target.y - Math.sin(v.tools.calcAngle(l)) * (l.target.radius);
};
v.tools.calcAngle =
function
(l) {
return
Math.atan2(l.target.y - l.source.y, l.target.x - l.source.x);
};
v.tools.getSelfLinkPath =
function
(l) {
var
ri = l.source.radius;
var
ro = l.source.radius + v.conf.selfLinkDistance;
var
x = 0;
var
y = 0;
var
pathStart = {
"source"
: {
"x"
: 0,
"y"
: 0,
"radius"
: ri
},
"target"
: {
"x"
: (x + ro / 2),
"y"
: (y + ro),
"radius"
: ri
}
};
var
pathEnd = {
"source"
: {
"x"
: (x - ro / 2),
"y"
: (y + ro),
"radius"
: ri
},
"target"
: {
"x"
: x,
"y"
: y,
"radius"
: ri
}
};
var
path =
"M"
+ v.tools.adjustSourceX(pathStart) +
","
+ v.tools.adjustSourceY(pathStart);
path +=
" L"
+ (x + ro / 2) +
","
+ (y + ro);
path +=
" A"
+ ro +
","
+ ro +
" 0 0,1 "
+ (x - ro / 2) +
","
+ (y + ro);
path +=
" L"
+ v.tools.adjustTargetX(pathEnd) +
","
+ v.tools.adjustTargetY(pathEnd);
return
path;
};
v.tools.getLabelPath =
function
(n) {
var
r = n.radius + v.conf.labelDistance;
var
x = 0;
var
y = 0;
var
path =
"M"
+ (x - r) +
","
+ y;
path +=
" a"
+ r +
","
+ r +
" 0 0,1 "
+ (r * 2) +
",0"
;
path +=
" a"
+ r +
","
+ r +
" 0 0,1 -"
+ (r * 2) +
",0"
;
return
path;
};
v.tools.openLink =
function
(node) {
var
win;
if
(v.conf.nodeLinkTarget ===
"none"
) {
window.location.assign(node.LINK);
}
else
if
(v.conf.nodeLinkTarget ===
"nodeID"
) {
win = window.open(node.LINK, node.ID);
win.focus();
}
else
if
(v.conf.nodeLinkTarget ===
"domContainerID"
) {
win = window.open(node.LINK, v.dom.containerId);
win.focus();
}
else
{
win = window.open(node.LINK, v.conf.nodeLinkTarget);
win.focus();
}
};
v.tools.applyConfigurationObject =
function
(confObject) {
var
key;
for
(key
in
confObject) {
if
(confObject.hasOwnProperty(key) &&
v.conf.hasOwnProperty(key) &&
confObject[key] !== v.conf[key]) {
graph[key](confObject[key]);
}
}
};
v.tools.zoomEventProxy =
function
(fn) {
return
function
() {
if
(
(!v.conf.dragMode || v.conf.dragMode && d3.event.target.tagName !==
"circle"
) &&
v.conf.zoomMode &&
(!d3.event.altKey && !d3.event.shiftKey)
) {
fn.apply(
this
, arguments);
}
};
};
v.tools.lassoEventProxy =
function
(fn) {
return
function
() {
if
(
(!v.conf.dragMode || d3.event.target.tagName !==
"circle"
) &&
v.conf.lassoMode &&
(!v.conf.zoomMode || d3.event.altKey || d3.event.shiftKey)
) {
fn.apply(
this
, arguments);
}
};
};
v.tools.showTooltip =
function
(text) {
var
position;
v.dom.tooltip.html(text).style(
"display"
,
"block"
);
if
(v.conf.tooltipPosition ===
"svgTopLeft"
) {
position = v.tools.getOffsetRect(v.dom.svg.node());
v.dom.tooltip
.style(
"top"
, position.top +
(v.dom.svg.style(
"border-width"
) ? parseInt(v.dom.svg.style(
"border-width"
)) : 1) +
"px"
)
.style(
"left"
, position.left +
(v.dom.svg.style(
"border-width"
) ? parseInt(v.dom.svg.style(
"border-width"
)) : 1) +
"px"
);
}
else
if
(v.conf.tooltipPosition ===
"svgTopRight"
) {
position = v.tools.getOffsetRect(v.dom.svg.node());
v.dom.tooltip
.style(
"top"
, position.top +
parseInt((v.dom.svg.style(
"border-width"
) ? parseInt(v.dom.svg.style(
"border-width"
)) : 1)) +
"px"
)
.style(
"left"
, position.left +
parseInt(v.dom.svg.style(
"width"
)) +
parseInt((v.dom.svg.style(
"border-width"
) ? parseInt(v.dom.svg.style(
"border-width"
)) : 1)) -
parseInt(v.dom.tooltip.style(
"width"
)) -
2 * parseInt(
(v.dom.tooltip.style(
"border-width"
) ? parseInt(v.dom.tooltip.style(
"border-width"
)) : 0)
) -
parseInt(v.dom.tooltip.style(
"padding-left"
)) -
parseInt(v.dom.tooltip.style(
"padding-right"
)) +
"px"
);
}
else
{
v.dom.tooltip
.style(
"left"
, d3.event.pageX + 10 +
"px"
)
.style(
"top"
, d3.event.pageY +
"px"
);
}
};
v.tools.hideTooltip =
function
() {
v.dom.tooltip.style(
"display"
,
"none"
);
};
v.tools.onLinkClick =
function
(link) {
if
(d3.event.defaultPrevented) {
return
null
;
}
else
{
v.tools.log(
"Event link_click triggered."
);
v.tools.triggerApexEvent(
this
,
"net_gobrechts_d3_force_linkclick"
, link);
if
(
typeof
(v.conf.onLinkClickFunction) ===
"function"
) {
v.conf.onLinkClickFunction.call(
this
, d3.event, link);
}
}
};
v.tools.getMarkerUrl =
function
(l) {
if
(v.conf.showLinkDirection) {
return
"url(#"
+ v.dom.containerId +
"_"
+ (l.COLOR ? l.COLOR :
"normal"
) +
")"
;
}
else
{
return
null
;
}
};
v.tools.getMarkerUrlHighlighted =
function
() {
if
(v.conf.showLinkDirection) {
return
"url(#"
+ v.dom.containerId +
"_highlighted)"
;
}
else
{
return
null
;
}
};
v.tools.onLinkMouseenter =
function
(link) {
if
(v.conf.showTooltips && link.INFOSTRING) {
v.tools.showTooltip(link.INFOSTRING);
}
};
v.tools.onLinkMouseleave =
function
() {
if
(v.conf.showTooltips) {
v.tools.hideTooltip();
}
};
v.tools.onNodeMouseenter =
function
(node) {
v.main.nodes.classed(
"highlighted"
,
function
(n) {
return
v.tools.neighboring(n, node);
});
v.main.links
.classed(
"highlighted"
,
function
(l) {
return
l.source.ID === node.ID || l.target.ID === node.ID;
})
.style(
"marker-end"
,
function
(l) {
if
(l.source.ID === node.ID || l.target.ID === node.ID) {
return
v.tools.getMarkerUrlHighlighted(l);
}
else
{
return
v.tools.getMarkerUrl(l);
}
});
v.main.selfLinks
.classed(
"highlighted"
,
function
(l) {
return
l.FROMID === node.ID;
})
.style(
"marker-end"
,
function
(l) {
if
(l.source.ID === node.ID || l.target.ID === node.ID) {
return
v.tools.getMarkerUrlHighlighted(l);
}
else
{
return
v.tools.getMarkerUrl(l);
}
});
if
(v.conf.showLabels) {
v.main.labels.classed(
"highlighted"
,
function
(l) {
return
l.ID === node.ID;
});
v.main.labelsCircular.classed(
"highlighted"
,
function
(l) {
return
l.ID === node.ID;
});
}
d3.select(
this
).classed(
"highlighted"
,
true
);
v.tools.log(
"Event node_mouseenter triggered."
);
v.tools.triggerApexEvent(
this
,
"net_gobrechts_d3_force_mouseenter"
, node);
if
(
typeof
(v.conf.onNodeMouseenterFunction) ===
"function"
) {
v.conf.onNodeMouseenterFunction.call(
this
, d3.event, node);
}
if
(v.conf.showTooltips && node.INFOSTRING) {
v.tools.showTooltip(node.INFOSTRING);
}
};
v.tools.onNodeMouseleave =
function
(node) {
v.main.nodes.classed(
"highlighted"
,
false
);
v.main.links
.classed(
"highlighted"
,
false
)
.style(
"marker-end"
, v.tools.getMarkerUrl);
v.main.selfLinks
.classed(
"highlighted"
,
false
)
.style(
"marker-end"
, v.tools.getMarkerUrl);
if
(v.conf.showLabels) {
v.main.labels.classed(
"highlighted"
,
false
);
v.main.labelsCircular.classed(
"highlighted"
,
false
);
}
v.tools.log(
"Event node_mouseleave triggered."
);
v.tools.triggerApexEvent(
this
,
"net_gobrechts_d3_force_mouseleave"
, node);
if
(
typeof
(v.conf.onNodeMouseleaveFunction) ===
"function"
) {
v.conf.onNodeMouseleaveFunction.call(
this
, d3.event, node);
}
if
(v.conf.showTooltips) {
v.tools.hideTooltip();
}
};
v.tools.onNodeClick =
function
(node) {
if
(d3.event.defaultPrevented) {
return
null
;
}
else
{
if
(node.LINK && v.conf.nodeEventToOpenLink ===
"click"
) {
v.tools.openLink(node);
}
if
(v.conf.nodeEventToStopPinMode ===
"click"
) {
d3.select(
this
).classed(
"fixed"
, node.fixed = 0);
}
v.tools.log(
"Event node_click triggered."
);
v.tools.triggerApexEvent(
this
,
"net_gobrechts_d3_force_click"
, node);
if
(
typeof
(v.conf.onNodeClickFunction) ===
"function"
) {
v.conf.onNodeClickFunction.call(
this
, d3.event, node);
}
}
};
v.tools.onNodeDblclick =
function
(node) {
if
(node.LINK && v.conf.nodeEventToOpenLink ===
"dblclick"
) {
v.tools.openLink(node);
}
if
(v.conf.nodeEventToStopPinMode ===
"dblclick"
) {
d3.select(
this
).classed(
"fixed"
, node.fixed = 0);
}
v.tools.log(
"Event node_dblclick triggered."
);
v.tools.triggerApexEvent(
this
,
"net_gobrechts_d3_force_dblclick"
, node);
if
(
typeof
(v.conf.onNodeDblclickFunction) ===
"function"
) {
v.conf.onNodeDblclickFunction.call(
this
, d3.event, node);
}
};
v.tools.onNodeContextmenu =
function
(node) {
if
(v.conf.onNodeContextmenuPreventDefault) {
d3.event.preventDefault();
}
if
(node.LINK && v.conf.nodeEventToOpenLink ===
"contextmenu"
) {
v.tools.openLink(node);
}
if
(v.conf.nodeEventToStopPinMode ===
"contextmenu"
) {
d3.select(
this
).classed(
"fixed"
, node.fixed = 0);
}
v.tools.log(
"Event node_contextmenu triggered."
);
v.tools.triggerApexEvent(
this
,
"net_gobrechts_d3_force_contextmenu"
, node);
if
(
typeof
(v.conf.onNodeContextmenuFunction) ===
"function"
) {
v.conf.onNodeContextmenuFunction.call(
this
, d3.event, node);
}
};
v.tools.onLassoStart =
function
(nodes) {
var
data = {};
data.numberOfSelectedNodes = 0;
data.idsOfSelectedNodes =
null
;
data.numberOfNodes = nodes.size();
data.nodes = nodes;
v.tools.log(
"Event lasso_start triggered."
);
v.tools.triggerApexEvent(document.querySelector(
"#"
+ v.dom.containerId),
"net_gobrechts_d3_force_lassostart"
,
data
);
if
(
typeof
(v.conf.onLassoStartFunction) ===
"function"
) {
v.conf.onLassoStartFunction.call(v.dom.svg, d3.event, data);
}
};
v.tools.onLassoEnd =
function
(nodes) {
var
data = {};
data.numberOfSelectedNodes = 0;
data.idsOfSelectedNodes =
""
;
data.numberOfNodes = nodes.size();
data.nodes = nodes;
nodes.each(
function
(n) {
if
(n.selected) {
data.idsOfSelectedNodes += (n.ID +
":"
);
data.numberOfSelectedNodes++;
}
});
data.idsOfSelectedNodes =
(data.idsOfSelectedNodes.length > 0 ?
data.idsOfSelectedNodes.substr(0, data.idsOfSelectedNodes.length - 1) :
null
);
v.tools.log(
"Event lasso_end triggered."
);
v.tools.triggerApexEvent(document.querySelector(
"#"
+ v.dom.containerId),
"net_gobrechts_d3_force_lassoend"
, data);
if
(
typeof
(v.conf.onLassoEndFunction) ===
"function"
) {
v.conf.onLassoEndFunction.call(v.dom.svg, d3.event, data);
}
};
v.tools.getOffsetRect =
function
(elem) {
var
box = elem.getBoundingClientRect();
var
body = document.body;
var
docElem = document.documentElement;
var
scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
var
scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;
var
clientTop = docElem.clientTop || body.clientTop || 0;
var
clientLeft = docElem.clientLeft || body.clientLeft || 0;
var
top = box.top + scrollTop - clientTop;
var
left = box.left + scrollLeft - clientLeft;
return
{
top: Math.round(top),
left: Math.round(left)
};
};
v.tools.createLegend =
function
() {
v.data.distinctNodeColorValues.forEach(
function
(colorString, i) {
var
color = colorString.split(
";"
);
v.dom.legend
.append(
"circle"
)
.attr(
"cx"
, 11)
.attr(
"cy"
, v.conf.height - ((i + 1) * 14 - 3))
.attr(
"r"
, 6)
.attr(
"fill"
, v.tools.color(color[1]));
v.dom.legend
.append(
"text"
)
.attr(
"x"
, 21)
.attr(
"y"
, v.conf.height - ((i + 1) * 14 - 6))
.text((color[0] ? color[0] : color[1]));
});
};
v.tools.removeLegend =
function
() {
v.dom.legend.selectAll(
"*"
).remove();
};
v.tools.writeConfObjectIntoWizard =
function
() {
if
(v.status.customize) {
v.dom.customizeConfObject.text(JSON.stringify(graph.optionsCustomizationWizard(),
null
,
" "
));
}
};
v.tools.createCustomizeLink =
function
() {
if
(!v.status.customize &&
(v.conf.debug || document.querySelector(
"#apex-dev-toolbar"
) || document.querySelector(
"#apexDevToolbar"
))
) {
if
(document.querySelector(
"#d3-force-customize-link"
) ===
null
) {
v.dom.svg.append(
"svg:text"
)
.attr(
"id"
,
"d3-force-customize-link"
)
.attr(
"class"
,
"link"
)
.attr(
"x"
, 5)
.attr(
"y"
, 15)
.attr(
"text-anchor"
,
"start"
)
.text(
"Customize Me"
)
.on(
"click"
,
function
() {
graph.customize(
true
);
});
}
}
};
v.tools.removeCustomizeLink =
function
() {
v.dom.svg.select(
"#d3-force-customize-link"
).remove();
};
v.tools.customizeDrag = d3.behavior.drag()
.on(
"dragstart"
,
function
() {
var
mouseToBody = d3.mouse(document.body);
v.dom.customizePosition = v.tools.getOffsetRect(document.querySelector(
"#"
+ v.dom.containerId +
"_customizing"
));
v.dom.customizePosition.mouseLeft = mouseToBody[0] - v.dom.customizePosition.left;
v.dom.customizePosition.mouseTop = mouseToBody[1] - v.dom.customizePosition.top;
})
.on(
"drag"
,
function
() {
var
mouseToBody = d3.mouse(document.body);
v.dom.customize
.style(
"left"
, Math.max(0,
mouseToBody[0] - v.dom.customizePosition.mouseLeft) +
"px"
)
.style(
"top"
, Math.max(0,
mouseToBody[1] - v.dom.customizePosition.mouseTop) +
"px"
);
})
.on(
"dragend"
,
function
() {
v.dom.customizePosition = v.tools.getOffsetRect(v.dom.customize.node());
});
v.tools.createCustomizeWizardIfNotRendering =
function
() {
if
(v.status.customize && !v.status.graphRendering) {
v.tools.createCustomizeWizard();
}
};
v.tools.createCustomizeWizard =
function
() {
var
grid, gridRow, gridCell, row, td, form, i = 4,
currentOption, valueInOptions, key;
var
releaseFixedNodesAndResume =
function
() {
graph.releaseFixedNodes().resume();
};
var
onSelectChange =
function
() {
v.status.customizeCurrentTabPosition =
this
.id;
if
(v.confDefaults[
this
.name].type ===
"text"
) {
graph[
this
.name](
this
.options[
this
.selectedIndex].value).render();
}
else
if
(v.confDefaults[
this
.name].type ===
"number"
) {
graph[
this
.name](parseFloat(
this
.options[
this
.selectedIndex].value)).render();
}
else
if
(v.confDefaults[
this
.name].type ===
"bool"
) {
graph[
this
.name]((
this
.options[
this
.selectedIndex].value ===
"true"
)).render();
}
};
var
appendOptionsToSelect =
function
(key) {
v.confDefaults[key].options.forEach(
function
(option) {
currentOption = option;
form.append(
"option"
)
.attr(
"value"
, option)
.attr(
"selected"
,
function
() {
if
(v.confDefaults[key].type ===
"text"
|| v.confDefaults[key].type ===
"bool"
) {
if
(currentOption === v.conf[key]) {
valueInOptions =
true
;
return
"selected"
;
}
else
{
return
null
;
}
}
else
if
(v.confDefaults[key].type ===
"number"
) {
if
(parseFloat(currentOption) === v.conf[key]) {
valueInOptions =
true
;
return
"selected"
;
}
else
{
return
null
;
}
}
})
.text(option);
});
};
if
(!v.status.customize) {
v.tools.removeCustomizeWizard();
v.tools.createCustomizeLink();
}
else
{
v.tools.removeCustomizeLink();
if
(!v.dom.customizePosition) {
v.dom.customizePosition = v.tools.getOffsetRect(v.dom.svg.node());
v.dom.customizePosition.left = v.dom.customizePosition.left + v.conf.width + 8;
}
if
(document.querySelector(
"#"
+ v.dom.containerId +
"_customizing"
) !==
null
) {
v.dom.customize.remove();
}
v.dom.customize = v.dom.body.insert(
"div"
)
.attr(
"id"
, v.dom.containerId +
"_customizing"
)
.attr(
"class"
,
"net_gobrechts_d3_force_customize"
)
.style(
"left"
, v.dom.customizePosition.left +
"px"
)
.style(
"top"
, v.dom.customizePosition.top +
"px"
);
v.dom.customize.append(
"span"
)
.attr(
"class"
,
"drag"
)
.call(v.tools.customizeDrag)
.append(
"span"
)
.attr(
"class"
,
"title"
)
.text(
"Customize \""
+ v.dom.containerId +
"\""
);
v.dom.customize.append(
"a"
)
.attr(
"class"
,
"close focus"
)
.attr(
"tabindex"
, 1)
.text(
"Close"
)
.on(
"click"
,
function
() {
v.status.customize =
false
;
v.tools.removeCustomizeWizard();
v.tools.createCustomizeLink();
})
.on(
"keydown"
,
function
() {
if
(d3.event.keyCode === 13) {
v.status.customize =
false
;
v.tools.removeCustomizeWizard();
v.tools.createCustomizeLink();
}
});
grid = v.dom.customize.append(
"table"
);
gridRow = grid.append(
"tr"
);
gridCell = gridRow.append(
"td"
).style(
"vertical-align"
,
"top"
);
v.dom.customizeMenu = gridCell.append(
"span"
);
v.dom.customizeOptionsTable = gridCell.append(
"table"
);
for
(key
in
v.confDefaults) {
if
(v.confDefaults.hasOwnProperty(key) && v.confDefaults[key].display) {
i += 1;
row = v.dom.customizeOptionsTable.append(
"tr"
)
.attr(
"class"
, v.confDefaults[key].relation +
"-related"
);
row.append(
"td"
)
.attr(
"class"
,
"label"
)
key +
"\" target=\"github_d3_force\" tabindex=\""
+ i + 100 +
"\">"
+
key +
"</a>"
);
td = row.append(
"td"
);
form = td.append(
"select"
)
.attr(
"id"
, v.dom.containerId +
"_"
+ key)
.attr(
"name"
, key)
.attr(
"value"
, v.conf[key])
.attr(
"tabindex"
, i + 1)
.classed(
"warning"
, v.confDefaults[key].internal)
.on(
"change"
, onSelectChange);
valueInOptions =
false
;
appendOptionsToSelect(key);
if
(!valueInOptions) {
form.append(
"option"
)
.attr(
"value"
, v.conf[key])
.attr(
"selected"
,
"selected"
)
.text(v.conf[key]);
v.confDefaults[key].options.push(v.conf[key]);
}
if
(key ===
"pinMode"
) {
td.append(
"a"
)
.text(
" release all"
)
.attr(
"href"
,
null
)
.on(
"click"
, releaseFixedNodesAndResume);
}
}
}
v.dom.customizeOptionsTable.style(
"width"
, d3.select(v.dom.customizeOptionsTable).node()[0][0].clientWidth +
"px"
);
gridCell.append(
"span"
).html(
"<br>"
);
gridCell = gridRow.append(
"td"
)
.style(
"vertical-align"
,
"top"
)
.style(
"padding-left"
,
"5px"
);
gridCell.append(
"span"
)
.html(
"Your Configuration Object<p style=\"font-size:10px;margin:0;\">"
+
(v.status.apexPluginId ?
"To save your options please copy<br>this to your plugin region attributes.<br>"
+
"Only non-default options are shown.</p>"
:
"Use this to initialize your graph.<br>Only non-default options are shown.</p>"
)
);
v.dom.customizeConfObject = gridCell.append(
"textarea"
)
.attr(
"tabindex"
, i + 5)
.attr(
"readonly"
,
"readonly"
);
gridCell.append(
"span"
).html(
"<br><br>Current Positions<br>"
);
v.dom.customizePositions = gridCell.append(
"textarea"
)
.attr(
"tabindex"
, i + 6)
.attr(
"readonly"
,
"readonly"
)
.text((v.status.forceRunning ?
"Force started - wait for end event to show positions..."
:
JSON.stringify(graph.positions())));
gridCell.append(
"span"
).html(
"<br><br>Debug Log (descending)<br>"
);
v.dom.customizeLog = gridCell.append(
"textarea"
)
.attr(
"tabindex"
, i + 7)
.attr(
"readonly"
,
"readonly"
);
gridRow = grid.append(
"tr"
);
gridCell = gridRow.append(
"td"
)
.attr(
"colspan"
, 2)
.html(
"Copyrights:"
);
gridRow = grid.append(
"tr"
);
gridCell = gridRow.append(
"td"
)
.attr(
"colspan"
, 2)
.html(
"<table><tr><td style=\"padding-right:20px;\">"
+
"tabindex=\""
+ (i + 8) +
"\">D3 Force APEX Plugin</a> ("
+ v.version +
")<br>Ottmar Gobrecht</td><td style=\"padding-right:20px;\">"
+
"\">D3.js</a> ("
+ d3.version +
") and "
+
(i + 10) +
"\">D3 Lasso Plugin</a> (modified)<br>Mike Bostock"
+
"</td></tr><tr><td colspan=\"3\">"
+
"tabindex=\""
+ (i + 11) +
"\">D3 Labeler Plugin</a> (automatic label placement using simulated annealing)"
+
"<br>Evan Wang</td></tr></table>"
);
v.tools.createCustomizeMenu(v.status.customizeCurrentMenu);
v.tools.writeConfObjectIntoWizard();
if
(v.status.customizeCurrentTabPosition) {
document.getElementById(v.status.customizeCurrentTabPosition).focus();
}
}
};
v.tools.removeCustomizeWizard =
function
() {
d3.select(
"#"
+ v.dom.containerId +
"_customizing"
).remove();
};
v.tools.createCustomizeMenu =
function
(relation) {
v.status.customizeCurrentMenu = relation;
v.dom.customizeMenu.selectAll(
"*"
).remove();
v.dom.customizeMenu.append(
"span"
).text(
"Show options for:"
);
if
(v.status.customizeCurrentMenu ===
"nodes"
) {
v.dom.customizeMenu.append(
"span"
).style(
"font-weight"
,
"bold"
).style(
"margin-left"
,
"10px"
).text(
"NODES"
);
v.dom.customizeOptionsTable.selectAll(
"tr.node-related"
).classed(
"hidden"
,
false
);
v.dom.customizeOptionsTable.selectAll(
"tr.label-related,tr.link-related,tr.graph-related"
)
.classed(
"hidden"
,
true
);
}
else
{
v.dom.customizeMenu.append(
"a"
)
.style(
"font-weight"
,
"bold"
)
.style(
"margin-left"
,
"10px"
)
.text(
"NODES"
)
.attr(
"tabindex"
, 2)
.on(
"click"
,
function
() {
v.tools.createCustomizeMenu(
"nodes"
);
v.dom.customizeOptionsTable.selectAll(
"tr.node-related"
).classed(
"hidden"
,
false
);
v.dom.customizeOptionsTable.selectAll(
"tr.label-related,tr.link-related,tr.graph-related"
)
.classed(
"hidden"
,
true
);
})
.on(
"keydown"
,
function
() {
if
(d3.event.keyCode === 13) {
v.tools.createCustomizeMenu(
"nodes"
);
v.dom.customizeOptionsTable.selectAll(
"tr.node-related"
).classed(
"hidden"
,
false
);
v.dom.customizeOptionsTable.selectAll(
"tr.label-related,tr.link-related,tr.graph-related"
)
.classed(
"hidden"
,
true
);
}
});
}
if
(v.status.customizeCurrentMenu ===
"labels"
) {
v.dom.customizeMenu.append(
"span"
).style(
"font-weight"
,
"bold"
).style(
"margin-left"
,
"10px"
).text(
"LABELS"
);
v.dom.customizeOptionsTable.selectAll(
"tr.label-related"
).classed(
"hidden"
,
false
);
v.dom.customizeOptionsTable.selectAll(
"tr.node-related,tr.link-related,tr.graph-related"
)
.classed(
"hidden"
,
true
);
}
else
{
v.dom.customizeMenu.append(
"a"
)
.style(
"font-weight"
,
"bold"
)
.style(
"margin-left"
,
"10px"
)
.text(
"LABELS"
)
.attr(
"tabindex"
, 2)
.on(
"click"
,
function
() {
v.tools.createCustomizeMenu(
"labels"
);
v.dom.customizeOptionsTable.selectAll(
"tr.label-related"
).classed(
"hidden"
,
false
);
v.dom.customizeOptionsTable.selectAll(
"tr.node-related,tr.link-related,tr.graph-related"
)
.classed(
"hidden"
,
true
);
})
.on(
"keydown"
,
function
() {
if
(d3.event.keyCode === 13) {
v.tools.createCustomizeMenu(
"labels"
);
v.dom.customizeOptionsTable.selectAll(
"tr.label-related"
).classed(
"hidden"
,
false
);
v.dom.customizeOptionsTable.selectAll(
"tr.node-related,tr.link-related,tr.graph-related"
)
.classed(
"hidden"
,
true
);
}
});
}
if
(v.status.customizeCurrentMenu ===
"links"
) {
v.dom.customizeMenu.append(
"span"
).style(
"font-weight"
,
"bold"
).style(
"margin-left"
,
"10px"
).text(
"LINKS"
);
v.dom.customizeOptionsTable.selectAll(
"tr.link-related"
).classed(
"hidden"
,
false
);
v.dom.customizeOptionsTable.selectAll(
"tr.node-related,tr.label-related,tr.graph-related"
)
.classed(
"hidden"
,
true
);
}
else
{
v.dom.customizeMenu.append(
"a"
)
.style(
"font-weight"
,
"bold"
)
.style(
"margin-left"
,
"10px"
)
.text(
"LINKS"
)
.attr(
"tabindex"
, 3)
.on(
"click"
,
function
() {
v.tools.createCustomizeMenu(
"links"
);
v.dom.customizeOptionsTable.selectAll(
"tr.link-related"
).classed(
"hidden"
,
false
);
v.dom.customizeOptionsTable.selectAll(
"tr.node-related,tr.label-related,tr.graph-related"
)
.classed(
"hidden"
,
true
);
})
.on(
"keydown"
,
function
() {
if
(d3.event.keyCode === 13) {
v.tools.createCustomizeMenu(
"links"
);
v.dom.customizeOptionsTable.selectAll(
"tr.link-related"
).classed(
"hidden"
,
false
);
v.dom.customizeOptionsTable.selectAll(
"tr.node-related,tr.label-related,tr.graph-related"
)
.classed(
"hidden"
,
true
);
}
});
}
if
(v.status.customizeCurrentMenu ===
"graph"
) {
v.dom.customizeMenu.append(
"span"
).style(
"font-weight"
,
"bold"
).style(
"margin-left"
,
"10px"
).text(
"GRAPH"
);
v.dom.customizeOptionsTable.selectAll(
"tr.graph-related"
).classed(
"hidden"
,
false
);
v.dom.customizeOptionsTable.selectAll(
"tr.node-related,tr.label-related,tr.link-related"
)
.classed(
"hidden"
,
true
);
}
else
{
v.dom.customizeMenu.append(
"a"
)
.style(
"font-weight"
,
"bold"
)
.style(
"margin-left"
,
"10px"
)
.text(
"GRAPH"
)
.attr(
"tabindex"
, 4)
.on(
"click"
,
function
() {
v.tools.createCustomizeMenu(
"graph"
);
v.dom.customizeOptionsTable.selectAll(
"tr.graph-related"
).classed(
"hidden"
,
false
);
v.dom.customizeOptionsTable.selectAll(
"tr.node-related,tr.label-related,tr.link-related"
)
.classed(
"hidden"
,
true
);
})
.on(
"keydown"
,
function
() {
if
(d3.event.keyCode === 13) {
v.tools.createCustomizeMenu(
"graph"
);
v.dom.customizeOptionsTable.selectAll(
"tr.graph-related"
).classed(
"hidden"
,
false
);
v.dom.customizeOptionsTable.selectAll(
"tr.node-related,tr.label-related,tr.link-related"
)
.classed(
"hidden"
,
true
);
}
});
}
v.dom.customizeMenu.append(
"span"
).html(
"<br><br>"
);
};
v.tools.wrapLabels =
function
(labels, width) {
labels.each(
function
(label, i) {
var
text = d3.select(
this
);
if
(i === 0) {
v.status.labelFontSize = parseInt(text.style(
"font-size"
));
}
if
(!
this
.hasAttribute(
"lines"
)) {
var
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = v.status.labelFontSize * v.conf.wrappedLabelLineHeight,
x = text.attr(
"x"
),
y = text.attr(
"y"
),
dy = 0,
tspan = text.text(
null
).append(
"tspan"
).attr(
"x"
, x).attr(
"y"
, y).attr(
"dy"
, dy +
"px"
);
while
(word = words.pop()) {
line.push(word);
tspan.text(line.join(
" "
));
if
(tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(
" "
));
line = [word];
tspan = text.append(
"tspan"
).attr(
"x"
, x).attr(
"y"
, y).attr(
"dy"
, ++lineNumber * lineHeight +
dy +
"px"
).text(word);
}
}
text.attr(
"lines"
, lineNumber + 1);
}
});
};
v.lib.labelerPlugin =
function
() {
var
lab = [],
anc = [],
w = 1,
h = 1,
labeler = {};
var
max_move = 5,
max_angle = 0.5,
acc = 0,
rej = 0;
var
w_len = 0.2,
w_inter = 1.0,
w_lab2 = 30.0,
w_lab_anc = 30.0,
w_orient = 1.0;
var
user_energy =
false
,
user_schedule =
false
;
var
user_defined_energy,
user_defined_schedule;
var
energy =
function
(index) {
var
m = lab.length,
ener = 0,
dx = lab[index].x - anc[index].x,
dy = anc[index].y - lab[index].y,
dist = Math.sqrt(dx * dx + dy * dy),
overlap =
true
;
if
(dist > 0) {
ener += dist * w_len;
}
dx /= dist;
dy /= dist;
if
(dx > 0 && dy > 0) {
ener += 0;
}
else
if
(dx < 0 && dy > 0) {
ener += w_orient;
}
else
if
(dx < 0 && dy < 0) {
ener += 2 * w_orient;
}
else
{
ener += 3 * w_orient;
}
var
x21 = lab[index].x,
y21 = lab[index].y - lab[index].height + 2.0,
x22 = lab[index].x + lab[index].width,
y22 = lab[index].y + 2.0;
var
x11, x12, y11, y12, x_overlap, y_overlap, overlap_area;
for
(
var
i = 0; i < m; i++) {
if
(i !== index) {
overlap = intersect(anc[index].x, lab[index].x, anc[i].x, lab[i].x,
anc[index].y, lab[index].y, anc[i].y, lab[i].y);
if
(overlap) {
ener += w_inter;
}
x11 = lab[i].x;
y11 = lab[i].y - lab[i].height + 2.0;
x12 = lab[i].x + lab[i].width;
y12 = lab[i].y + 2.0;
x_overlap = Math.max(0, Math.min(x12, x22) - Math.max(x11, x21));
y_overlap = Math.max(0, Math.min(y12, y22) - Math.max(y11, y21));
overlap_area = x_overlap * y_overlap;
ener += (overlap_area * w_lab2);
}
x11 = anc[i].x - anc[i].r;
y11 = anc[i].y - anc[i].r;
x12 = anc[i].x + anc[i].r;
y12 = anc[i].y + anc[i].r;
x_overlap = Math.max(0, Math.min(x12, x22) - Math.max(x11, x21));
y_overlap = Math.max(0, Math.min(y12, y22) - Math.max(y11, y21));
overlap_area = x_overlap * y_overlap;
ener += (overlap_area * w_lab_anc);
}
return
ener;
};
var
mcmove =
function
(currT) {
var
i = Math.floor(Math.random() * lab.length);
var
x_old = lab[i].x;
var
y_old = lab[i].y;
var
old_energy;
if
(user_energy) {
old_energy = user_defined_energy(i, lab, anc);
}
else
{
old_energy = energy(i);
}
lab[i].x += (Math.random() - 0.5) * max_move;
lab[i].y += (Math.random() - 0.5) * max_move;
if
(lab[i].x > w) {
lab[i].x = x_old;
}
if
(lab[i].x < 0) {
lab[i].x = x_old;
}
if
(lab[i].y > h) {
lab[i].y = y_old;
}
if
(lab[i].y < 0) {
lab[i].y = y_old;
}
var
new_energy;
if
(user_energy) {
new_energy = user_defined_energy(i, lab, anc);
}
else
{
new_energy = energy(i);
}
var
delta_energy = new_energy - old_energy;
if
(Math.random() < Math.exp(-delta_energy / currT)) {
acc += 1;
}
else
{
lab[i].x = x_old;
lab[i].y = y_old;
rej += 1;
}
};
var
mcrotate =
function
(currT) {
var
i = Math.floor(Math.random() * lab.length);
var
x_old = lab[i].x;
var
y_old = lab[i].y;
var
old_energy;
if
(user_energy) {
old_energy = user_defined_energy(i, lab, anc);
}
else
{
old_energy = energy(i);
}
var
angle = (Math.random() - 0.5) * max_angle;
var
s = Math.sin(angle);
var
c = Math.cos(angle);
lab[i].x -= anc[i].x;
lab[i].y -= anc[i].y;
var
x_new = lab[i].x * c - lab[i].y * s,
y_new = lab[i].x * s + lab[i].y * c;
lab[i].x = x_new + anc[i].x;
lab[i].y = y_new + anc[i].y;
if
(lab[i].x > w) {
lab[i].x = x_old;
}
if
(lab[i].x < 0) {
lab[i].x = x_old;
}
if
(lab[i].y > h) {
lab[i].y = y_old;
}
if
(lab[i].y < 0) {
lab[i].y = y_old;
}
var
new_energy;
if
(user_energy) {
new_energy = user_defined_energy(i, lab, anc);
}
else
{
new_energy = energy(i);
}
var
delta_energy = new_energy - old_energy;
if
(Math.random() < Math.exp(-delta_energy / currT)) {
acc += 1;
}
else
{
lab[i].x = x_old;
lab[i].y = y_old;
rej += 1;
}
};
var
intersect =
function
(x1, x2, x3, x4, y1, y2, y3, y4) {
var
mua, mub;
var
denom, numera, numerb;
denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
numera = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
numerb = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);
mua = numera / denom;
mub = numerb / denom;
return
!(mua < 0 || mua > 1 || mub < 0 || mub > 1);
};
var
cooling_schedule =
function
(currT, initialT, nsweeps) {
return
(currT - (initialT / nsweeps));
};
labeler.start =
function
(nsweeps) {
var
m = lab.length,
currT = 1.0,
initialT = 1.0;
for
(
var
i = 0; i < nsweeps; i++) {
for
(
var
j = 0; j < m; j++) {
if
(Math.random() < 0.5) {
mcmove(currT);
}
else
{
mcrotate(currT);
}
}
currT = cooling_schedule(currT, initialT, nsweeps);
}
};
labeler.width =
function
(x) {
if
(!arguments.length) {
return
w;
}
w = x;
return
labeler;
};
labeler.height =
function
(x) {
if
(!arguments.length) {
return
h;
}
h = x;
return
labeler;
};
labeler.label =
function
(x) {
if
(!arguments.length) {
return
lab;
}
lab = x;
return
labeler;
};
labeler.anchor =
function
(x) {
if
(!arguments.length) {
return
anc;
}
anc = x;
return
labeler;
};
labeler.alt_energy =
function
(x) {
if
(!arguments.length) {
return
energy;
}
user_defined_energy = x;
user_energy =
true
;
return
labeler;
};
labeler.alt_schedule =
function
(x) {
if
(!arguments.length) {
return
cooling_schedule;
}
user_defined_schedule = x;
user_schedule =
true
;
return
labeler;
};
return
labeler;
};
v.lib.lassoPlugin =
function
() {
var
items =
null
,
closePathDistance = 75,
closePathSelect =
true
,
isPathClosed =
false
,
hoverSelect =
true
,
area =
null
,
pathContainer =
null
,
on = {
start:
function
() {},
draw:
function
() {},
end:
function
() {}
};
function
lasso() {
var
_this = d3.select(
this
[0][0]);
var
g, dyn_path, close_path, complete_path, path, origin, last_known_point, path_length_start, drag;
pathContainer = pathContainer || _this;
if
(pathContainer.selectAll(
"g.lasso"
).size() === 0) {
g = pathContainer.append(
"g"
).attr(
"class"
,
"lasso"
);
dyn_path = g.append(
"path"
).attr(
"class"
,
"drawn"
);
close_path = g.append(
"path"
).attr(
"class"
,
"loop_close"
);
complete_path = g.append(
"path"
).attr(
"class"
,
"complete_path"
).attr(
"display"
,
"none"
);
}
else
{
g = pathContainer.select(
"g.lasso"
);
dyn_path = g.select(
"path.drawn"
);
close_path = g.select(
"path.loop_close"
);
complete_path = g.select(
"path.complete_path"
);
}
function
dragstart() {
path =
""
;
dyn_path.attr(
"d"
,
null
);
close_path.attr(
"d"
,
null
);
path_length_start = 0;
items[0].forEach(
function
(d) {
d.hoverSelected =
false
;
d.loopSelected =
false
;
var
cur_box = d.getBBox();
var
ctm = d.getCTM();
d.lassoPoint = {
cx: Math.round((cur_box.x + cur_box.width / 2) * ctm.a + ctm.e),
cy: Math.round((cur_box.y + cur_box.height / 2) * ctm.d + ctm.f),
edges: {
top: 0,
right: 0,
bottom: 0,
left: 0
},
close_edges: {
left: 0,
right: 0
}
};
});
if
(hoverSelect ===
true
) {
items.on(
"mouseover.lasso"
,
function
() {
d3.select(
this
)[0][0].hoverSelected =
true
;
});
}
on.start();
}
function
dragmove() {
var
x = d3.mouse(
this
)[0],
y = d3.mouse(
this
)[1],
distance,
close_draw_path,
complete_path_d,
close_path_node,
close_path_length,
close_path_edges,
path_node,
path_length_end,
i,
last_pos,
prior_pos,
prior_pos_obj,
cur_pos,
cur_pos_obj,
calcLassoPointEdges =
function
(d) {
if
(cur_pos_obj.x > d.lassoPoint.cx) {
d.lassoPoint.edges.right = d.lassoPoint.edges.right + 1;
}
if
(cur_pos_obj.x < d.lassoPoint.cx) {
d.lassoPoint.edges.left = d.lassoPoint.edges.left + 1;
}
},
calcLassoPointCloseEdges =
function
(d) {
if
(Math.round(cur_pos.y) !== Math.round(prior_pos.y) &&
Math.round(cur_pos.x) > d.lassoPoint.cx) {
d.lassoPoint.close_edges.right = 1;
}
if
(Math.round(cur_pos.y) !== Math.round(prior_pos.y) &&
Math.round(cur_pos.x) < d.lassoPoint.cx) {
d.lassoPoint.close_edges.left = 1;
}
},
ckeckIfNodeYequalsCurrentPosY =
function
(d) {
return
d.lassoPoint.cy === Math.round(cur_pos.y);
},
ckeckIfNodeYequalsCurrentPriorPosY =
function
(d) {
var
a;
if
(d.lassoPoint.cy === cur_pos_obj.y && d.lassoPoint.cy !== prior_pos_obj.y) {
last_known_point = {
x: prior_pos_obj.x,
y: prior_pos_obj.y
};
a =
false
;
}
else
if
(d.lassoPoint.cy === cur_pos_obj.y && d.lassoPoint.cy === prior_pos_obj.y) {
a =
false
;
}
else
if
(d.lassoPoint.cy === prior_pos_obj.y && d.lassoPoint.cy !== cur_pos_obj.y) {
a = sign(d.lassoPoint.cy - cur_pos_obj.y) !== sign(d.lassoPoint.cy - last_known_point.y);
}
else
{
last_known_point = {
x: prior_pos_obj.x,
y: prior_pos_obj.y
};
a = sign(d.lassoPoint.cy - cur_pos_obj.y) !== sign(d.lassoPoint.cy - prior_pos_obj.y);
}
return
a;
};
if
(path ===
""
) {
path = path +
"M "
+ x +
" "
+ y;
origin = [x, y];
}
else
{
path = path +
" L "
+ x +
" "
+ y;
}
items[0].forEach(
function
(d) {
d.lassoPoint.close_edges = {
left: 0,
right: 0
};
});
distance = Math.sqrt(Math.pow(x - origin[0], 2) + Math.pow(y - origin[1], 2));
close_draw_path =
"M "
+ x +
" "
+ y +
" L "
+ origin[0] +
" "
+ origin[1];
dyn_path.attr(
"d"
, path);
if
(distance <= closePathDistance) {
close_path.attr(
"display"
,
null
);
}
else
{
close_path.attr(
"display"
,
"none"
);
}
isPathClosed = distance <= closePathDistance;
complete_path_d = d3.select(
"path"
)[0][0].attributes.d.value +
"Z"
;
complete_path.attr(
"d"
, complete_path_d);
path_node = dyn_path.node();
path_length_end = path_node.getTotalLength();
last_pos = path_node.getPointAtLength(path_length_start - 1);
for
(i = path_length_start; i <= path_length_end; i++) {
cur_pos = path_node.getPointAtLength(i);
cur_pos_obj = {
x: Math.round(cur_pos.x * 100) / 100,
y: Math.round(cur_pos.y * 100) / 100
};
prior_pos = path_node.getPointAtLength(i - 1);
prior_pos_obj = {
x: Math.round(prior_pos.x * 100) / 100,
y: Math.round(prior_pos.y * 100) / 100
};
items[0].filter(ckeckIfNodeYequalsCurrentPriorPosY).forEach(calcLassoPointEdges);
}
if
(isPathClosed ===
true
&& closePathSelect ===
true
) {
close_path.attr(
"d"
, close_draw_path);
close_path_node = close_path.node();
close_path_length = close_path_node.getTotalLength();
close_path_edges = {
left: 0,
right: 0
};
for
(i = 0; i <= close_path_length; i++) {
cur_pos = close_path_node.getPointAtLength(i);
prior_pos = close_path_node.getPointAtLength(i - 1);
items[0].filter(ckeckIfNodeYequalsCurrentPosY).forEach(calcLassoPointCloseEdges);
}
items[0].forEach(
function
(a) {
if
((a.lassoPoint.edges.left + a.lassoPoint.close_edges.left) > 0 &&
(a.lassoPoint.edges.right + a.lassoPoint.close_edges.right) % 2 === 1) {
a.loopSelected =
true
;
}
else
{
a.loopSelected =
false
;
}
});
}
else
{
items[0].forEach(
function
(d) {
d.loopSelected =
false
;
});
}
d3.selectAll(items[0].filter(
function
(d) {
return
(d.loopSelected && isPathClosed) || d.hoverSelected;
}))
.attr(
"d"
,
function
(d) {
d.possible =
true
;
return
d.possible;
});
d3.selectAll(items[0].filter(
function
(d) {
return
!((d.loopSelected && isPathClosed) || d.hoverSelected);
}))
.attr(
"d"
,
function
(d) {
d.possible =
false
;
return
d.possible;
});
on.draw();
path_length_start = path_length_end + 1;
}
function
dragend() {
items.on(
"mouseover.lasso"
,
null
);
items.filter(
function
(d) {
return
d.possible ===
true
;
})
.attr(
"d"
,
function
(d) {
d.selected =
true
;
return
d.selected;
});
items.filter(
function
(d) {
return
d.possible ===
false
;
})
.attr(
"d"
,
function
(d) {
d.selected =
false
;
return
d.selected;
});
items.attr(
"d"
,
function
(d) {
d.possible =
false
;
return
d.possible;
});
dyn_path.attr(
"d"
,
null
);
close_path.attr(
"d"
,
null
);
on.end();
}
drag = d3.behavior.drag()
.on(
"dragstart"
, dragstart)
.on(
"drag"
, dragmove)
.on(
"dragend"
, dragend);
area.call(drag);
}
lasso.items =
function
(_) {
if
(!arguments.length) {
return
items;
}
items = _;
items[0].forEach(
function
(d) {
var
item = d3.select(d);
if
(
typeof
item.datum() ===
"undefined"
) {
item.datum({
possible:
false
,
selected:
false
});
}
else
{
item.attr(
"d"
,
function
(e) {
e.possible =
false
;
e.selected =
false
;
return
e;
});
}
});
return
lasso;
};
lasso.closePathDistance =
function
(_) {
if
(!arguments.length) {
return
closePathDistance;
}
closePathDistance = _;
return
lasso;
};
lasso.closePathSelect =
function
(_) {
if
(!arguments.length) {
return
closePathSelect;
}
closePathSelect = _ ===
true
;
return
lasso;
};
lasso.isPathClosed =
function
(_) {
if
(!arguments.length) {
return
isPathClosed;
}
isPathClosed = _ ===
true
;
return
lasso;
};
lasso.hoverSelect =
function
(_) {
if
(!arguments.length) {
return
hoverSelect;
}
hoverSelect = _ ===
true
;
return
lasso;
};
lasso.on =
function
(type, _) {
if
(!arguments.length) {
return
on;
}
if
(arguments.length === 1) {
return
on[type];
}
var
types = [
"start"
,
"draw"
,
"end"
];
if
(types.indexOf(type) > -1) {
on[type] = _;
}
return
lasso;
};
lasso.area =
function
(_) {
if
(!arguments.length) {
return
area;
}
area = _;
return
lasso;
};
lasso.pathContainer =
function
(_) {
if
(!arguments.length) {
return
pathContainer;
}
pathContainer = d3.select(_[0][0]);
return
lasso;
};
function
sign(x) {
return
x ? x < 0 ? -1 : 1 : 0;
}
return
lasso;
};
v.main.init();
graph.start =
function
(data) {
var
firstChar;
if
(data) {
graph.render(data);
}
else
if
(v.status.apexPluginId) {
if
(v.conf.showLoadingIndicatorOnAjaxCall) {
graph.showLoadingIndicator(
true
);
}
apex.server.plugin(
v.status.apexPluginId, {
p_debug: $v(
"pdebug"
),
pageItems: v.status.apexPageItemsToSubmit
}, {
success:
function
(dataString) {
if
(v.conf.showLoadingIndicatorOnAjaxCall) {
graph.showLoadingIndicator(
false
);
}
firstChar = dataString.trim().substr(0, 1);
if
(firstChar ===
"<"
|| firstChar ===
"{"
) {
graph.render(dataString);
}
else
if
(dataString.trim().substr(0, 16) ===
"no_query_defined"
) {
graph.render();
v.tools.logError(
"No query defined."
);
}
else
if
(dataString.trim().substr(0, 22) ===
"query_returned_no_data"
) {
graph.render({
"data"
: {
"nodes"
: [{
"ID"
:
"1"
,
"LABEL"
:
"ERROR: No data."
,
"COLORVALUE"
:
"1"
,
"SIZEVALUE"
:
"1"
}],
"links"
: []
}
});
v.tools.logError(
"Query returned no data."
);
}
else
{
graph.render({
"data"
: {
"nodes"
: [{
"ID"
:
"1"
,
"LABEL"
:
"ERROR: "
+ dataString +
"."
,
"COLORVALUE"
:
"1"
,
"SIZEVALUE"
:
"1"
}],
"links"
: []
}
});
v.tools.logError(dataString);
}
},
error:
function
(xhr, status, errorThrown) {
graph.render({
"data"
: {
"nodes"
: [{
"ID"
:
"1"
,
"LABEL"
:
"AJAX call terminated with errors."
,
"COLORVALUE"
:
"1"
,
"SIZEVALUE"
:
"1"
}],
"links"
: []
}
});
v.tools.logError(
"AJAX call terminated with errors: "
+ errorThrown +
"."
);
},
dataType:
"text"
}
);
}
else
{
graph.render();
}
return
graph;
};
graph.render =
function
(data) {
var
message;
v.status.graphStarted =
true
;
v.status.graphRendering =
true
;
v.tools.triggerApexEvent(document.querySelector(
"#"
+ v.dom.containerId),
"apexbeforerefresh"
);
if
(!data && !v.status.graphReady) {
v.tools.logError(
"Houston, we have a problem - we have to provide sample data."
);
v.status.sampleData =
true
;
data = v.data.sampleData;
}
else
if
(data) {
v.status.sampleData =
false
;
}
if
(data) {
if
(v.status.graphReady) {
v.status.graphOldPositions = graph.positions();
}
if
(data.constructor === Object) {
v.data.dataConverted = data;
if
(v.conf.debug) {
v.tools.log(
"Data object:"
);
v.tools.log(v.data.dataConverted,
true
);
}
}
else
if
(data.constructor === String) {
if
(data.trim().substr(0, 1) ===
"<"
) {
try
{
v.data.dataConverted = v.tools.xmlToJson(v.tools.parseXml(data));
if
(v.data.dataConverted ===
null
) {
message =
"Unable to convert XML string."
;
v.tools.logError(message);
v.data.dataConverted = {
"data"
: {
"nodes"
: [{
"ID"
:
"1"
,
"LABEL"
:
"ERROR: "
+ message,
"COLORVALUE"
:
"1"
,
"SIZEVALUE"
:
"1"
}],
"links"
: []
}
};
}
}
catch
(e) {
message =
"Unable to convert XML string: "
+ e.message +
"."
;
v.tools.logError(message);
v.data.dataConverted = {
"data"
: {
"nodes"
: [{
"ID"
:
"1"
,
"LABEL"
:
"ERROR: "
+ message,
"COLORVALUE"
:
"1"
,
"SIZEVALUE"
:
"1"
}],
"links"
: []
}
};
}
}
else
if
(data.trim().substr(0, 1) ===
"{"
) {
try
{
v.data.dataConverted = JSON.parse(data);
}
catch
(e) {
message =
"Unable to parse JSON string: "
+ e.message +
"."
;
v.tools.logError(message);
v.data.dataConverted = {
"data"
: {
"nodes"
: [{
"ID"
:
"1"
,
"LABEL"
:
"ERROR: "
+ message,
"COLORVALUE"
:
"1"
,
"SIZEVALUE"
:
"1"
}],
"links"
: []
}
};
}
}
else
{
message =
"Your data string is not starting with \"<\" or \"{\" - parsing not possible."
;
v.tools.logError(message);
v.data.dataConverted = {
"data"
: {
"nodes"
: [{
"ID"
:
"1"
,
"LABEL"
:
"ERROR: "
+ message,
"COLORVALUE"
:
"1"
,
"SIZEVALUE"
:
"1"
}],
"links"
: []
}
};
}
if
(v.conf.debug) {
v.tools.log(
"Data string:"
);
v.tools.log(data,
true
);
v.tools.log(
"Converted data object:"
);
v.tools.log(v.data.dataConverted,
true
);
}
}
else
{
message =
"Unable to parse your data - input data can be a XML string, "
+
"JSON string or JavaScript object."
;
v.tools.logError(message);
v.data.dataConverted = {
"data"
: {
"nodes"
: [{
"ID"
:
"1"
,
"LABEL"
:
"ERROR: "
+ message,
"COLORVALUE"
:
"1"
,
"SIZEVALUE"
:
"1"
}],
"links"
: []
}
};
}
if
(v.data.dataConverted !==
null
) {
if
(v.data.dataConverted.hasOwnProperty(
"data"
) && v.data.dataConverted.data !==
null
) {
if
(v.data.dataConverted.data.hasOwnProperty(
"nodes"
) && v.data.dataConverted.data.nodes !==
null
) {
v.data.nodes = v.data.dataConverted.data.nodes;
if
(v.data.nodes.length === 0) {
message =
"Your data contains an empty nodes array."
;
v.tools.logError(message);
v.data.nodes = [{
"ID"
:
"1"
,
"LABEL"
:
"ERROR: "
+ message,
"COLORVALUE"
:
"1"
,
"SIZEVALUE"
:
"1"
}];
}
}
else
{
message =
"Your data contains no nodes."
;
v.tools.logError(message);
v.data.nodes = [{
"ID"
:
"1"
,
"LABEL"
:
"ERROR: "
+ message,
"COLORVALUE"
:
"1"
,
"SIZEVALUE"
:
"1"
}];
}
if
(v.data.dataConverted.data.hasOwnProperty(
"links"
) && v.data.dataConverted.data.links !==
null
) {
v.data.links = v.data.dataConverted.data.links;
}
else
{
v.data.links = [];
}
}
else
{
message =
"Missing root element named data."
;
v.tools.logError(message);
v.data = {
"nodes"
: [{
"ID"
:
"1"
,
"LABEL"
:
"ERROR: "
+ message,
"COLORVALUE"
:
"1"
,
"SIZEVALUE"
:
"1"
}],
"links"
: []
};
}
}
else
{
message =
"Unable to parse your data - please consult the API reference for possible data formats."
;
v.tools.logError(message);
v.data = {
"nodes"
: [{
"ID"
:
"1"
,
"LABEL"
:
"ERROR: "
+ message,
"COLORVALUE"
:
"1"
,
"SIZEVALUE"
:
"1"
}],
"links"
: []
};
}
v.data.idLookup = [];
v.data.nodes.forEach(
function
(n) {
n.SIZEVALUE = parseFloat(n.SIZEVALUE);
n.LABELCIRCULAR = v.tools.parseBool(n.LABELCIRCULAR);
if
(n.fixed) {
n.fixed = v.tools.parseBool(n.fixed);
}
if
(n.x) {
n.x = parseFloat(n.x);
}
if
(n.y) {
n.y = parseFloat(n.y);
}
v.data.idLookup[n.ID] = n;
});
v.data.links.forEach(
function
(l) {
l.source = v.data.idLookup[l.FROMID];
l.target = v.data.idLookup[l.TOID];
});
v.data.links = v.data.links.filter(
function
(l) {
return
typeof
l.source !==
"undefined"
&&
typeof
l.target !==
"undefined"
;
});
v.data.neighbors = v.data.links.map(
function
(l) {
return
l.FROMID +
":"
+ l.TOID;
});
v.data.distinctNodeColorValues = v.data.nodes
.map(
function
(n) {
return
(n.COLORLABEL ? n.COLORLABEL :
""
) +
";"
+ n.COLORVALUE;
})
.filter(
function
(value, index, self) {
return
self.indexOf(value) === index;
})
.sort(
function
(a, b) {
var
x = a.toLowerCase(),
y = b.toLowerCase();
return
x < y ? 1 : x > y ? -1 : 0;
});
v.data.distinctLinkColorValues = v.data.links
.map(
function
(l) {
return
l.COLOR;
})
.filter(Boolean)
.filter(
function
(value, index, self) {
return
self.indexOf(value) === index;
})
.sort(
function
(a, b) {
var
x = a.toLowerCase(),
y = b.toLowerCase();
return
x < y ? 1 : x > y ? -1 : 0;
});
if
(v.conf.positions) {
if
(v.conf.positions.constructor === Array) {
v.conf.positions.forEach(
function
(n) {
if
(v.data.idLookup[n.ID] !== undefined) {
if
(!v.data.idLookup[n.ID].fixed) {
v.data.idLookup[n.ID].fixed = n.fixed;
}
if
(!v.data.idLookup[n.ID].x) {
v.data.idLookup[n.ID].x = v.data.idLookup[n.ID].px = n.x;
}
if
(!v.data.idLookup[n.ID].y) {
v.data.idLookup[n.ID].y = v.data.idLookup[n.ID].py = n.y;
}
}
});
}
else
{
v.tools.logError(
"Unable to set node positions: positions method parameter must be an array of "
+
"node positions"
);
}
}
else
if
(v.status.graphOldPositions) {
v.status.graphOldPositions.forEach(
function
(n) {
if
(v.data.idLookup[n.ID] !== undefined) {
if
(!v.data.idLookup[n.ID].fixed) {
v.data.idLookup[n.ID].fixed = n.fixed;
}
if
(!v.data.idLookup[n.ID].x) {
v.data.idLookup[n.ID].x = v.data.idLookup[n.ID].px = n.x;
}
if
(!v.data.idLookup[n.ID].y) {
v.data.idLookup[n.ID].y = v.data.idLookup[n.ID].py = n.y;
}
}
});
}
v.conf.positions =
null
;
v.status.graphOldPositions =
null
;
}
v.tools.setColorFunction();
v.tools.setRadiusFunction();
v.data.nodes.forEach(
function
(n) {
n.radius = v.tools.radius(n.SIZEVALUE);
});
v.main.markers = v.dom.defs.selectAll(
"marker.custom"
)
.data(v.data.distinctLinkColorValues,
function
(m) {
return
m;
});
v.main.markers.enter().append(
"svg:marker"
)
.attr(
"id"
,
function
(m) {
return
v.dom.containerId +
"_"
+ m;
})
.attr(
"class"
,
"custom"
)
.attr(
"stroke"
,
"none"
)
.attr(
"fill"
,
function
(m) {
return
m;
})
.attr(
"viewBox"
,
"0 0 10 10"
)
.attr(
"refX"
, 10)
.attr(
"refY"
, 5)
.attr(
"markerWidth"
, 5)
.attr(
"markerHeight"
, 5)
.attr(
"orient"
,
"auto"
)
.attr(
"markerUnits"
,
"strokeWidth"
)
.append(
"svg:path"
)
.attr(
"d"
,
"M0,0 L10,5 L0,10"
);
v.main.markers.exit().remove();
v.main.links = v.dom.graph.selectAll(
"line.link"
)
.data(v.data.links.filter(
function
(l) {
return
l.FROMID !== l.TOID;
}),
function
(l) {
return
l.FROMID +
"_"
+ l.TOID;
});
v.main.links.enter().append(
"svg:line"
)
.attr(
"class"
,
"link"
)
.on(
"mouseenter"
, v.tools.onLinkMouseenter)
.on(
"mouseleave"
, v.tools.onLinkMouseleave)
.on(
"click"
, v.tools.onLinkClick);
v.main.links.exit().remove();
v.main.links
.style(
"marker-end"
, v.tools.getMarkerUrl)
.classed(
"dotted"
,
function
(l) {
return
(l.STYLE ===
"dotted"
);
})
.classed(
"dashed"
,
function
(l) {
return
(l.STYLE ===
"dashed"
);
})
.style(
"stroke"
,
function
(l) {
return
(l.COLOR ? l.COLOR :
null
);
});
v.main.selfLinks = v.dom.graph.selectAll(
"path.link"
)
.data(v.data.links.filter(
function
(l) {
return
l.FROMID === l.TOID && v.conf.showSelfLinks;
}),
function
(l) {
return
l.FROMID +
"_"
+ l.TOID;
});
v.main.selfLinks.enter().append(
"svg:path"
)
.attr(
"id"
,
function
(l) {
return
v.dom.containerId +
"_link_"
+ l.FROMID +
"_"
+ l.TOID;
})
.attr(
"class"
,
"link"
)
.on(
"mouseenter"
, v.tools.onLinkMouseenter)
.on(
"mouseleave"
, v.tools.onLinkMouseleave)
.on(
"click"
, v.tools.onLinkClick);
v.main.selfLinks.exit().remove();
v.main.selfLinks
.attr(
"d"
,
function
(l) {
return
v.tools.getSelfLinkPath(l);
})
.style(
"marker-end"
, v.tools.getMarkerUrl)
.classed(
"dotted"
,
function
(l) {
return
(l.STYLE ===
"dotted"
);
})
.classed(
"dashed"
,
function
(l) {
return
(l.STYLE ===
"dashed"
);
})
.style(
"stroke"
,
function
(l) {
return
(l.COLOR ? l.COLOR :
null
);
});
v.main.patterns = v.dom.defs.selectAll(
"pattern"
)
.data(v.data.nodes.filter(
function
(n) {
return
(n.IMAGE ?
true
:
false
);
}),
function
(n) {
return
n.ID;
});
v.main.patterns.enter().append(
"svg:pattern"
)
.attr(
"id"
,
function
(n) {
return
v.dom.containerId +
"_pattern_"
+ n.ID;
})
.append(
"svg:image"
);
v.main.patterns.exit().remove();
v.main.patterns.each(
function
() {
d3.select(
this
)
.attr(
"x"
, 0)
.attr(
"y"
, 0)
.attr(
"height"
,
function
(n) {
return
n.radius * 2;
})
.attr(
"width"
,
function
(n) {
return
n.radius * 2;
});
d3.select(
this
.firstChild)
.attr(
"x"
, 0)
.attr(
"y"
, 0)
.attr(
"height"
,
function
(n) {
return
n.radius * 2;
})
.attr(
"width"
,
function
(n) {
return
n.radius * 2;
})
.attr(
"xlink:href"
,
function
(n) {
return
n.IMAGE;
});
});
v.main.nodes = v.dom.graph.selectAll(
"circle.node"
)
.data(v.data.nodes,
function
(n) {
return
n.ID;
});
v.main.nodes.enter().append(
"svg:circle"
)
.attr(
"class"
,
"node"
)
.attr(
"cx"
,
function
(n) {
if
(!n.fixed && !n.x) {
n.x = Math.floor((Math.random() * v.tools.getGraphWidth()) + 1);
return
n.x;
}
})
.attr(
"cy"
,
function
(n) {
if
(!n.fixed && !n.y) {
n.y = Math.floor((Math.random() * v.conf.height) + 1);
return
n.y;
}
})
.on(
"mouseenter"
, v.tools.onNodeMouseenter)
.on(
"mouseleave"
, v.tools.onNodeMouseleave)
.on(
"click"
, v.tools.onNodeClick)
.on(
"dblclick"
, v.tools.onNodeDblclick)
.on(
"contextmenu"
, v.tools.onNodeContextmenu);
v.main.nodes.exit().remove();
v.main.nodes
.attr(
"r"
,
function
(n) {
return
n.radius;
})
.attr(
"fill"
,
function
(n) {
return
(n.IMAGE ?
"url(#"
+ v.dom.containerId +
"_pattern_"
+ n.ID +
")"
: v.tools.color(n.COLORVALUE));
});
if
(v.conf.showLabels) {
v.main.labels = v.dom.graph.selectAll(
"text.label"
)
.data(v.data.nodes.filter(
function
(n) {
return
!n.LABELCIRCULAR && !v.conf.labelsCircular;
}),
function
(n) {
return
n.ID;
});
v.main.labels.enter().append(
"svg:text"
)
.attr(
"class"
,
"label"
);
v.main.labels.exit().remove();
v.main.labels.text(
function
(n) {
return
n.LABEL;
});
v.main.labelPaths = v.dom.defs.selectAll(
"path.label"
)
.data(v.data.nodes.filter(
function
(n) {
return
n.LABELCIRCULAR || v.conf.labelsCircular;
}),
function
(n) {
return
n.ID;
});
v.main.labelPaths.enter().append(
"svg:path"
)
.attr(
"id"
,
function
(n) {
return
v.dom.containerId +
"_textPath_"
+ n.ID;
})
.attr(
"class"
,
"label"
);
v.main.labelPaths.exit().remove();
v.main.labelPaths.attr(
"d"
,
function
(n) {
return
v.tools.getLabelPath(n);
});
v.main.labelsCircular = v.dom.graph.selectAll(
"text.labelCircular"
)
.data(v.data.nodes.filter(
function
(n) {
return
n.LABELCIRCULAR || v.conf.labelsCircular;
}),
function
(n) {
return
n.ID;
});
v.main.labelsCircular.enter().append(
"svg:text"
)
.attr(
"class"
,
"labelCircular"
)
.append(
"svg:textPath"
)
.attr(
"xlink:href"
,
function
(n) {
return
"#"
+ v.dom.containerId +
"_textPath_"
+ n.ID;
});
v.main.labelsCircular.exit().remove();
v.main.labelsCircular.each(
function
(n) {
d3.select(
this
.firstChild).text(n.LABEL);
});
}
else
{
v.dom.defs.selectAll(
"path.label"
).remove();
v.dom.graph.selectAll(
"text.label,text.labelCircular"
).remove();
}
graph
.debug(v.conf.debug)
.showBorder(v.conf.showBorder)
.setDomParentPaddingToZero(v.conf.setDomParentPaddingToZero)
.useDomParentWidth(v.conf.useDomParentWidth)
.width(v.conf.width)
.height(v.conf.height)
.alignFixedNodesToGrid(v.conf.alignFixedNodesToGrid)
.dragMode(v.conf.dragMode)
.pinMode(v.conf.pinMode)
.lassoMode(v.conf.lassoMode)
.zoomMode(v.conf.zoomMode)
.transform(v.conf.transform)
.autoRefresh(v.conf.autoRefresh)
.linkDistance(v.conf.linkDistance)
.wrapLabels(v.conf.wrapLabels)
.charge(v.conf.charge)
.chargeDistance(v.conf.chargeDistance)
.gravity(v.conf.gravity)
.linkStrength(v.conf.linkStrength)
.friction(v.conf.friction)
.theta(v.conf.theta);
v.main.force
.nodes(v.data.nodes)
.links(v.data.links)
.start();
if
(v.status.customize) {
v.tools.createCustomizeWizard();
}
else
{
v.tools.createCustomizeLink();
}
v.status.graphReady =
true
;
v.status.graphRendering =
false
;
v.tools.triggerApexEvent(document.querySelector(
"#"
+ v.dom.containerId),
"apexafterrefresh"
);
return
graph;
};
graph.resume =
function
() {
v.main.force.resume();
v.tools.createCustomizeWizardIfNotRendering();
return
graph;
};
graph.showBorder =
function
(value) {
if
(!arguments.length) {
return
v.conf.showBorder;
}
v.conf.showBorder = value;
if
(v.status.graphStarted) {
v.dom.svg.classed(
"border"
, v.conf.showBorder);
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.showLegend =
function
(value) {
if
(!arguments.length) {
return
v.conf.showLegend;
}
v.conf.showLegend = value;
if
(v.status.graphStarted) {
if
(v.conf.showLegend) {
v.tools.removeLegend();
v.tools.createLegend();
}
else
{
v.tools.removeLegend();
}
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.showSelfLinks =
function
(value) {
if
(!arguments.length) {
return
v.conf.showSelfLinks;
}
v.conf.showSelfLinks = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.showLinkDirection =
function
(value) {
if
(!arguments.length) {
return
v.conf.showLinkDirection;
}
v.conf.showLinkDirection = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.showTooltips =
function
(value) {
if
(!arguments.length) {
return
v.conf.showTooltips;
}
v.conf.showTooltips = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.tooltipPosition =
function
(value) {
if
(!arguments.length) {
return
v.conf.tooltipPosition;
}
v.conf.tooltipPosition = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.colorScheme =
function
(value) {
if
(!arguments.length) {
return
v.conf.colorScheme;
}
v.conf.colorScheme = value;
v.tools.setColorFunction();
if
(v.status.graphStarted) {
v.main.nodes
.attr(
"fill"
,
function
(n) {
return
(n.IMAGE ?
"url(#"
+ v.dom.containerId +
"_pattern_"
+ n.ID +
")"
:
v.tools.color(n.COLORVALUE));
});
if
(v.conf.showLegend) {
v.tools.removeLegend();
v.tools.createLegend();
}
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.showLabels =
function
(value) {
if
(!arguments.length) {
return
v.conf.showLabels;
}
v.conf.showLabels = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.wrapLabels =
function
(value) {
if
(!arguments.length) {
return
v.conf.wrapLabels;
}
v.conf.wrapLabels = value;
if
(v.conf.wrapLabels) {
v.status.wrapLabelsOnNextTick =
true
;
}
if
(v.status.graphStarted) {
v.main.labels.each(
function
() { d3.select(
this
).attr(
"lines"
,
null
) });
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.wrappedLabelWidth =
function
(value) {
if
(!arguments.length) {
return
v.conf.wrappedLabelWidth;
}
v.conf.wrappedLabelWidth = value;
if
(v.conf.wrapLabels && v.main.labels) {
v.main.labels.each(
function
() { d3.select(
this
).attr(
"lines"
,
null
) });
v.status.wrapLabelsOnNextTick =
true
;
}
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.wrappedLabelLineHeight =
function
(value) {
if
(!arguments.length) {
return
v.conf.wrappedLabelLineHeight;
}
v.conf.wrappedLabelLineHeight = value;
if
(v.conf.wrapLabels) {
v.status.wrapLabelsOnNextTick =
true
;
}
if
(v.status.graphStarted) {
v.main.labels.each(
function
() { d3.select(
this
).attr(
"lines"
,
null
) });
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.labelsCircular =
function
(value) {
if
(!arguments.length) {
return
v.conf.labelsCircular;
}
v.conf.labelsCircular = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.labelDistance =
function
(value) {
if
(!arguments.length) {
return
v.conf.labelDistance;
}
v.conf.labelDistance = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.preventLabelOverlappingOnForceEnd =
function
(value) {
if
(!arguments.length) {
return
v.conf.preventLabelOverlappingOnForceEnd;
}
v.conf.preventLabelOverlappingOnForceEnd = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.labelPlacementIterations =
function
(value) {
if
(!arguments.length) {
return
v.conf.labelPlacementIterations;
}
v.conf.labelPlacementIterations = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.dragMode =
function
(value) {
if
(!arguments.length) {
return
v.conf.dragMode;
}
v.conf.dragMode = value;
if
(v.status.graphStarted) {
if
(v.conf.dragMode) {
v.main.nodes.call(v.main.drag);
}
else
{
v.main.nodes.on(
"mousedown.drag"
,
null
);
v.main.nodes.on(
"touchstart.drag"
,
null
);
}
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.pinMode =
function
(value) {
if
(!arguments.length) {
return
v.conf.pinMode;
}
v.conf.pinMode = value;
if
(v.status.graphStarted) {
if
(v.conf.pinMode) {
v.main.drag.on(
"dragstart"
,
function
(n) {
d3.select(
this
).classed(
"fixed"
, n.fixed = 1);
});
}
else
{
v.main.drag.on(
"dragstart"
,
null
);
}
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.lassoMode =
function
(value) {
if
(!arguments.length) {
return
v.conf.lassoMode;
}
v.conf.lassoMode = value;
if
(v.status.graphStarted) {
if
(v.conf.lassoMode) {
v.dom.graphOverlay.call(v.main.lasso);
v.main.lasso.items(v.main.nodes);
v.main.lasso.on(
"start"
,
function
() {
v.main.lasso.items().classed(
"selected"
,
false
);
v.tools.onLassoStart(v.main.lasso.items());
});
v.main.lasso.on(
"draw"
,
function
() {
v.main.lasso.items().filter(
function
(d) {
return
d.possible ===
true
;
})
.classed(
"selected"
,
true
);
v.main.lasso.items().filter(
function
(d) {
return
d.possible ===
false
;
})
.classed(
"selected"
,
false
);
});
v.main.lasso.on(
"end"
,
function
() {
v.main.lasso.items().filter(
function
(d) {
return
d.selected ===
true
;
})
.classed(
"selected"
,
true
);
v.main.lasso.items().filter(
function
(d) {
return
d.selected ===
false
;
})
.classed(
"selected"
,
false
);
v.tools.onLassoEnd(v.main.lasso.items());
});
v.events.mousedownLasso = v.dom.graphOverlay.on(
"mousedown.drag"
);
v.events.touchstartLasso = v.dom.graphOverlay.on(
"touchstart.drag"
);
v.dom.graphOverlay.on(
"mousedown.drag"
, v.tools.lassoEventProxy(v.events.mousedownLasso));
v.dom.graphOverlay.on(
"touchstart.drag"
, v.tools.lassoEventProxy(v.events.touchstartLasso));
}
else
{
v.dom.graphOverlay.on(
".drag"
,
null
);
v.main.nodes.classed(
"selected"
,
false
);
}
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.zoomMode =
function
(value) {
if
(!arguments.length) {
return
v.conf.zoomMode;
}
v.conf.zoomMode = value;
if
(v.status.graphStarted) {
if
(v.conf.zoomMode) {
v.main.zoom.scaleExtent([v.conf.minZoomFactor, v.conf.maxZoomFactor])
.size([v.tools.getGraphWidth(), v.conf.height])
.on(
"zoom"
, v.main.zoomed);
v.dom.graphOverlay.call(v.main.zoom);
v.events.dblclickZoom = v.dom.graphOverlay.on(
"dblclick.zoom"
);
v.events.mousedownZoom = v.dom.graphOverlay.on(
"mousedown.zoom"
);
v.events.touchstartZoom = v.dom.graphOverlay.on(
"touchstart.zoom"
);
v.dom.graphOverlay.on(
"dblclick.zoom"
, v.tools.zoomEventProxy(v.events.dblclickZoom));
v.dom.graphOverlay.on(
"mousedown.zoom"
, v.tools.zoomEventProxy(v.events.mousedownZoom));
v.dom.graphOverlay.on(
"touchstart.zoom"
, v.tools.zoomEventProxy(v.events.touchstartZoom));
if
(JSON.stringify(v.conf.transform) !== JSON.stringify(v.confDefaults.transform)) {
v.dom.graph.attr(
"transform"
,
"translate("
+ v.main.zoom.translate() +
")scale("
+
v.main.zoom.scale() +
")"
);
v.tools.writeConfObjectIntoWizard();
}
}
else
{
v.dom.graphOverlay.on(
".zoom"
,
null
);
v.main.zoom.translate([0, 0]);
v.main.zoom.scale(1);
v.conf.transform = {
"translate"
: [0, 0],
"scale"
: 1
};
v.dom.graph.attr(
"transform"
,
"translate(0,0)scale(1)"
);
}
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.minZoomFactor =
function
(value) {
if
(!arguments.length) {
return
v.conf.minZoomFactor;
}
v.conf.minZoomFactor = value;
if
(v.status.graphReady) {
graph.zoomMode(v.conf.zoomMode);
}
return
graph;
};
graph.maxZoomFactor =
function
(value) {
if
(!arguments.length) {
return
v.conf.maxZoomFactor;
}
v.conf.maxZoomFactor = value;
if
(v.status.graphReady) {
graph.zoomMode(v.conf.zoomMode);
}
return
graph;
};
graph.zoom =
function
(centerX, centerY, viewportWidth) {
graph.zoomSmooth(centerX, centerY, viewportWidth, 0);
return
graph;
};
graph.zoomSmooth =
function
(centerX, centerY, viewportWidth, duration) {
var
x, y, scale;
var
width = v.tools.getGraphWidth();
centerX = (isNaN(centerX) ? width / 2 : parseInt(centerX));
centerY = (isNaN(centerY) ? v.conf.height / 2 : parseInt(centerY));
viewportWidth = (isNaN(viewportWidth) ? width : parseInt(viewportWidth));
duration = (isNaN(duration) ? 1500 : parseInt(duration));
scale = width / viewportWidth;
x = width / 2 - centerX * scale;
y = v.conf.height / 2 - centerY * scale;
v.main.interpolateZoom([x, y], scale, duration);
return
graph;
};
graph.transform =
function
(transform) {
if
(!arguments.length) {
return
{
"translate"
: v.main.zoom.translate(),
"scale"
: v.main.zoom.scale()
};
}
else
{
v.main.interpolateZoom(transform.translate, transform.scale, 0);
}
return
graph;
};
graph.zoomToFit =
function
(duration) {
var
svg = {},
graph_, padding = 10,
x, y, scale;
duration = (isNaN(duration) ? 500 : parseInt(duration));
svg.width = v.tools.getGraphWidth();
svg.height = v.conf.height;
graph_ = v.dom.graph.node().getBBox();
scale = Math.min((svg.height - 2 * padding) / graph_.height,
(svg.width - 2 * padding) / graph_.width);
x = (svg.width - graph_.width * scale) / 2 - graph_.x * scale;
y = (svg.height - graph_.height * scale) / 2 - graph_.y * scale;
v.main.interpolateZoom([x, y], scale, duration);
return
graph;
};
graph.zoomToFitOnForceEnd =
function
(value) {
if
(!arguments.length) {
return
v.conf.zoomToFitOnForceEnd;
}
v.conf.zoomToFitOnForceEnd = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.showLoadingIndicatorOnAjaxCall =
function
(value) {
if
(!arguments.length) {
return
v.conf.showLoadingIndicatorOnAjaxCall;
}
v.conf.showLoadingIndicatorOnAjaxCall = value;
return
graph;
};
graph.showLoadingIndicator =
function
(value) {
if
(v.tools.parseBool(value)) {
v.dom.loading.style(
"display"
,
"block"
);
}
else
{
v.dom.loading.style(
"display"
,
"none"
);
}
return
graph;
};
graph.alignFixedNodesToGrid =
function
(value) {
if
(!arguments.length) {
return
v.conf.alignFixedNodesToGrid;
}
v.conf.alignFixedNodesToGrid = value;
if
(v.status.graphStarted) {
if
(v.conf.alignFixedNodesToGrid) {
if
(v.status.graphReady) {
v.main.nodes.each(
function
(n) {
if
(n.fixed) {
n.x = n.px = v.tools.getNearestGridPosition(n.x, v.conf.width);
n.y = n.py = v.tools.getNearestGridPosition(n.y, v.conf.height);
}
});
}
v.main.drag.on(
"dragend"
,
function
(n) {
n.x = n.px = v.tools.getNearestGridPosition(n.x, v.conf.width);
n.y = n.py = v.tools.getNearestGridPosition(n.y, v.conf.height);
});
}
else
{
v.main.drag.on(
"dragend"
,
null
);
}
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.gridSize =
function
(value) {
if
(!arguments.length) {
return
v.conf.gridSize;
}
v.conf.gridSize = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.moveFixedNodes =
function
(x, y) {
if
(v.status.graphStarted) {
if
(!x) {
x = 0;
}
if
(!y) {
y = 0;
}
if
(x !== 0 || y !== 0) {
v.main.nodes.each(
function
(n) {
if
(n.fixed) {
n.x = n.px = (v.conf.alignFixedNodesToGrid ?
v.tools.getNearestGridPosition(n.x + x, v.conf.width) : n.x + x);
n.y = n.py = (v.conf.alignFixedNodesToGrid ?
v.tools.getNearestGridPosition(n.y + y, v.conf.width) : n.y + y);
}
});
}
}
return
graph;
};
graph.releaseFixedNodes =
function
() {
if
(v.status.graphStarted) {
v.main.nodes.each(
function
(n) {
n.fixed = 0;
});
}
return
graph;
};
graph.nodeEventToStopPinMode =
function
(value) {
if
(!arguments.length) {
return
v.conf.nodeEventToStopPinMode;
}
v.conf.nodeEventToStopPinMode = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.onNodeContextmenuPreventDefault =
function
(value) {
if
(!arguments.length) {
return
v.conf.onNodeContextmenuPreventDefault;
}
v.conf.onNodeContextmenuPreventDefault = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.nodeEventToOpenLink =
function
(value) {
if
(!arguments.length) {
return
v.conf.nodeEventToOpenLink;
}
v.conf.nodeEventToOpenLink = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.nodeLinkTarget =
function
(value) {
if
(!arguments.length) {
return
v.conf.nodeLinkTarget;
}
v.conf.nodeLinkTarget = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.autoRefresh =
function
(value) {
if
(!arguments.length) {
return
v.conf.autoRefresh;
}
v.conf.autoRefresh = value;
if
(v.status.graphStarted) {
if
(v.conf.autoRefresh && v.conf.refreshInterval && !v.conf.interval) {
v.conf.interval = window.setInterval(
function
() {
graph.start();
}, v.conf.refreshInterval);
v.tools.log(
"Auto refresh started with an interval of "
+ v.conf.refreshInterval +
" milliseconds."
);
}
else
if
(!v.conf.autoRefresh && v.conf.interval) {
clearInterval(v.conf.interval);
v.conf.interval =
null
;
v.tools.log(
"Auto refresh stopped."
);
}
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.refreshInterval =
function
(value) {
if
(!arguments.length) {
return
v.conf.refreshInterval;
}
v.conf.refreshInterval = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.useDomParentWidth =
function
(value) {
if
(!arguments.length) {
return
v.conf.useDomParentWidth;
}
v.conf.useDomParentWidth = value;
if
(v.status.graphStarted) {
if
(v.conf.useDomParentWidth) {
v.dom.containerWidth = v.tools.getSvgParentInnerWidth();
d3.select(window).on(
"resize"
,
function
() {
var
oldWidth = v.dom.containerWidth;
var
newWidth = v.tools.getSvgParentInnerWidth();
if
(oldWidth !== newWidth) {
v.dom.containerWidth = newWidth;
graph.width(v.conf.width).resume();
}
});
}
else
{
d3.select(window).on(
"resize"
,
null
);
}
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.setDomParentPaddingToZero =
function
(value) {
if
(!arguments.length) {
return
v.conf.setDomParentPaddingToZero;
}
v.conf.setDomParentPaddingToZero = value;
if
(v.status.graphStarted) {
if
(v.conf.setDomParentPaddingToZero) {
v.dom.svgParent.style(
"padding"
,
"0"
);
}
else
{
v.dom.svgParent.style(
"padding"
,
null
);
}
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.domParentWidth =
function
() {
return
v.dom.containerWidth || v.tools.getSvgParentInnerWidth();
};
graph.width =
function
(value) {
if
(!arguments.length) {
return
v.conf.width;
}
v.conf.width = value;
if
(v.status.graphStarted) {
v.dom.svg.attr(
"width"
, v.tools.getGraphWidth());
v.dom.graphOverlaySizeHelper.attr(
"width"
, v.tools.getGraphWidth());
v.dom.loadingRect.attr(
"width"
, v.tools.getGraphWidth());
v.dom.loadingText.attr(
"x"
, v.tools.getGraphWidth() / 2);
v.main.force.size([v.tools.getGraphWidth(), v.conf.height]);
if
(v.conf.zoomMode) {
v.main.zoom.size([v.tools.getGraphWidth(), v.conf.height]);
}
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.height =
function
(value) {
if
(!arguments.length) {
return
v.conf.height;
}
v.conf.height = value;
if
(v.status.graphStarted) {
v.dom.svg.attr(
"height"
, v.conf.height);
v.dom.graphOverlaySizeHelper.attr(
"height"
, v.conf.height);
v.dom.loadingRect.attr(
"height"
, v.conf.height);
v.dom.loadingText.attr(
"y"
, v.conf.height / 2);
v.main.force.size([v.tools.getGraphWidth(), v.conf.height]);
if
(v.conf.showLegend) {
v.tools.removeLegend();
v.tools.createLegend();
}
if
(v.conf.zoomMode) {
v.main.zoom.size([v.tools.getGraphWidth(), v.conf.height]);
}
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.minNodeRadius =
function
(value) {
if
(!arguments.length) {
return
v.conf.minNodeRadius;
}
v.conf.minNodeRadius = value;
if
(v.status.graphReady) {
v.tools.setRadiusFunction();
v.main.nodes.each(
function
(n) {
n.radius = v.tools.radius(n.SIZEVALUE);
});
v.main.nodes.attr(
"r"
,
function
(n) {
return
n.radius;
});
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.maxNodeRadius =
function
(value) {
if
(!arguments.length) {
return
v.conf.maxNodeRadius;
}
v.conf.maxNodeRadius = value;
if
(v.status.graphReady) {
v.tools.setRadiusFunction();
v.main.nodes.each(
function
(n) {
n.radius = v.tools.radius(n.SIZEVALUE);
});
v.main.nodes.attr(
"r"
,
function
(n) {
return
n.radius;
});
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.selfLinkDistance =
function
(value) {
if
(!arguments.length) {
return
v.conf.selfLinkDistance;
}
v.conf.selfLinkDistance = value;
if
(v.status.graphStarted) {
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.linkDistance =
function
(value) {
if
(!arguments.length) {
return
v.conf.linkDistance;
}
v.conf.linkDistance = value;
if
(v.status.graphStarted) {
v.main.force.linkDistance(v.conf.linkDistance);
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.charge =
function
(value) {
if
(!arguments.length) {
return
v.conf.charge;
}
v.conf.charge = value;
if
(v.status.graphStarted) {
v.main.force.charge(v.conf.charge);
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.chargeDistance =
function
(value) {
if
(!arguments.length) {
return
v.conf.chargeDistance;
}
v.conf.chargeDistance = value;
if
(v.status.graphStarted) {
v.main.force.chargeDistance(v.conf.chargeDistance);
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.gravity =
function
(value) {
if
(!arguments.length) {
return
v.conf.gravity;
}
v.conf.gravity = value;
if
(v.status.graphStarted) {
v.main.force.gravity(v.conf.gravity);
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.linkStrength =
function
(value) {
if
(!arguments.length) {
return
v.conf.linkStrength;
}
v.conf.linkStrength = value;
if
(v.status.graphStarted) {
v.main.force.linkStrength(v.conf.linkStrength);
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.friction =
function
(value) {
if
(!arguments.length) {
return
v.conf.friction;
}
v.conf.friction = value;
if
(v.status.graphStarted) {
v.main.force.friction(v.conf.friction);
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.theta =
function
(value) {
if
(!arguments.length) {
return
v.conf.theta;
}
v.conf.theta = value;
if
(v.status.graphStarted) {
v.main.force.theta(v.conf.theta);
v.tools.createCustomizeWizardIfNotRendering();
}
return
graph;
};
graph.positions =
function
(positionsArray) {
if
(!arguments.length) {
var
positions = [];
v.data.nodes.forEach(
function
(n) {
positions.push({
"ID"
: n.ID,
"x"
: Math.round(n.x),
"y"
: Math.round(n.y),
"fixed"
: (n.fixed ? 1 : 0)
});
});
return
positions;
}
else
{
if
(v.status.graphReady) {
if
(positionsArray.constructor === Array) {
positionsArray.forEach(
function
(n) {
if
(v.data.idLookup[n.ID] !== undefined) {
v.data.idLookup[n.ID].fixed = v.tools.parseBool(n.fixed);
v.data.idLookup[n.ID].x = v.data.idLookup[n.ID].px = n.x;
v.data.idLookup[n.ID].y = v.data.idLookup[n.ID].py = n.y;
}
});
}
else
{
v.tools.logError(
"Unable to set node positions: positions method parameter must be an array of "
+
"node positions"
);
}
}
else
{
v.conf.positions = positionsArray;
}
return
graph;
}
};
graph.onLinkClickFunction =
function
(eventFunction) {
if
(!arguments.length) {
return
v.conf.onLinkClickFunction;
}
v.conf.onLinkClickFunction = eventFunction;
return
graph;
};
graph.onNodeMouseenterFunction =
function
(eventFunction) {
if
(!arguments.length) {
return
v.conf.onNodeMouseenterFunction;
}
v.conf.onNodeMouseenterFunction = eventFunction;
return
graph;
};
graph.onNodeMouseleaveFunction =
function
(value) {
if
(!arguments.length) {
return
v.conf.onNodeMouseleaveFunction;
}
v.conf.onNodeMouseleaveFunction = value;
return
graph;
};
graph.onNodeClickFunction =
function
(value) {
if
(!arguments.length) {
return
v.conf.onNodeClickFunction;
}
v.conf.onNodeClickFunction = value;
return
graph;
};
graph.onNodeDblclickFunction =
function
(value) {
if
(!arguments.length) {
return
v.conf.onNodeDblclickFunction;
}
v.conf.onNodeDblclickFunction = value;
return
graph;
};
graph.onNodeContextmenuFunction =
function
(value) {
if
(!arguments.length) {
return
v.conf.onNodeContextmenuFunction;
}
v.conf.onNodeContextmenuFunction = value;
return
graph;
};
graph.onLassoStartFunction =
function
(value) {
if
(!arguments.length) {
return
v.conf.onLassoStartFunction;
}
v.conf.onLassoStartFunction = value;
return
graph;
};
graph.onLassoEndFunction =
function
(value) {
if
(!arguments.length) {
return
v.conf.onLassoEndFunction;
}
v.conf.onLassoEndFunction = value;
return
graph;
};
graph.sampleData =
function
(data) {
if
(!arguments.length) {
return
v.data.sampleData;
}
v.data.sampleData = data;
return
graph;
};
graph.data =
function
() {
return
v.data.dataConverted;
};
graph.nodeDataById =
function
(id) {
return
v.data.idLookup[id];
};
graph.options =
function
(options) {
var
key;
if
(!arguments.length) {
var
conf = {};
for
(key
in
v.conf) {
if
(v.conf.hasOwnProperty(key)) {
if
(v.confDefaults.hasOwnProperty(key)) {
if
((v.confDefaults[key].type ===
"bool"
||
v.confDefaults[key].type ===
"number"
||
v.confDefaults[key].type ===
"text"
) &&
v.confDefaults[key].val !== v.conf[key]) {
conf[key] = v.conf[key];
}
else
if
(v.confDefaults[key].type ===
"object"
&&
JSON.stringify(v.confDefaults[key].val) !== JSON.stringify(v.conf[key])) {
conf[key] = v.conf[key];
}
}
else
if
(!v.confDefaults.hasOwnProperty(key) &&
v.conf[key] !== undefined &&
v.conf[key] !==
null
) {
conf[key] = v.conf[key];
}
}
}
return
conf;
}
else
{
v.tools.applyConfigurationObject(options);
return
graph;
}
};
graph.optionsCustomizationWizard =
function
(options) {
var
key;
if
(!arguments.length) {
var
conf = {};
for
(key
in
v.confDefaults) {
if
(v.confDefaults.hasOwnProperty(key)) {
if
((v.confDefaults[key].type ===
"bool"
||
v.confDefaults[key].type ===
"number"
||
v.confDefaults[key].type ===
"text"
) &&
v.confDefaults[key].val !== v.conf[key]) {
conf[key] = v.conf[key];
}
else
if
(v.confDefaults[key].type ===
"object"
&&
JSON.stringify(v.confDefaults[key].val) !== JSON.stringify(v.conf[key])) {
conf[key] = v.conf[key];
}
}
}
return
conf;
}
else
{
v.tools.applyConfigurationObject(options);
return
graph;
}
};
graph.customize =
function
(value) {
if
(!arguments.length) {
return
v.status.customize;
}
v.status.customize = value;
if
(v.status.graphStarted) {
if
(v.status.customize) {
v.tools.createCustomizeWizard();
v.tools.removeCustomizeLink();
}
else
{
v.tools.removeCustomizeWizard();
if
(v.conf.debug) {
v.tools.createCustomizeLink();
}
}
}
return
graph;
};
graph.debug =
function
(value) {
if
(!arguments.length) {
return
v.conf.debug;
}
v.conf.debug = value;
if
(v.status.graphStarted) {
if
(v.conf.debug) {
v.tools.createCustomizeLink();
}
else
{
v.tools.removeCustomizeLink();
}
}
return
graph;
};
graph.userAgent =
function
() {
return
v.status.userAgent;
};
graph.inspect =
function
() {
return
v;
};
graph.version =
function
() {
return
v.version;
};
if
(v.status.apexPluginId) {
apex.jQuery(
"#"
+ v.dom.containerId).bind(
"apexrefresh"
,
function
() {
graph.start();
});
apex.jQuery(window).on(
"apexwindowresized"
,
function
() {
graph.render();
});
apex.jQuery(
"#t_Button_navControl"
).click(
function
() {
setTimeout(
function
() {
graph.render();
}, 500);
});
}
return
graph;
}