Browse Source

feat: change styles if element is selected (#2446)

* element characteristic changes
* assume edge color inheritance is correct before choosing
* Adjust nodes’ chosen’s boolean -> bool
* Need to get user-reset size
* make example edges thicker for more noticeable shadow
* preemptive ES6 fix (see #2500/#2501)
* documentation for the feature that was previously overwritten
readme-improvements
David Anderson 7 years ago
committed by Alexander Wunschik
parent
commit
becf18e6eb
32 changed files with 1238 additions and 432 deletions
  1. +97
    -1
      docs/network/edges.html
  2. +85
    -0
      docs/network/nodes.html
  3. +466
    -0
      examples/network/other/chosen.html
  4. +4
    -6
      lib/network/modules/CanvasRenderer.js
  5. +0
    -13
      lib/network/modules/EdgesHandler.js
  6. +166
    -59
      lib/network/modules/components/Edge.js
  7. +67
    -2
      lib/network/modules/components/Node.js
  8. +3
    -3
      lib/network/modules/components/edges/BezierEdgeDynamic.js
  9. +3
    -3
      lib/network/modules/components/edges/BezierEdgeStatic.js
  10. +3
    -3
      lib/network/modules/components/edges/CubicBezierEdge.js
  11. +3
    -3
      lib/network/modules/components/edges/StraightEdge.js
  12. +74
    -101
      lib/network/modules/components/edges/util/EdgeBase.js
  13. +18
    -22
      lib/network/modules/components/nodes/shapes/Box.js
  14. +11
    -11
      lib/network/modules/components/nodes/shapes/Circle.js
  15. +16
    -16
      lib/network/modules/components/nodes/shapes/CircularImage.js
  16. +16
    -18
      lib/network/modules/components/nodes/shapes/Database.js
  17. +5
    -5
      lib/network/modules/components/nodes/shapes/Diamond.js
  18. +5
    -5
      lib/network/modules/components/nodes/shapes/Dot.js
  19. +16
    -18
      lib/network/modules/components/nodes/shapes/Ellipse.js
  20. +11
    -12
      lib/network/modules/components/nodes/shapes/Icon.js
  21. +4
    -4
      lib/network/modules/components/nodes/shapes/Image.js
  22. +3
    -3
      lib/network/modules/components/nodes/shapes/Square.js
  23. +5
    -5
      lib/network/modules/components/nodes/shapes/Star.js
  24. +11
    -11
      lib/network/modules/components/nodes/shapes/Text.js
  25. +3
    -3
      lib/network/modules/components/nodes/shapes/Triangle.js
  26. +3
    -3
      lib/network/modules/components/nodes/shapes/TriangleDown.js
  27. +16
    -18
      lib/network/modules/components/nodes/util/CircleImageBase.js
  28. +15
    -13
      lib/network/modules/components/nodes/util/NodeBase.js
  29. +15
    -17
      lib/network/modules/components/nodes/util/ShapeBase.js
  30. +83
    -53
      lib/network/modules/components/shared/Label.js
  31. +10
    -0
      lib/network/options.js
  32. +1
    -1
      lib/util.js

+ 97
- 1
docs/network/edges.html View File

@ -120,6 +120,7 @@ var options = {
from: {enabled: false, scaleFactor:1, type:'arrow'}
},
arrowStrikethrough: true,
chosen: true,
color: {
color:'#848484',
highlight:'#848484',
@ -298,6 +299,101 @@ network.setOptions(options);
<td><code>true</code></td>
<td>When false, the edge stops at the arrow. This can be useful if you have thick lines and you want the arrow to end in a point. Middle arrows are not affected by this.</td>
</tr>
<tr class='toggle collapsible' onclick="toggleTable('optionTable','chosen', this);">
<td><span parent="chosen" class="right-caret"></span> chosen</td>
<td>Object or Boolean</td>
<td><code>true</code></td>
<td>
When true, selecting or hovering on an edge will change it and its label's characteristics according the default.
When false, no change to the edge or its label will occur when the edge is chosen.
If an object is supplied, finer-grained adjustment of edge and label characteristics is available when an edge is chosen.
</td>
</tr>
<tr parent="chosen" class="hidden">
<td class="indent">chosen.edge</td>
<td>Function or Boolean</td>
<td>undefined</td>
<td>
When true, selecting or hovering on an edge will change its characteristics according the default.
When false, no change to the edge will occur when the edge is chosen.
<p>
If a function is supplied, it is called when the edge is chosen.
<pre class="code">
function(values, id, selected, hovering) {
values.<i>property</i> = <i>chosenValue</i>;
}</pre>
</p>
<p>
Any of the incoming arguments may be used to determine characteristic changes.
If a property is not specifically assigned by the supplied function, it will be left unchanged.
A specific function may be assigned to each particular edge in its options, or to all in the network's <code>edges</code> options.
</p>
<p>
The properties define the characteristics that can be changed as follows:
</p>
<table>
<tr><th>Property</th><th>Edge Reference</th></tr>
<tr><td>dashes</td><td>see dashes</td></tr>
<tr><td>toArrow</td><td>see arrows.to.enabled</td></tr>
<tr><td>toArrowScale</td><td>see arrows.to.scaleFactor</td></tr>
<tr><td>toArrowType</td><td>see arrows.to.type</td></tr>
<tr><td>middleArrow</td><td>see arrows.middle.enabled</td></tr>
<tr><td>middleArrowScale</td><td>see arrows.middle.scaleFactor</td></tr>
<tr><td>middleArrowType</td><td>see arrows.middle.type</td></tr>
<tr><td>fromArrow</td><td>see arrows.from.enabled</td></tr>
<tr><td>fromArrowScale</td><td>see arrows.from.scaleFactor</td></tr>
<tr><td>fromArrowType</td><td>see arrows.from.type</td></tr>
<tr><td>arrowStrikethrough</td><td>see arrowStrikethrough</td></tr>
<tr><td>color</td><td>see color.color</td></tr>
<tr><td>inheritsColor</td><td>see color.inherit</td></tr>
<tr><td>opacity</td><td>see color.opacity</td></tr>
<tr><td>hidden</td><td>see hidden</td></tr>
<tr><td>length</td><td>see length</td></tr>
<tr><td>shadow</td><td>see shadow.enabled</td></tr>
<tr><td>shadowColor</td><td>see shadow.color</td></tr>
<tr><td>shadowSize</td><td>see shadow.size</td></tr>
<tr><td>shadowX</td><td>see shadow.x</td></tr>
<tr><td>shadowY</td><td>see shadow.y</td></tr>
<tr><td>width</td><td>see width</td></tr>
</table>
<br/>
</td>
</tr>
<tr parent="chosen" class="hidden">
<td class="indent">chosen.label</td>
<td>Function or Boolean</td>
<td>undefined</td>
<td>
When true, selecting or hovering on an edge will change its label's characteristics according the default.
When false, no change to the edge's label will occur when the edge is chosen.
<p>
If a function is supplied, it is called when the edge is chosen.
<pre class="code">
function(values, id, selected, hovering) {
values.<i>property</i> = <i>chosenValue</i>;
}</pre>
</p>
<p>
Any of the incoming arguments may be used to determine characteristic changes.
If a property is not specifically assigned by the supplied function, it will be left unchanged.
A specific function may be assigned to each particular edge in its options, or to all in the network's <code>edges</code> options.
</p>
<p>
The properties define the characteristics that can be changed as follows:
</p>
<table>
<tr><th>Property</th><th>Edge Reference</th></tr>
<tr><td>color</td><td>see font.color</td></tr>
<tr><td>size</td><td>see font.size</td></tr>
<tr><td>face</td><td>see font.face</td></tr>
<tr><td>mod</td><td>font modifier ('bold', 'italic', etc.)</td></tr>
<tr><td>vadjust</td><td>see font.vadjust</td></tr>
<tr><td>strokeWidth</td><td>see font.strokeWidth</td></tr>
<tr><td>strokeColor</td><td>see font.strokeColor</td></tr>
</table>
<br/>
</td>
</tr>
<tr class='toggle collapsible' onclick="toggleTable('optionTable','color', this);">
<td><span parent="color" class="right-caret"></span> color</td>
<td>Object or String</td>
@ -311,7 +407,7 @@ network.setOptions(options);
<td class="indent">color.color</td>
<td>String</td>
<td><code>'#848484'</code></td>
<td>The color of the border of the node when it is not selected or hovered over <i>(assuming hover is
<td>The color of the edge when it is not selected or hovered over <i>(assuming hover is
enabled in the interaction module)</i>.
</td>
</tr>

+ 85
- 0
docs/network/nodes.html View File

@ -110,6 +110,7 @@ var options = {
borderWidth: 1,
borderWidthSelected: 2,
brokenImage:undefined,
chosen: true,
color: {
border: '#2B7CE9',
background: '#97C2FC',
@ -271,6 +272,90 @@ network.setOptions(options);
a backup image in case the URL supplied in the image option cannot be resolved.
</td>
</tr>
<tr class='toggle collapsible' onclick="toggleTable('optionTable','chosen', this);">
<td><span parent="chosen" class="right-caret"></span> chosen</td>
<td>Object or Boolean</td>
<td><code>true</code></td>
<td>
When true, selecting or hovering on a node will change it and its label's characteristics according the default.
When false, no change to the node or its label will occur when the node is chosen.
If an object is supplied, finer-grained adjustment of node and label characteristics is available when a node is chosen.
</td>
</tr>
<tr parent="chosen" class="hidden">
<td class="indent">chosen.node</td>
<td>Function or Boolean</td>
<td>undefined</td>
<td>
When true, selecting or hovering on a node will change its characteristics according the default.
When false, no change to the node will occur when the node is chosen.
<p>
If a function is supplied, it is called when the node is chosen.
<pre class="code">
function(values, id, selected, hovering) {
values.<i>property</i> = <i>chosenValue</i>;
}</pre>
</p>
<p>
Any of the incoming arguments may be used to determine characteristic changes.
If a property is not specifically assigned by the supplied function, it will be left unchanged.
A specific function may be assigned to each particular node in its options, or to all in the network's <code>nodes</code> options.
</p>
<p>
The properties define the characteristics that can be changed as follows:
</p>
<table>
<tr><th>Property</th><th>Node Reference</th></tr>
<tr><td>color</td><td>see color.background</td></tr>
<tr><td>borderWidth</td><td>see borderWidth</td></tr>
<tr><td>borderColor</td><td>see color.border</td></tr>
<tr><td>size</td><td>see size</td></tr>
<tr><td>borderDashes</td><td>see shapeProperties.borderDashes</td></tr>
<tr><td>borderRadius</td><td>see shapeProperties.borderRadius</td></tr>
<tr><td>shadow</td><td>see shadow.enabled</td></tr>
<tr><td>shadowColor</td><td>see shadow.color</td></tr>
<tr><td>shadowSize</td><td>see shadow.size</td></tr>
<tr><td>shadowX</td><td>see shadow.x</td></tr>
<tr><td>shadowY</td><td>see shadow.y</td></tr>
</table>
<br/>
</td>
</tr>
<tr parent="chosen" class="hidden">
<td class="indent">chosen.label</td>
<td>Function or Boolean</td>
<td>undefined</td>
<td>
When true, selecting or hovering on a node will change its label's characteristics according the default.
When false, no change to the node's label will occur when the node is chosen.
<p>
If a function is supplied, it is called when the node is chosen.
<pre class="code">
function(values, id, selected, hovering) {
values.<i>property</i> = <i>chosenValue</i>;
}</pre>
</p>
<p>
Any of the incoming arguments may be used to determine characteristic changes.
If a property is not specifically assigned by the supplied function, it will be left unchanged.
A specific function may be assigned to each particular node in its options, or to all in the network's <code>nodes</code> options.
</p>
<p>
The properties define the characteristics that can be changed as follows:
</p>
<table>
<tr><th>Property</th><th>Node Reference</th></tr>
<tr><td>color</td><td>see font.color</td></tr>
<tr><td>size</td><td>see font.size</td></tr>
<tr><td>face</td><td>see font.face</td></tr>
<tr><td>mod</td><td>font modifier ('bold', 'italic', etc.)</td></tr>
<tr><td>vadjust</td><td>see font.vadjust</td></tr>
<tr><td>strokeWidth</td><td>see font.strokeWidth</td></tr>
<tr><td>strokeColor</td><td>see font.strokeColor</td></tr>
</table>
<br/>
</td>
</tr>
<tr class='toggle collapsible' onclick="toggleTable('optionTable','color', this);">
<td><span parent="color" class="right-caret"></span> color</td>
<td>Object or String</td>

+ 466
- 0
examples/network/other/chosen.html View File

@ -0,0 +1,466 @@
<!doctype html>
<html>
<head>
<title>Network | Chosen Elements</title>
<script type="text/javascript" src="../../../dist/vis.js"></script>
<link href="../../../dist/vis-network.min.css" rel="stylesheet" type="text/css" />
<style type="text/css">
#mynetwork {
width: 900px;
height: 600px;
border: 1px solid lightgray;
}
code {
font-size: 14px;
background: #dddddd;
}
p {
max-width: 600px;
}
.indented {
margin-left: 30px;
}
.sep {
height: 1px;
width: 35%;
margin-left: 40px;
background-color: #dddddd;
}
</style>
<script src="../../googleAnalytics.js"></script>
</head>
<body>
<p>When a node or edge is selected or hovered its visible characteristics can be changed.</p>
<div id="mynetwork"></div>
<p>In this network, an element (node, edge or label) will change a characteristic when hovered, and it will be locked in when selected.
This is managed by setting up a 'chosen' function that will be called when the element containing the function is chosen.
These functions may be set on nodes, edges and labels, at the individual or group level.</p>
<p>All states (unselected, hover-over-unselected, selected, and hover-over selected) may be handled as needed by the application using vis, as the select and hover states are passed to the chosen function when called.
Additionally, the id of the element is passed to allow context-specific characteristic adjustment on select or hover as needed.</p>
<p><i>It should be noted that the characteristics which might affect the position of elements have been left out on purpose.
While it might be interesting to make them changeable, this is problematic on hovering.
Consider that the user hovers over an object.
If it changed characteristics that moved it outside of the hover-distance, it would then no longer be hovering.
So it would be moved back to its original prosition, within the hover-distance and then again be hovering over the object.
This hysteresis loop is kept from occurring by leaving out the characteristics that could cause it.
Some seemingly innocuous changes (such as resizing a node's label on hover that would in turn cause the node to resize and move out of hover-distance) may still cause hysteresis, but with care they should be avoidable.</i></p>
<script type="text/javascript">
var changeChosenLabelColor =
function(ctx, values, id) {
values.color = "#ff0000";
}
var changeChosenLabelSize =
function(ctx, values, id) {
values.size += 1;
}
var changeChosenLabelFace =
function(ctx, values, id) {
values.face = "serif";
}
var changeChosenLabelMod =
function(ctx, values, id) {
values.mod = "bold italic";
}
var changeChosenLabelStrokeWidth =
function(ctx, values, id) {
values.strokeWidth = 5;
}
var changeChosenLabelStrokeColor =
function(ctx, values, id) {
values.strokeColor = "#00ff00";
}
var changeChosenNodeColor =
function(values, id, selected, hovering) {
values.color = "#ffdd88";
}
var changeChosenNodeBorderWidth =
function(values, id, selected, hovering) {
values.borderWidth = 3;
}
var changeChosenNodeBorderColor =
function(values, id, selected, hovering) {
values.borderColor = "#ff0000";
}
var changeChosenNodeSize =
function(values, id, selected, hovering) {
values.size = 30;
}
var changeChosenNodeBorderDashes =
function(values, id, selected, hovering) {
values.borderDashes = [ 10, 10 ];
}
var changeChosenNodeBorderRadius =
function(values, id, selected, hovering) {
values.borderRadius = 15;
}
var changeChosenNodeShadow =
function(values, id, selected, hovering) {
values.shadow = true;
}
var changeChosenNodeShadowColor =
function(values, id, selected, hovering) {
values.shadowColor = "#ff0000";
}
var changeChosenNodeShadowSize =
function(values, id, selected, hovering) {
values.shadowSize = 30;
}
var changeChosenNodeShadowX =
function(values, id, selected, hovering) {
values.shadowX = -5;
}
var changeChosenNodeShadowY =
function(values, id, selected, hovering) {
values.shadowY = -5;
}
var changeChosenEdgeToArrow =
function(values, id, selected, hovering) {
values.toArrow = true;
}
var changeChosenEdgeToArrowScale =
function(values, id, selected, hovering) {
values.toArrowScale = 2;
}
var changeChosenEdgeToArrowType =
function(values, id, selected, hovering) {
values.toArrowType = "circle";
}
var changeChosenEdgeMiddleArrow =
function(values, id, selected, hovering) {
values.middleArrow = true;
}
var changeChosenEdgeMiddleArrowScale =
function(values, id, selected, hovering) {
values.middleArrowScale = 2;
}
var changeChosenEdgeMiddleArrowType =
function(values, id, selected, hovering) {
values.middleArrowType = "circle";
}
var changeChosenEdgeFromArrow =
function(values, id, selected, hovering) {
values.fromArrow = true;
}
var changeChosenEdgeFromArrowScale =
function(values, id, selected, hovering) {
values.fromArrowScale = 2;
}
var changeChosenEdgeFromArrowType =
function(values, id, selected, hovering) {
values.fromArrowType = "circle";
}
var changeChosenEdgeArrowStrikethrough =
function(values, id, selected, hovering) {
values.arrowStrikethrough = false;
}
var changeChosenEdgeColor =
function(values, id, selected, hovering) {
values.color = "#00ff00";
}
var changeChosenEdgeInheritsColor =
function(values, id, selected, hovering) {
values.inheritsColor = "both";
}
var changeChosenEdgeOpacity =
function(values, id, selected, hovering) {
values.opacity = 0.25;
}
var changeChosenEdgeHidden =
function(values, id, selected, hovering) {
values.hidden = true;
}
var changeChosenEdgeShadow =
function(values, id, selected, hovering) {
values.shadow = true;
}
var changeChosenEdgeShadowColor =
function(values, id, selected, hovering) {
values.shadowColor = "#00ffff";
}
var changeChosenEdgeShadowSize =
function(values, id, selected, hovering) {
values.shadowSize = 20;
}
var changeChosenEdgeShadowX =
function(values, id, selected, hovering) {
values.shadowX = -5;
}
var changeChosenEdgeShadowY =
function(values, id, selected, hovering) {
values.shadowY = -5;
}
var changeChosenEdgeWidth =
function(values, id, selected, hovering) {
values.width = 5;
}
var changeChosenEdgeDashes =
function(values, id, selected, hovering) {
values.dashes = [10, 10];
}
var nodes = [
{ id: 1000, label: "label does not change",
x: -400, y: -300,
chosen: { label: false, node: false } },
{ id: 1010, label: "label default settings",
x: -400, y: -225,
chosen: { label: true, node: false } },
{ id: 1020, label: "label changes color",
x: -400, y: -150,
chosen: { label: changeChosenLabelColor, node: false } },
{ id: 1030, label: "label changes size",
x: -400, y: -75,
chosen: { label: changeChosenLabelSize, node: false } },
{ id: 1040, label: "label changes face",
x: -400, y: 0,
chosen: { label: changeChosenLabelFace, node: false } },
{ id: 1050, label: "label changes modifier",
x: -400, y: 75,
chosen: { label: changeChosenLabelMod, node: false } },
{ id: 1060, label: "label changes stokeWidth",
x: -400, y: 150,
chosen: { label: changeChosenLabelStrokeWidth, node: false } },
{ id: 1070, label: "label changes stokeColor",
x: -400, y: 225, font: { strokeWidth: 2 },
chosen: { label: changeChosenLabelStrokeColor, node: false } },
{ id: 2000, label: "node does not change",
x: 0, y: -300,
chosen: { label: false, node: false } },
{ id: 2010, label: "node default settings",
x: 0, y: -225,
chosen: { label: false, node: true } },
{ id: 2020, label: "node changes color",
x: 0, y: -150,
chosen: { label: false, node: changeChosenNodeColor } },
{ id: 2030, label: "node changes borderWidth",
x: 0, y: -75,
chosen: { label: false, node: changeChosenNodeBorderWidth } },
{ id: 2040, label: "node changes borderColor",
x: 0, y: 0,
chosen: { label: false, node: changeChosenNodeBorderColor } },
{ id: 2050, label: "shaped nodes change size",
x: 0, y: 70, shape: 'star',
chosen: { label: false, node: changeChosenNodeSize } },
{ id: 2051, x: -60, y: 70, shape: 'dot',
chosen: { label: false, node: changeChosenNodeSize } },
{ id: 2052, x: -120, y: 70, shape: 'diamond',
chosen: { label: false, node: changeChosenNodeSize } },
{ id: 2053, x: 60, y: 70, shape: 'square',
chosen: { label: false, node: changeChosenNodeSize } },
{ id: 2054, x: 120, y: 70, shape: 'triangle',
chosen: { label: false, node: changeChosenNodeSize } },
{ id: 2055, x: 165, y: 70, shape: 'triangleDown',
chosen: { label: false, node: changeChosenNodeSize } },
{ id: 2060, label: "node changes borderDashes",
x: 0, y: 150,
chosen: { label: false, node: changeChosenNodeBorderDashes } },
{ id: 2070, label: "node changes borderRadius",
x: 0, y: 225,
chosen: { label: false, node: changeChosenNodeBorderRadius } },
{ id: 2080, label: "node changes shadow",
x: 0, y: 300,
chosen: { label: false, node: changeChosenNodeShadow } },
{ id: 2090, label: "node changes shadowColor",
x: 0, y: 375, shadow: true,
chosen: { label: false, node: changeChosenNodeShadowColor } },
{ id: 2100, label: "node changes shadowSize",
x: 0, y: 450, shadow: true,
chosen: { label: false, node: changeChosenNodeShadowSize } },
{ id: 2110, label: "node changes shadowX",
x: 0, y: 525, shadow: true,
chosen: { label: false, node: changeChosenNodeShadowX } },
{ id: 2120, label: "node changes shadowY",
x: 0, y: 600, shadow: true,
chosen: { label: false, node: changeChosenNodeShadowY } },
{ id: 3000, x: 275, y: -310, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3001, x: 525, y: -210, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3010, x: 275, y: -235, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3011, x: 525, y: -135, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3020, x: 275, y: -160, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3021, x: 525, y: -60, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3030, x: 275, y: -85, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3031, x: 525, y: 15, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3040, x: 275, y: -10, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3041, x: 525, y: 90, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3050, x: 275, y: 65, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3051, x: 525, y: 165, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3060, x: 275, y: 140, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3061, x: 525, y: 240, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3070, x: 275, y: 215, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3071, x: 525, y: 315, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3080, x: 275, y: 290, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0},
{ id: 3081, x: 525, y: 390, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3090, x: 275, y: 365, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3091, x: 525, y: 465, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3100, x: 275, y: 440, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3101, x: 525, y: 540, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3110, x: 275, y: 515, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3111, x: 525, y: 615, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3120, x: 575, y: -310, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3121, x: 825, y: -210, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3130, x: 575, y: -235, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3131, x: 825, y: -135, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3140, x: 575, y: -160, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3141, x: 825, y: -60, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3150, x: 575, y: -85, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3151, x: 825, y: 15, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3160, x: 575, y: -10, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3161, x: 825, y: 90, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3170, x: 575, y: 65, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3171, x: 825, y: 165, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3180, x: 575, y: 140, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3181, x: 825, y: 240, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3190, x: 575, y: 215, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3191, x: 825, y: 315, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3200, x: 575, y: 290, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3201, x: 825, y: 390, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3210, x: 575, y: 365, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3211, x: 825, y: 465, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
{ id: 3220, x: 575, y: 440, chosen: false, shape: "dot", size: 10, color: "#dd6644", borderWidth: 0 },
{ id: 3221, x: 825, y: 540, chosen: false, shape: "dot", size: 10, color: "#6699dd", borderWidth: 0 },
];
var edges = [
{ id: 4000, from: 3000, to: 3001, label: "edge does not change",
chosen: false },
{ id: 4010, from: 3010, to: 3011, label: "edge has default settings",
chosen: { label: false, edge: true } },
{ id: 4020, from: 3020, to: 3021, label: "edge changes toArrow",
chosen: { label: false, edge: changeChosenEdgeToArrow } },
{ id: 4030, from: 3030, to: 3031, label: "edge changes toArrowScale",
arrows: { to: true },
chosen: { label: false, edge: changeChosenEdgeToArrowScale } },
{ id: 4040, from: 3040, to: 3041, label: "edge changes toArrowType",
arrows: { to: true },
chosen: { label: false, edge: changeChosenEdgeToArrowType } },
{ id: 4050, from: 3050, to: 3051, label: "edge changes middleArrow",
chosen: { label: false, edge: changeChosenEdgeMiddleArrow } },
{ id: 4060, from: 3060, to: 3061, label: "edge changes middleArrowScale",
arrows: { middle: true },
chosen: { label: false, edge: changeChosenEdgeMiddleArrowScale } },
{ id: 4070, from: 3070, to: 3071, label: "edge changes middleArrowType",
arrows: { middle: true },
chosen: { label: false, edge: changeChosenEdgeMiddleArrowType } },
{ id: 4080, from: 3080, to: 3081, label: "edge changes fromArrow",
chosen: { label: false, edge: changeChosenEdgeFromArrow } },
{ id: 4090, from: 3090, to: 3091, label: "edge changes fromArrowScale",
arrows: { from: true },
chosen: { label: false, edge: changeChosenEdgeFromArrowScale } },
{ id: 4100, from: 3100, to: 3101, label: "edge changes fromArrowType",
arrows: { from: true },
chosen: { label: false, edge: changeChosenEdgeFromArrowType } },
{ id: 4110, from: 3110, to: 3111, label: "edge changes arrowStrikethrough",
arrows: { to: true, from: true }, width: 7,
chosen: { label: false, edge: changeChosenEdgeArrowStrikethrough } },
{ id: 4120, from: 3120, to: 3121, label: "edge changes color",
chosen: { label: false, edge: changeChosenEdgeColor } },
{ id: 4130, from: 3130, to: 3131, label: "edge inherits color",
chosen: { label: false, edge: changeChosenEdgeInheritsColor } },
{ id: 4140, from: 3140, to: 3141, label: "edge changes opacity",
chosen: { label: false, edge: changeChosenEdgeOpacity } },
{ id: 4150, from: 3150, to: 3151, label: "edge changes hidden",
chosen: { label: false, edge: changeChosenEdgeHidden } },
{ id: 4160, from: 3160, to: 3161, label: "edge changes shadow",
width: 7,
chosen: { label: false, edge: changeChosenEdgeShadow } },
{ id: 4170, from: 3170, to: 3171, label: "edge changes shadowColor",
shadow: true, width: 7,
chosen: { label: false, edge: changeChosenEdgeShadowColor } },
{ id: 4180, from: 3180, to: 3181, label: "edge changes shadowSize",
shadow: true, width: 7,
chosen: { label: false, edge: changeChosenEdgeShadowSize } },
{ id: 4190, from: 3190, to: 3191, label: "edge changes shadowX",
shadow: true, width: 7,
chosen: { label: false, edge: changeChosenEdgeShadowX } },
{ id: 4200, from: 3200, to: 3201, label: "edge changes shadowY",
shadow: true, width: 7,
chosen: { label: false, edge: changeChosenEdgeShadowY } },
{ id: 4210, from: 3210, to: 3211, label: "edge changes width",
chosen: { label: false, edge: changeChosenEdgeWidth } },
{ id: 4220, from: 3220, to: 3221, label: "edge changes dashes",
chosen: { label: false, edge: changeChosenEdgeDashes } },
];
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var options = {
edges: {
font: {
size: 16
},
selfReferenceSize: 30
},
nodes: {
shape: 'box',
widthConstraint: 250,
color: "#cccccc",
margin: 10,
font: {
size: 16
}
},
physics: {
enabled: false
},
interaction: {
hover: true
}
};
var network = new vis.Network(container, data, options);
</script>
</body>
</html>

+ 4
- 6
lib/network/modules/CanvasRenderer.js View File

@ -32,11 +32,9 @@ class CanvasRenderer {
}
bindEventListeners() {
this.body.emitter.on("dragStart", () => {
this.dragging = true;
});
this.body.emitter.on("dragEnd", () => this.dragging = false);
this.body.emitter.on("_resizeNodes", () => this._resizeNodes());
this.body.emitter.on("dragStart", () => { this.dragging = true; });
this.body.emitter.on("dragEnd", () => { this.dragging = false; });
this.body.emitter.on("_resizeNodes", () => { this._resizeNodes(); });
this.body.emitter.on("_redraw", () => {
if (this.renderingActive === false) {
this._redraw();
@ -327,4 +325,4 @@ class CanvasRenderer {
}
export default CanvasRenderer;
export default CanvasRenderer;

+ 0
- 13
lib/network/modules/EdgesHandler.js View File

@ -151,7 +151,6 @@ class EdgesHandler {
// this is called when options of EXISTING nodes or edges have changed.
this.body.emitter.on("_dataUpdated", () => {
this.reconnectEdges();
this.markAllEdgesAsDirty();
});
// refresh the edges. Used when reverting from hierarchical layout
@ -177,11 +176,6 @@ class EdgesHandler {
// use the parser from the Edge class to fill in all shorthand notations
Edge.parseOptions(this.options, options);
// handle multiple input cases for color
if (options.color !== undefined) {
this.markAllEdgesAsDirty();
}
// update smooth settings in all edges
let dataChanged = false;
if (options.smooth !== undefined) {
@ -361,13 +355,6 @@ class EdgesHandler {
return new Edge(properties, this.body, this.options, this.defaultOptions, this.edgeOptions)
}
markAllEdgesAsDirty() {
for (var edgeId in this.body.edges) {
this.body.edges[edgeId].edgeType.colorDirty = true;
}
}
/**
* Reconnect all edges
* @private

+ 166
- 59
lib/network/modules/components/Edge.js View File

@ -39,7 +39,6 @@ class Edge {
this.selected = false;
this.hover = false;
this.labelDirty = true;
this.colorDirty = true;
this.baseWidth = this.options.width;
this.baseFontSize = this.options.font.size;
@ -65,16 +64,26 @@ class Edge {
if (!options) {
return;
}
this.colorDirty = true;
Edge.parseOptions(this.options, options, true, this.globalOptions);
if (options.id !== undefined) {this.id = options.id;}
if (options.from !== undefined) {this.fromId = options.from;}
if (options.to !== undefined) {this.toId = options.to;}
if (options.title !== undefined) {this.title = options.title;}
if (options.value !== undefined) {options.value = parseFloat(options.value);}
if (options.id !== undefined) {
this.id = options.id;
}
if (options.from !== undefined) {
this.fromId = options.from;
}
if (options.to !== undefined) {
this.toId = options.to;
}
if (options.title !== undefined) {
this.title = options.title;
}
if (options.value !== undefined) {
options.value = parseFloat(options.value);
}
this.choosify(options);
// update label Module
this.updateLabelModule(options);
@ -197,6 +206,94 @@ class Edge {
}
}
choosify(options) {
this.chooser = true;
let pile = [options, this.options, this.defaultOptions];
let chosen = util.topMost(pile, 'chosen');
if (typeof chosen === 'boolean') {
this.chooser = chosen;
} else if (typeof chosen === 'object') {
let chosenEdge = util.topMost(pile, ['chosen', 'edge']);
if ((typeof chosenEdge === 'boolean') || (typeof chosenEdge === 'function')) {
this.chooser = chosenEdge;
}
}
}
getFormattingValues() {
let toArrow = (this.options.arrows.to === true) || (this.options.arrows.to.enabled === true)
let fromArrow = (this.options.arrows.from === true) || (this.options.arrows.from.enabled === true)
let middleArrow = (this.options.arrows.middle === true) || (this.options.arrows.middle.enabled === true)
let inheritsColor = this.options.color.inherit;
let values = {
toArrow: toArrow,
toArrowScale: this.options.arrows.to.scaleFactor,
toArrowType: this.options.arrows.to.type,
middleArrow: middleArrow,
middleArrowScale: this.options.arrows.middle.scaleFactor,
middleArrowType: this.options.arrows.middle.type,
fromArrow: fromArrow,
fromArrowScale: this.options.arrows.from.scaleFactor,
fromArrowType: this.options.arrows.from.type,
arrowStrikethrough: this.options.arrowStrikethrough,
color: (inheritsColor? undefined : this.options.color.color),
inheritsColor: inheritsColor,
opacity: this.options.color.opacity,
hidden: this.options.hidden,
length: this.options.length,
shadow: this.options.shadow.enabled,
shadowColor: this.options.shadow.color,
shadowSize: this.options.shadow.size,
shadowX: this.options.shadow.x,
shadowY: this.options.shadow.y,
dashes: this.options.dashes,
width: this.options.width
};
if (this.selected || this.hover) {
if (this.chooser === true) {
if (this.selected) {
let selectedWidth = this.options.selectionWidth;
if (typeof selectedWidth === 'function') {
values.width = selectedWidth(values.width);
} else if (typeof selectedWidth === 'number') {
values.width += selectedWidth;
}
values.width = Math.max(values.width, 0.3 / this.body.view.scale);
values.color = this.options.color.highlight;
values.shadow = this.options.shadow.enabled;
} else if (this.hover) {
let hoverWidth = this.options.hoverWidth;
if (typeof hoverWidth === 'function') {
values.width = hoverWidth(values.width);
} else if (typeof hoverWidth === 'number') {
values.width += hoverWidth;
}
values.width = Math.max(values.width, 0.3 / this.body.view.scale);
values.color = this.options.color.hover;
values.shadow = this.options.shadow.enabled;
}
} else if (typeof this.chooser === 'function') {
this.chooser(values, this.options.id, this.selected, this.hover);
if (values.color !== undefined) {
values.inheritsColor = false;
}
if (values.shadow === false) {
if ((values.shadowColor !== this.options.shadow.color) ||
(values.shadowSize !== this.options.shadow.size) ||
(values.shadowX !== this.options.shadow.x) ||
(values.shadowY !== this.options.shadow.y)) {
values.shadow = true;
}
}
}
} else {
values.shadow = this.options.shadow.enabled;
values.width = Math.max(values.width, 0.3 / this.body.view.scale);
}
return values;
}
/**
* update the options in the label module
@ -207,6 +304,7 @@ class Edge {
this.baseFontSize = this.labelModule.baseSize;
}
this.labelModule.constrain(this.edgeOptions, options, this.defaultOptions);
this.labelModule.choosify(this.edgeOptions, options, this.defaultOptions);
}
/**
@ -214,46 +312,47 @@ class Edge {
* @returns {boolean}
*/
updateEdgeType() {
let smooth = this.options.smooth;
let dataChanged = false;
let changeInType = true;
let smooth = this.options.smooth;
if (this.edgeType !== undefined) {
if (this.edgeType instanceof BezierEdgeDynamic && smooth.enabled === true && smooth.type === 'dynamic') {changeInType = false;}
if (this.edgeType instanceof CubicBezierEdge && smooth.enabled === true && smooth.type === 'cubicBezier') {changeInType = false;}
if (this.edgeType instanceof BezierEdgeStatic && smooth.enabled === true && smooth.type !== 'dynamic' && smooth.type !== 'cubicBezier') {changeInType = false;}
if (this.edgeType instanceof StraightEdge && smooth.enabled === false) {changeInType = false;}
if ((((this.edgeType instanceof BezierEdgeDynamic) &&
(smooth.enabled === true) &&
(smooth.type === 'dynamic'))) ||
(((this.edgeType instanceof CubicBezierEdge) &&
(smooth.enabled === true) &&
(smooth.type === 'cubicBezier'))) ||
(((this.edgeType instanceof BezierEdgeStatic) &&
(smooth.enabled === true) &&
(smooth.type !== 'dynamic') &&
(smooth.type !== 'cubicBezier'))) ||
(((this.edgeType instanceof StraightEdge) &&
(smooth.type.enabled === false)))) {
changeInType = false;
}
if (changeInType === true) {
dataChanged = this.cleanup();
}
}
if (changeInType === true) {
if (this.options.smooth.enabled === true) {
if (this.options.smooth.type === 'dynamic') {
if (smooth.enabled === true) {
if (smooth.type === 'dynamic') {
dataChanged = true;
this.edgeType = new BezierEdgeDynamic(this.options, this.body, this.labelModule);
}
else if (this.options.smooth.type === 'cubicBezier') {
} else if (smooth.type === 'cubicBezier') {
this.edgeType = new CubicBezierEdge(this.options, this.body, this.labelModule);
}
else {
} else {
this.edgeType = new BezierEdgeStatic(this.options, this.body, this.labelModule);
}
}
else {
} else {
this.edgeType = new StraightEdge(this.options, this.body, this.labelModule);
}
}
else {
// if nothing changes, we just set the options.
} else { // if nothing changes, we just set the options.
this.edgeType.setOptions(this.options);
}
return dataChanged;
}
/**
* Connect an edge to its nodes
*/
@ -353,21 +452,18 @@ class Edge {
this.updateLabelModule();
}
_setInteractionWidths() {
if (typeof this.options.hoverWidth === 'function') {
this.edgeType.hoverWidth = this.options.hoverWidth(this.options.width);
}
else {
this.edgeType.hoverWidth = this.options.hoverWidth + this.options.width;
}
if (typeof this.options.selectionWidth === 'function') {
this.edgeType.selectionWidth = this.options.selectionWidth(this.options.width);
}
else {
this.edgeType.selectionWidth = this.options.selectionWidth + this.options.width;
}
}
_setInteractionWidths() {
if (typeof this.options.hoverWidth === 'function') {
this.edgeType.hoverWidth = this.options.hoverWidth(this.options.width);
} else {
this.edgeType.hoverWidth = this.options.hoverWidth + this.options.width;
}
if (typeof this.options.selectionWidth === 'function') {
this.edgeType.selectionWidth = this.options.selectionWidth(this.options.width);
} else {
this.edgeType.selectionWidth = this.options.selectionWidth + this.options.width;
}
}
/**
@ -377,6 +473,11 @@ class Edge {
* @param {CanvasRenderingContext2D} ctx
*/
draw(ctx) {
let values = this.getFormattingValues();
if (values.hidden) {
return;
}
// get the via node from the edge type
let viaNode = this.edgeType.getViaNode();
let arrowData = {};
@ -386,33 +487,39 @@ class Edge {
this.edgeType.toPoint = this.edgeType.to;
// from and to arrows give a different end point for edges. we set them here
if (this.options.arrows.from.enabled === true) {
arrowData.from = this.edgeType.getArrowData(ctx,'from', viaNode, this.selected, this.hover);
if (this.options.arrowStrikethrough === false)
if (values.fromArrow) {
arrowData.from = this.edgeType.getArrowData(ctx, 'from', viaNode, this.selected, this.hover, values);
if (values.arrowStrikethrough === false)
this.edgeType.fromPoint = arrowData.from.core;
}
if (this.options.arrows.to.enabled === true) {
arrowData.to = this.edgeType.getArrowData(ctx,'to', viaNode, this.selected, this.hover);
if (this.options.arrowStrikethrough === false)
if (values.toArrow) {
arrowData.to = this.edgeType.getArrowData(ctx, 'to', viaNode, this.selected, this.hover, values);
if (values.arrowStrikethrough === false)
this.edgeType.toPoint = arrowData.to.core;
}
// the middle arrow depends on the line, which can depend on the to and from arrows so we do this one lastly.
if (this.options.arrows.middle.enabled === true) {
arrowData.middle = this.edgeType.getArrowData(ctx,'middle', viaNode, this.selected, this.hover);
if (values.middleArrow) {
arrowData.middle = this.edgeType.getArrowData(ctx,'middle', viaNode, this.selected, this.hover, values);
}
// draw everything
this.edgeType.drawLine(ctx, this.selected, this.hover, viaNode);
this.drawArrows(ctx, arrowData);
this.edgeType.drawLine(ctx, values, this.selected, this.hover, viaNode);
this.drawArrows(ctx, arrowData, values);
this.drawLabel (ctx, viaNode);
}
drawArrows(ctx, arrowData) {
if (this.options.arrows.from.enabled === true) {this.edgeType.drawArrowHead(ctx, this.selected, this.hover, arrowData.from);}
if (this.options.arrows.middle.enabled === true) {this.edgeType.drawArrowHead(ctx, this.selected, this.hover, arrowData.middle);}
if (this.options.arrows.to.enabled === true) {this.edgeType.drawArrowHead(ctx, this.selected, this.hover, arrowData.to);}
drawArrows(ctx, arrowData, values) {
if (values.fromArrow) {
this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.from);
}
if (values.middleArrow) {
this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.middle);
}
if (values.toArrow) {
this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.to);
}
}
@ -429,13 +536,13 @@ class Edge {
// if the label has to be rotated:
if (this.options.font.align !== "horizontal") {
this.labelModule.calculateLabelSize(ctx,selected,point.x,point.y);
this.labelModule.calculateLabelSize(ctx, selected, this.hover, point.x, point.y);
ctx.translate(point.x, this.labelModule.size.yLine);
this._rotateForLabelAlignment(ctx);
}
// draw the label
this.labelModule.draw(ctx, point.x, point.y, selected);
this.labelModule.draw(ctx, point.x, point.y, selected, this.hover);
ctx.restore();
}
else {
@ -452,7 +559,7 @@ class Edge {
y = node1.y - node1.shape.height * 0.5;
}
point = this._pointOnCircle(x, y, radius, 0.125);
this.labelModule.draw(ctx, point.x, point.y, selected);
this.labelModule.draw(ctx, point.x, point.y, selected, this.hover);
}
}
}

+ 67
- 2
lib/network/modules/components/Node.js View File

@ -139,6 +139,8 @@ class Node {
// this transforms all shorthands into fully defined options
Node.parseOptions(this.options, options, true, this.globalOptions);
this.choosify(options);
// load the images
if (this.options.image !== undefined) {
if (this.imagelist) {
@ -219,6 +221,66 @@ class Node {
}
}
choosify(options) {
this.chooser = true;
let pile = [options, this.options, this.defaultOptions];
let chosen = util.topMost(pile, 'chosen');
if (typeof chosen === 'boolean') {
this.chooser = chosen;
} else if (typeof chosen === 'object') {
let chosenNode = util.topMost(pile, ['chosen', 'node']);
if ((typeof chosenNode === 'boolean') || (typeof chosenNode === 'function')) {
this.chooser = chosenNode;
}
}
}
getFormattingValues() {
let values = {
color: this.options.color.background,
borderWidth: this.options.borderWidth,
borderColor: this.options.color.border,
size: this.options.size,
borderDashes: this.options.shapeProperties.borderDashes,
borderRadius: this.options.shapeProperties.borderRadius,
shadow: this.options.shadow.enabled,
shadowColor: this.options.shadow.color,
shadowSize: this.options.shadow.size,
shadowX: this.options.shadow.x,
shadowY: this.options.shadow.y
};
if (this.selected || this.hover) {
if (this.chooser === true) {
if (this.selected) {
values.borderWidth *= 2;
values.color = this.options.color.highlight.background;
values.borderColor = this.options.color.highlight.border;
values.shadow = this.options.shadow.enabled;
} else if (this.hover) {
values.color = this.options.color.hover.background;
values.borderColor = this.options.color.hover.border;
values.shadow = this.options.shadow.enabled;
}
} else if (typeof this.chooser === 'function') {
this.chooser(values, this.options.id, this.selected, this.hover);
if (values.shadow === false) {
if ((values.shadowColor !== this.options.shadow.color) ||
(values.shadowSize !== this.options.shadow.size) ||
(values.shadowX !== this.options.shadow.x) ||
(values.shadowY !== this.options.shadow.y)) {
values.shadow = true;
}
}
}
} else {
values.shadow = this.options.shadow.enabled;
}
return values;
}
updateLabelModule(options) {
if (this.options.label === undefined || this.options.label === null) {
this.options.label = '';
@ -228,6 +290,7 @@ class Node {
this.baseFontSize = this.labelModule.baseSize;
}
this.labelModule.constrain(this.nodeOptions, options, this.defaultOptions);
this.labelModule.choosify(this.nodeOptions, options, this.defaultOptions);
}
updateShape(currentShape) {
@ -396,7 +459,8 @@ class Node {
* @param {CanvasRenderingContext2D} ctx
*/
draw(ctx) {
this.shape.draw(ctx, this.x, this.y, this.selected, this.hover);
let values = this.getFormattingValues();
this.shape.draw(ctx, this.x, this.y, this.selected, this.hover, values);
}
@ -413,7 +477,8 @@ class Node {
* @param {CanvasRenderingContext2D} ctx
*/
resize(ctx) {
this.shape.resize(ctx, this.selected);
let values = this.getFormattingValues();
this.shape.resize(ctx, this.selected, this.hover, values);
}

+ 3
- 3
lib/network/modules/components/edges/BezierEdgeDynamic.js View File

@ -102,7 +102,7 @@ class BezierEdgeDynamic extends BezierEdgeBase {
* @param {CanvasRenderingContext2D} ctx
* @private
*/
_line(ctx, viaNode) {
_line(ctx, values, viaNode) {
// draw a straight line
ctx.beginPath();
ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
@ -114,9 +114,9 @@ class BezierEdgeDynamic extends BezierEdgeBase {
ctx.quadraticCurveTo(viaNode.x, viaNode.y, this.toPoint.x, this.toPoint.y);
}
// draw shadow if enabled
this.enableShadow(ctx);
this.enableShadow(ctx, values);
ctx.stroke();
this.disableShadow(ctx);
this.disableShadow(ctx, values);
}
getViaNode() {

+ 3
- 3
lib/network/modules/components/edges/BezierEdgeStatic.js View File

@ -10,7 +10,7 @@ class BezierEdgeStatic extends BezierEdgeBase {
* @param {CanvasRenderingContext2D} ctx
* @private
*/
_line(ctx, viaNode) {
_line(ctx, values, viaNode) {
// draw a straight line
ctx.beginPath();
ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
@ -23,9 +23,9 @@ class BezierEdgeStatic extends BezierEdgeBase {
ctx.quadraticCurveTo(viaNode.x, viaNode.y, this.toPoint.x, this.toPoint.y);
}
// draw shadow if enabled
this.enableShadow(ctx);
this.enableShadow(ctx, values);
ctx.stroke();
this.disableShadow(ctx);
this.disableShadow(ctx, values);
}
getViaNode() {

+ 3
- 3
lib/network/modules/components/edges/CubicBezierEdge.js View File

@ -10,7 +10,7 @@ class CubicBezierEdge extends CubicBezierEdgeBase {
* @param {CanvasRenderingContext2D} ctx
* @private
*/
_line(ctx, viaNodes) {
_line(ctx, values, viaNodes) {
// get the coordinates of the support points.
let via1 = viaNodes[0];
let via2 = viaNodes[1];
@ -27,9 +27,9 @@ class CubicBezierEdge extends CubicBezierEdgeBase {
ctx.bezierCurveTo(via1.x, via1.y, via2.x, via2.y, this.toPoint.x, this.toPoint.y);
}
// draw shadow if enabled
this.enableShadow(ctx);
this.enableShadow(ctx, values);
ctx.stroke();
this.disableShadow(ctx);
this.disableShadow(ctx, values);
}
_getViaCoordinates() {

+ 3
- 3
lib/network/modules/components/edges/StraightEdge.js View File

@ -10,15 +10,15 @@ class StraightEdge extends EdgeBase {
* @param {CanvasRenderingContext2D} ctx
* @private
*/
_line(ctx) {
_line(ctx, values) {
// draw a straight line
ctx.beginPath();
ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
ctx.lineTo(this.toPoint.x, this.toPoint.y);
// draw shadow if enabled
this.enableShadow(ctx);
this.enableShadow(ctx, values);
ctx.stroke();
this.disableShadow(ctx);
this.disableShadow(ctx, values);
}
getViaNode() {

+ 74
- 101
lib/network/modules/components/edges/util/EdgeBase.js View File

@ -18,7 +18,10 @@ class EdgeBase {
this.from = this.body.nodes[this.options.from];
this.to = this.body.nodes[this.options.to];
}
cleanup() {return false}
cleanup() {
return false;
}
setOptions(options) {
this.options = options;
@ -34,36 +37,36 @@ class EdgeBase {
* @param {CanvasRenderingContext2D} ctx
* @private
*/
drawLine(ctx, selected, hover, viaNode) {
drawLine(ctx, values, selected, hover, viaNode) {
// set style
ctx.strokeStyle = this.getColor(ctx, selected, hover);
ctx.lineWidth = this.getLineWidth(selected, hover);
ctx.strokeStyle = this.getColor(ctx, values, selected, hover);
ctx.lineWidth = values.width;
if (this.options.dashes !== false) {
this._drawDashedLine(ctx, viaNode);
if (values.dashes !== false) {
this._drawDashedLine(ctx, values, viaNode);
}
else {
this._drawLine(ctx, viaNode);
this._drawLine(ctx, values, viaNode);
}
}
_drawLine(ctx, viaNode, fromPoint, toPoint) {
_drawLine(ctx, values, viaNode, fromPoint, toPoint) {
if (this.from != this.to) {
// draw line
this._line(ctx, viaNode, fromPoint, toPoint);
this._line(ctx, values, viaNode, fromPoint, toPoint);
}
else {
let [x,y,radius] = this._getCircleData(ctx);
this._circle(ctx, x, y, radius);
let [x,y,radius] = this._getCircleData(ctx, values);
this._circle(ctx, values, x, y, radius);
}
}
_drawDashedLine(ctx, viaNode, fromPoint, toPoint) {
_drawDashedLine(ctx, values, viaNode, fromPoint, toPoint) {
ctx.lineCap = 'round';
let pattern = [5,5];
if (Array.isArray(this.options.dashes) === true) {
pattern = this.options.dashes;
if (Array.isArray(values.dashes) === true) {
pattern = values.dashes;
}
// only firefox and chrome support this method, else we use the legacy one.
@ -77,11 +80,11 @@ class EdgeBase {
// draw the line
if (this.from != this.to) {
// draw line
this._line(ctx, viaNode);
this._line(ctx, values, viaNode);
}
else {
let [x,y,radius] = this._getCircleData(ctx);
this._circle(ctx, x, y, radius);
let [x,y,radius] = this._getCircleData(ctx, values);
this._circle(ctx, values, x, y, radius);
}
// restore the dash settings.
@ -95,16 +98,16 @@ class EdgeBase {
ctx.dashedLine(this.from.x, this.from.y, this.to.x, this.to.y, pattern);
}
else {
let [x,y,radius] = this._getCircleData(ctx);
this._circle(ctx, x, y, radius);
let [x,y,radius] = this._getCircleData(ctx, values);
this._circle(ctx, values, x, y, radius);
}
// draw shadow if enabled
this.enableShadow(ctx);
this.enableShadow(ctx, values);
ctx.stroke();
// disable shadows for other elements.
this.disableShadow(ctx);
this.disableShadow(ctx, values);
}
}
@ -252,24 +255,23 @@ class EdgeBase {
}
getColor(ctx, selected, hover) {
let colorOptions = this.options.color;
if (colorOptions.inherit !== false) {
getColor(ctx, values, selected, hover) {
if (values.inheritsColor !== false) {
// when this is a loop edge, just use the 'from' method
if (colorOptions.inherit === 'both' && this.from.id !== this.to.id) {
if ((values.inheritsColor === 'both') && (this.from.id !== this.to.id)) {
let grd = ctx.createLinearGradient(this.from.x, this.from.y, this.to.x, this.to.y);
let fromColor, toColor;
fromColor = this.from.options.color.highlight.border;
toColor = this.to.options.color.highlight.border;
if (this.from.selected === false && this.to.selected === false) {
fromColor = util.overrideOpacity(this.from.options.color.border, this.options.color.opacity);
toColor = util.overrideOpacity(this.to.options.color.border, this.options.color.opacity);
if ((this.from.selected === false) && (this.to.selected === false)) {
fromColor = util.overrideOpacity(this.from.options.color.border, values.opacity);
toColor = util.overrideOpacity(this.to.options.color.border, values.opacity);
}
else if (this.from.selected === true && this.to.selected === false) {
else if ((this.from.selected === true) && (this.to.selected === false)) {
toColor = this.to.options.color.border;
}
else if (this.from.selected === false && this.to.selected === true) {
else if ((this.from.selected === false) && (this.to.selected === true)) {
fromColor = this.from.options.color.border;
}
grd.addColorStop(0, fromColor);
@ -279,37 +281,13 @@ class EdgeBase {
return grd;
}
if (this.colorDirty === true) {
if (colorOptions.inherit === "to") {
this.color.highlight = this.to.options.color.highlight.border;
this.color.hover = this.to.options.color.hover.border;
this.color.color = util.overrideOpacity(this.to.options.color.border, colorOptions.opacity);
}
else { // (this.options.color.inherit.source === "from") {
this.color.highlight = this.from.options.color.highlight.border;
this.color.hover = this.from.options.color.hover.border;
this.color.color = util.overrideOpacity(this.from.options.color.border, colorOptions.opacity);
}
if (values.inheritsColor === "to") {
return util.overrideOpacity(this.to.options.color.border, values.opacity);
} else { // "from"
return util.overrideOpacity(this.from.options.color.border, values.opacity);
}
}
else if (this.colorDirty === true) {
this.color.highlight = colorOptions.highlight;
this.color.hover = colorOptions.hover;
this.color.color = util.overrideOpacity(colorOptions.color, colorOptions.opacity);
}
// if color inherit is on and gradients are used, the function has already returned by now.
this.colorDirty = false;
if (selected === true) {
return this.color.highlight;
}
else if (hover === true) {
return this.color.hover;
}
else {
return this.color.color;
} else {
return util.overrideOpacity(values.color, values.opacity);
}
}
@ -321,9 +299,9 @@ class EdgeBase {
* @param {Number} radius
* @private
*/
_circle(ctx, x, y, radius) {
_circle(ctx, values, x, y, radius) {
// draw shadow if enabled
this.enableShadow(ctx);
this.enableShadow(ctx, values);
// draw a circle
ctx.beginPath();
@ -331,7 +309,7 @@ class EdgeBase {
ctx.stroke();
// disable shadows for other elements.
this.disableShadow(ctx);
this.disableShadow(ctx, values);
}
@ -347,13 +325,13 @@ class EdgeBase {
* @param {number} y3
* @private
*/
getDistanceToEdge(x1, y1, x2, y2, x3, y3, via) { // x3,y3 is the point
getDistanceToEdge(x1, y1, x2, y2, x3, y3, via, values) { // x3,y3 is the point
let returnValue = 0;
if (this.from != this.to) {
returnValue = this._getDistanceToEdge(x1, y1, x2, y2, x3, y3, via)
}
else {
let [x,y,radius] = this._getCircleData();
let [x,y,radius] = this._getCircleData(undefined, values);
let dx = x - x3;
let dy = y - y3;
returnValue = Math.abs(Math.sqrt(dx * dx + dy * dy) - radius);
@ -404,7 +382,7 @@ class EdgeBase {
* @param position
* @param viaNode
*/
getArrowData(ctx, position, viaNode, selected, hover) {
getArrowData(ctx, position, viaNode, selected, hover, values) {
// set lets
let angle;
let arrowPoint;
@ -413,27 +391,27 @@ class EdgeBase {
let guideOffset;
let scaleFactor;
let type;
let lineWidth = this.getLineWidth(selected, hover);
let lineWidth = values.width;
if (position === 'from') {
node1 = this.from;
node2 = this.to;
guideOffset = 0.1;
scaleFactor = this.options.arrows.from.scaleFactor;
type = this.options.arrows.from.type;
scaleFactor = values.fromArrowScale;
type = values.fromArrowType;
}
else if (position === 'to') {
node1 = this.to;
node2 = this.from;
guideOffset = -0.1;
scaleFactor = this.options.arrows.to.scaleFactor;
type = this.options.arrows.to.type;
scaleFactor = values.toArrowScale;
type = values.toArrowType;
}
else {
node1 = this.to;
node2 = this.from;
scaleFactor = this.options.arrows.middle.scaleFactor;
type = this.options.arrows.middle.type;
scaleFactor = values.middleArrowScale;
type = values.middleArrowType;
}
// if not connected to itself
@ -441,33 +419,28 @@ class EdgeBase {
if (position !== 'middle') {
// draw arrow head
if (this.options.smooth.enabled === true) {
arrowPoint = this.findBorderPosition(node1, ctx, {via: viaNode});
arrowPoint = this.findBorderPosition(node1, ctx, { via: viaNode });
let guidePos = this.getPoint(Math.max(0.0, Math.min(1.0, arrowPoint.t + guideOffset)), viaNode);
angle = Math.atan2((arrowPoint.y - guidePos.y), (arrowPoint.x - guidePos.x));
}
else {
} else {
angle = Math.atan2((node1.y - node2.y), (node1.x - node2.x));
arrowPoint = this.findBorderPosition(node1, ctx);
}
}
else {
} else {
angle = Math.atan2((node1.y - node2.y), (node1.x - node2.x));
arrowPoint = this.getPoint(0.5, viaNode); // this is 0.6 to account for the size of the arrow.
}
}
else {
} else {
// draw circle
let [x,y,radius] = this._getCircleData(ctx);
if (position === 'from') {
arrowPoint = this.findBorderPosition(this.from, ctx, {x, y, low:0.25, high:0.6, direction:-1});
arrowPoint = this.findBorderPosition(this.from, ctx, { x, y, low: 0.25, high: 0.6, direction: -1 });
angle = arrowPoint.t * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI;
}
else if (position === 'to') {
arrowPoint = this.findBorderPosition(this.from, ctx, {x, y, low:0.6, high:1.0, direction:1});
} else if (position === 'to') {
arrowPoint = this.findBorderPosition(this.from, ctx, { x, y, low: 0.6, high: 1.0, direction: 1 });
angle = arrowPoint.t * -2 * Math.PI + 1.5 * Math.PI - 1.1 * Math.PI;
}
else {
} else {
arrowPoint = this._pointOnCircle(x, y, radius, 0.175);
angle = 3.9269908169872414; // === 0.175 * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI;
}
@ -477,9 +450,9 @@ class EdgeBase {
var xi = arrowPoint.x - length * 0.9 * Math.cos(angle);
var yi = arrowPoint.y - length * 0.9 * Math.sin(angle);
let arrowCore = {x: xi, y: yi};
let arrowCore = { x: xi, y: yi };
return {point: arrowPoint, core: arrowCore, angle: angle, length: length, type: type};
return { point: arrowPoint, core: arrowCore, angle: angle, length: length, type: type };
}
/**
@ -489,11 +462,11 @@ class EdgeBase {
* @param hover
* @param arrowData
*/
drawArrowHead(ctx, selected, hover, arrowData) {
drawArrowHead(ctx, values, selected, hover, arrowData) {
// set style
ctx.strokeStyle = this.getColor(ctx, selected, hover);
ctx.strokeStyle = this.getColor(ctx, values, selected, hover);
ctx.fillStyle = ctx.strokeStyle;
ctx.lineWidth = this.getLineWidth(selected, hover);
ctx.lineWidth = values.width;
if (arrowData.type && arrowData.type.toLowerCase() === 'circle') {
// draw circle at the end of the line
@ -504,24 +477,24 @@ class EdgeBase {
}
// draw shadow if enabled
this.enableShadow(ctx);
this.enableShadow(ctx, values);
ctx.fill();
// disable shadows for other elements.
this.disableShadow(ctx);
this.disableShadow(ctx, values);
}
enableShadow(ctx) {
if (this.options.shadow.enabled === true) {
ctx.shadowColor = this.options.shadow.color;
ctx.shadowBlur = this.options.shadow.size;
ctx.shadowOffsetX = this.options.shadow.x;
ctx.shadowOffsetY = this.options.shadow.y;
enableShadow(ctx, values) {
if (values.shadow === true) {
ctx.shadowColor = values.shadowColor;
ctx.shadowBlur = values.shadowSize;
ctx.shadowOffsetX = values.shadowX;
ctx.shadowOffsetY = values.shadowY;
}
}
disableShadow(ctx) {
if (this.options.shadow.enabled === true) {
disableShadow(ctx, values) {
if (values.shadow === true) {
ctx.shadowColor = 'rgba(0,0,0,0)';
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;

+ 18
- 22
lib/network/modules/components/nodes/shapes/Box.js View File

@ -8,59 +8,55 @@ class Box extends NodeBase {
this._setMargins(labelModule);
}
resize(ctx, selected) {
if (this.width === undefined) {
this.textSize = this.labelModule.getTextSize(ctx,selected);
resize(ctx, selected = this.selected, hover = this.hover) {
if ((this.width === undefined) || this.labelModule.differentState(selected, hover)) {
this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
this.width = this.textSize.width + this.margin.right + this.margin.left;
this.height = this.textSize.height + this.margin.top + this.margin.bottom;
this.radius = this.width / 2;
}
}
draw(ctx, x, y, selected, hover) {
this.resize(ctx, selected);
draw(ctx, x, y, selected, hover, values) {
this.resize(ctx, selected, hover);
this.left = x - this.width / 2;
this.top = y - this.height / 2;
let borderWidth = this.options.borderWidth;
let selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
ctx.lineWidth = (selected ? selectionLineWidth : borderWidth);
ctx.strokeStyle = values.borderColor;
ctx.lineWidth = values.borderWidth;
ctx.lineWidth /= this.body.view.scale;
ctx.lineWidth = Math.min(this.width, ctx.lineWidth);
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx.fillStyle = values.color;
let borderRadius = this.options.shapeProperties.borderRadius; // only effective for box
ctx.roundRect(this.left, this.top, this.width, this.height, borderRadius);
ctx.roundRect(this.left, this.top, this.width, this.height, values.borderRadius);
// draw shadow if enabled
this.enableShadow(ctx);
this.enableShadow(ctx, values);
// draw the background
ctx.fill();
// disable shadows for other elements.
this.disableShadow(ctx);
this.disableShadow(ctx, values);
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
// if borders are zero width, they will be drawn with width 1 by default. This prevents that
if (borderWidth > 0) {
this.enableBorderDashes(ctx);
if (values.borderWidth > 0) {
this.enableBorderDashes(ctx, values);
//draw the border
ctx.stroke();
//disable dashed border for other elements
this.disableBorderDashes(ctx);
this.disableBorderDashes(ctx, values);
}
ctx.restore();
this.updateBoundingBox(x,y,ctx,selected);
this.updateBoundingBox(x, y, ctx, selected, hover);
this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left,
this.top + this.textSize.height / 2 + this.margin.top, selected);
this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
}
updateBoundingBox(x,y, ctx, selected) {
this.resize(ctx, selected);
updateBoundingBox(x, y, ctx, selected, hover) {
this.resize(ctx, selected, hover);
this.left = x - this.width / 2;
this.top = y - this.height / 2;

+ 11
- 11
lib/network/modules/components/nodes/shapes/Circle.js View File

@ -8,9 +8,9 @@ class Circle extends CircleImageBase {
this._setMargins(labelModule);
}
resize(ctx, selected) {
if (this.width === undefined) {
this.textSize = this.labelModule.getTextSize(ctx, selected);
resize(ctx, selected = this.selected, hover = this.hover, values = { size: this.options.size}) {
if ((this.width === undefined) || (this.labelModule.differentState(selected, hover))) {
this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
var diameter = Math.max(this.textSize.width + this.margin.right + this.margin.left,
this.textSize.height + this.margin.top + this.margin.bottom);
this.options.size = diameter / 2;
@ -21,21 +21,21 @@ class Circle extends CircleImageBase {
}
}
draw(ctx, x, y, selected, hover) {
this.resize(ctx, selected);
draw(ctx, x, y, selected, hover, values) {
this.resize(ctx, selected, hover);
this.left = x - this.width / 2;
this.top = y - this.height / 2;
this._drawRawCircle(ctx, x, y, selected, hover, this.options.size);
this._drawRawCircle(ctx, x, y, selected, hover, values);
this.boundingBox.top = y - this.options.size;
this.boundingBox.left = x - this.options.size;
this.boundingBox.right = x + this.options.size;
this.boundingBox.bottom = y + this.options.size;
this.boundingBox.top = y - values.size;
this.boundingBox.left = x - values.size;
this.boundingBox.right = x + values.size;
this.boundingBox.bottom = y + values.size;
this.updateBoundingBox(x,y);
this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left,
this.top + this.textSize.height / 2 + this.margin.top, selected);
this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
}
updateBoundingBox(x,y) {

+ 16
- 16
lib/network/modules/components/nodes/shapes/CircularImage.js View File

@ -10,17 +10,17 @@ class CircularImage extends CircleImageBase {
this._swapToImageResizeWhenImageLoaded = true;
}
resize() {
if (this.imageObj.src === undefined || this.imageObj.width === undefined || this.imageObj.height === undefined ) {
if (!this.width) {
var diameter = this.options.size * 2;
this.width = diameter;
this.height = diameter;
this._swapToImageResizeWhenImageLoaded = true;
this.radius = 0.5*this.width;
}
}
else {
resize(ctx, selected = this.selected, hover = this.hover) {
if ((this.imageObj.src === undefined) ||
(this.imageObj.width === undefined) ||
(this.imageObj.height === undefined) ||
(this.labelModule.differentState(selected, hover))) {
var diameter = this.options.size * 2;
this.width = diameter;
this.height = diameter;
this._swapToImageResizeWhenImageLoaded = true;
this.radius = 0.5*this.width;
} else {
if (this._swapToImageResizeWhenImageLoaded) {
this.width = undefined;
this.height = undefined;
@ -30,7 +30,7 @@ class CircularImage extends CircleImageBase {
}
}
draw(ctx, x, y, selected, hover) {
draw(ctx, x, y, selected, hover, values) {
this.resize();
this.left = x - this.width / 2;
@ -39,18 +39,18 @@ class CircularImage extends CircleImageBase {
let size = Math.min(0.5*this.height, 0.5*this.width);
// draw the background circle. IMPORTANT: the stroke in this method is used by the clip method below.
this._drawRawCircle(ctx, x, y, selected, hover, size);
this._drawRawCircle(ctx, x, y, selected, hover, values);
// now we draw in the circle, we save so we can revert the clip operation after drawing.
ctx.save();
// clip is used to use the stroke in drawRawCircle as an area that we can draw in.
ctx.clip();
// draw the image
this._drawImageAtPosition(ctx);
this._drawImageAtPosition(ctx, values);
// restore so we can again draw on the full canvas
ctx.restore();
this._drawImageLabel(ctx, x, y, selected);
this._drawImageLabel(ctx, x, y, selected, hover);
this.updateBoundingBox(x,y);
}
@ -72,4 +72,4 @@ class CircularImage extends CircleImageBase {
}
}
export default CircularImage;
export default CircularImage;

+ 16
- 18
lib/network/modules/components/nodes/shapes/Database.js View File

@ -8,9 +8,9 @@ class Database extends NodeBase {
this._setMargins(labelModule);
}
resize(ctx, selected) {
if (this.width === undefined) {
this.textSize = this.labelModule.getTextSize(ctx, selected);
resize(ctx, selected, hover) {
if ((this.width === undefined) || (this.labelModule.differentState(selected, hover))) {
this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
var size = this.textSize.width + this.margin.right + this.margin.left;
this.width = size;
this.height = size;
@ -18,47 +18,45 @@ class Database extends NodeBase {
}
}
draw(ctx, x, y, selected, hover) {
this.resize(ctx, selected);
draw(ctx, x, y, selected, hover, values) {
this.resize(ctx, selected, hover);
this.left = x - this.width / 2;
this.top = y - this.height / 2;
var neutralborderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
var borderWidth = values.borderWidth / this.body.view.scale;
ctx.lineWidth = Math.min(this.width, borderWidth);
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
ctx.strokeStyle = values.borderColor;
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx.fillStyle = values.color;
ctx.database(x - this.width / 2, y - this.height / 2, this.width, this.height);
// draw shadow if enabled
this.enableShadow(ctx);
this.enableShadow(ctx, values);
// draw the background
ctx.fill();
// disable shadows for other elements.
this.disableShadow(ctx);
this.disableShadow(ctx, values);
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
// if borders are zero width, they will be drawn with width 1 by default. This prevents that
if (borderWidth > 0) {
this.enableBorderDashes(ctx);
this.enableBorderDashes(ctx, values);
//draw the border
ctx.stroke();
//disable dashed border for other elements
this.disableBorderDashes(ctx);
this.disableBorderDashes(ctx, values);
}
ctx.restore();
this.updateBoundingBox(x,y,ctx,selected);
this.updateBoundingBox(x, y, ctx, selected, hover);
this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left,
this.top + this.textSize.height / 2 + this.margin.top, selected);
this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
}
updateBoundingBox(x,y,ctx, selected) {
this.resize(ctx, selected);
updateBoundingBox(x, y, ctx, selected, hover) {
this.resize(ctx, selected, hover);
this.left = x - this.width * 0.5;
this.top = y - this.height * 0.5;

+ 5
- 5
lib/network/modules/components/nodes/shapes/Diamond.js View File

@ -7,12 +7,12 @@ class Diamond extends ShapeBase {
super(options, body, labelModule)
}
resize(ctx) {
this._resizeShape();
resize(ctx, values, selected = this.selected, hover = this.hover) {
this._resizeShape(selected, hover, values);
}
draw(ctx, x, y, selected, hover) {
this._drawShape(ctx, 'diamond', 4, x, y, selected, hover);
draw(ctx, x, y, selected, hover, values) {
this._drawShape(ctx, 'diamond', 4, x, y, selected, hover, values);
}
distanceToBorder(ctx, angle) {
@ -20,4 +20,4 @@ class Diamond extends ShapeBase {
}
}
export default Diamond;
export default Diamond;

+ 5
- 5
lib/network/modules/components/nodes/shapes/Dot.js View File

@ -7,12 +7,12 @@ class Dot extends ShapeBase {
super(options, body, labelModule)
}
resize(ctx) {
this._resizeShape();
resize(ctx, values, selected = this.selected, hover = this.hover) {
this._resizeShape(selected, hover, values);
}
draw(ctx, x, y, selected, hover) {
this._drawShape(ctx, 'circle', 2, x, y, selected, hover);
draw(ctx, x, y, selected, hover, values) {
this._drawShape(ctx, 'circle', 2, x, y, selected, hover, values);
}
distanceToBorder(ctx, angle) {
@ -21,4 +21,4 @@ class Dot extends ShapeBase {
}
}
export default Dot;
export default Dot;

+ 16
- 18
lib/network/modules/components/nodes/shapes/Ellipse.js View File

@ -7,9 +7,9 @@ class Ellipse extends NodeBase {
super(options, body, labelModule);
}
resize(ctx, selected) {
if (this.width === undefined) {
var textSize = this.labelModule.getTextSize(ctx, selected);
resize(ctx, selected = this.selected, hover = this.hover) {
if ((this.width === undefined) || (this.labelModule.differentState(selected, hover))) {
var textSize = this.labelModule.getTextSize(ctx, selected, hover);
this.height = textSize.height * 2;
this.width = textSize.width + this.height;
@ -17,48 +17,46 @@ class Ellipse extends NodeBase {
}
}
draw(ctx, x, y, selected, hover) {
this.resize(ctx, selected);
draw(ctx, x, y, selected, hover, values) {
this.resize(ctx, selected, hover);
this.left = x - this.width * 0.5;
this.top = y - this.height * 0.5;
var neutralborderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
var borderWidth = values.borderWidth / this.body.view.scale;
ctx.lineWidth = Math.min(this.width, borderWidth);
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
ctx.strokeStyle = values.borderColor;
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx.fillStyle = values.color;
ctx.ellipse(this.left, this.top, this.width, this.height);
// draw shadow if enabled
this.enableShadow(ctx);
this.enableShadow(ctx, values);
// draw the background
ctx.fill();
// disable shadows for other elements.
this.disableShadow(ctx);
this.disableShadow(ctx, values);
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
// if borders are zero width, they will be drawn with width 1 by default. This prevents that
if (borderWidth > 0) {
this.enableBorderDashes(ctx);
this.enableBorderDashes(ctx, values);
//draw the border
ctx.stroke();
//disable dashed border for other elements
this.disableBorderDashes(ctx);
this.disableBorderDashes(ctx, values);
}
ctx.restore();
this.updateBoundingBox(x, y, ctx, selected);
this.labelModule.draw(ctx, x, y, selected);
this.updateBoundingBox(x, y, ctx, selected, hover);
this.labelModule.draw(ctx, x, y, selected, hover);
}
updateBoundingBox(x, y, ctx, selected) {
this.resize(ctx, selected); // just in case
updateBoundingBox(x, y, ctx, selected, hover) {
this.resize(ctx, selected, hover); // just in case
this.left = x - this.width * 0.5;
this.top = y - this.height * 0.5;

+ 11
- 12
lib/network/modules/components/nodes/shapes/Icon.js View File

@ -8,8 +8,8 @@ class Icon extends NodeBase {
this._setMargins(labelModule);
}
resize(ctx) {
if (this.width === undefined) {
resize(ctx, selected, hover) {
if ((this.width === undefined) || (this.labelModule.differentState(selected, hover))) {
this.iconSize = {
width: Number(this.options.icon.size),
height: Number(this.options.icon.size)
@ -20,13 +20,13 @@ class Icon extends NodeBase {
}
}
draw(ctx, x, y, selected, hover) {
this.resize(ctx);
draw(ctx, x, y, selected, hover, values) {
this.resize(ctx, selected, hover);
this.options.icon.size = this.options.icon.size || 50;
this.left = x - this.width / 2;
this.top = y - this.height / 2;
this._icon(ctx, x, y, selected);
this._icon(ctx, x, y, selected, hover, values);
if (this.options.label !== undefined) {
var iconTextSpacing = 5;
@ -34,10 +34,10 @@ class Icon extends NodeBase {
y + this.height / 2 + iconTextSpacing, selected);
}
this.updateBoundingBox(x,y)
this.updateBoundingBox(x, y)
}
updateBoundingBox(x,y) {
updateBoundingBox(x, y) {
this.boundingBox.top = y - this.options.icon.size * 0.5;
this.boundingBox.left = x - this.options.icon.size * 0.5;
this.boundingBox.right = x + this.options.icon.size * 0.5;
@ -51,7 +51,7 @@ class Icon extends NodeBase {
}
}
_icon(ctx, x, y, selected) {
_icon(ctx, x, y, selected, hover, values) {
let iconSize = Number(this.options.icon.size);
if (this.options.icon.code !== undefined) {
@ -63,13 +63,12 @@ class Icon extends NodeBase {
ctx.textBaseline = "middle";
// draw shadow if enabled
this.enableShadow(ctx);
this.enableShadow(ctx, values);
ctx.fillText(this.options.icon.code, x, y);
// disable shadows for other elements.
this.disableShadow(ctx);
}
else {
this.disableShadow(ctx, values);
} else {
console.error('When using the icon shape, you need to define the code in the icon options object. This can be done per node or globally.')
}

+ 4
- 4
lib/network/modules/components/nodes/shapes/Image.js View File

@ -12,7 +12,7 @@ class Image extends CircleImageBase {
this._resizeImage();
}
draw(ctx, x, y, selected, hover) {
draw(ctx, x, y, selected, hover, values) {
this.resize();
this.left = x - this.width / 2;
this.top = y - this.height / 2;
@ -53,9 +53,9 @@ class Image extends CircleImageBase {
ctx.closePath();
}
this._drawImageAtPosition(ctx);
this._drawImageAtPosition(ctx, values);
this._drawImageLabel(ctx, x, y, selected || hover);
this._drawImageLabel(ctx, x, y, selected, hover);
this.updateBoundingBox(x,y);
}
@ -82,4 +82,4 @@ class Image extends CircleImageBase {
}
}
export default Image;
export default Image;

+ 3
- 3
lib/network/modules/components/nodes/shapes/Square.js View File

@ -11,8 +11,8 @@ class Square extends ShapeBase {
this._resizeShape();
}
draw(ctx, x, y, selected, hover) {
this._drawShape(ctx, 'square', 2, x, y, selected, hover);
draw(ctx, x, y, selected, hover, values) {
this._drawShape(ctx, 'square', 2, x, y, selected, hover, values);
}
distanceToBorder(ctx, angle) {
@ -20,4 +20,4 @@ class Square extends ShapeBase {
}
}
export default Square;
export default Square;

+ 5
- 5
lib/network/modules/components/nodes/shapes/Star.js View File

@ -7,12 +7,12 @@ class Star extends ShapeBase {
super(options, body, labelModule)
}
resize(ctx) {
this._resizeShape();
resize(ctx, values, selected, hover) {
this._resizeShape(selected, hover, values);
}
draw(ctx, x, y, selected, hover) {
this._drawShape(ctx, 'star', 4, x, y, selected, hover);
draw(ctx, x, y, selected, hover, values) {
this._drawShape(ctx, 'star', 4, x, y, selected, hover, values);
}
distanceToBorder(ctx, angle) {
@ -20,4 +20,4 @@ class Star extends ShapeBase {
}
}
export default Star;
export default Star;

+ 11
- 11
lib/network/modules/components/nodes/shapes/Text.js View File

@ -8,33 +8,33 @@ class Text extends NodeBase {
this._setMargins(labelModule);
}
resize(ctx, selected) {
if (this.width === undefined) {
this.textSize = this.labelModule.getTextSize(ctx,selected);
resize(ctx, selected, hover) {
if ((this.width === undefined) || this.labelModule.differentState(selected, hover)) {
this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
this.width = this.textSize.width + this.margin.right + this.margin.left;
this.height = this.textSize.height + this.margin.top + this.margin.bottom;
this.radius = 0.5*this.width;
}
}
draw(ctx, x, y, selected, hover) {
this.resize(ctx, selected || hover);
draw(ctx, x, y, selected, hover, values) {
this.resize(ctx, selected, hover);
this.left = x - this.width / 2;
this.top = y - this.height / 2;
// draw shadow if enabled
this.enableShadow(ctx);
this.enableShadow(ctx, values);
this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left,
this.top + this.textSize.height / 2 + this.margin.top, selected || hover);
this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
// disable shadows for other elements.
this.disableShadow(ctx);
this.disableShadow(ctx, values);
this.updateBoundingBox(x, y, ctx, selected);
this.updateBoundingBox(x, y, ctx, selected, hover);
}
updateBoundingBox(x, y, ctx, selected) {
this.resize(ctx, selected);
updateBoundingBox(x, y, ctx, selected, hover) {
this.resize(ctx, selected, hover);
this.left = x - this.width / 2;
this.top = y - this.height / 2;

+ 3
- 3
lib/network/modules/components/nodes/shapes/Triangle.js View File

@ -11,8 +11,8 @@ class Triangle extends ShapeBase {
this._resizeShape();
}
draw(ctx, x, y, selected, hover) {
this._drawShape(ctx, 'triangle', 3, x, y, selected, hover);
draw(ctx, x, y, selected, hover, values) {
this._drawShape(ctx, 'triangle', 3, x, y, selected, hover, values);
}
distanceToBorder(ctx, angle) {
@ -20,4 +20,4 @@ class Triangle extends ShapeBase {
}
}
export default Triangle;
export default Triangle;

+ 3
- 3
lib/network/modules/components/nodes/shapes/TriangleDown.js View File

@ -11,8 +11,8 @@ class TriangleDown extends ShapeBase {
this._resizeShape();
}
draw(ctx, x, y, selected, hover) {
this._drawShape(ctx, 'triangleDown', 3, x, y, selected, hover);
draw(ctx, x, y, selected, hover, values) {
this._drawShape(ctx, 'triangleDown', 3, x, y, selected, hover, values);
}
distanceToBorder(ctx, angle) {
@ -20,4 +20,4 @@ class TriangleDown extends ShapeBase {
}
}
export default TriangleDown;
export default TriangleDown;

+ 16
- 18
lib/network/modules/components/nodes/util/CircleImageBase.js View File

@ -65,43 +65,41 @@ class CircleImageBase extends NodeBase {
}
_drawRawCircle(ctx, x, y, selected, hover, size) {
var neutralborderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
_drawRawCircle(ctx, x, y, selected, hover, values) {
var borderWidth = values.borderWidth / this.body.view.scale;
ctx.lineWidth = Math.min(this.width, borderWidth);
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx.circle(x, y, size);
ctx.strokeStyle = values.borderColor;
ctx.fillStyle = values.color;
ctx.circle(x, y, values.size);
// draw shadow if enabled
this.enableShadow(ctx);
this.enableShadow(ctx, values);
// draw the background
ctx.fill();
// disable shadows for other elements.
this.disableShadow(ctx);
this.disableShadow(ctx, values);
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
// if borders are zero width, they will be drawn with width 1 by default. This prevents that
if (borderWidth > 0) {
this.enableBorderDashes(ctx);
this.enableBorderDashes(ctx, values);
//draw the border
ctx.stroke();
//disable dashed border for other elements
this.disableBorderDashes(ctx);
this.disableBorderDashes(ctx, values);
}
ctx.restore();
}
_drawImageAtPosition(ctx) {
_drawImageAtPosition(ctx, values) {
if (this.imageObj.width != 0) {
// draw the image
ctx.globalAlpha = 1.0;
// draw shadow if enabled
this.enableShadow(ctx);
this.enableShadow(ctx, values);
let factor = (this.imageObj.width / this.width) / this.body.view.scale;
if (factor > 2 && this.options.shapeProperties.interpolation === true) {
@ -136,17 +134,17 @@ class CircleImageBase extends NodeBase {
// disable shadows for other elements.
this.disableShadow(ctx);
this.disableShadow(ctx, values);
}
}
_drawImageLabel(ctx, x, y, selected) {
_drawImageLabel(ctx, x, y, selected, hover) {
var yLabel;
var offset = 0;
if (this.height !== undefined) {
offset = this.height * 0.5;
var labelDimensions = this.labelModule.getTextSize(ctx);
var labelDimensions = this.labelModule.getTextSize(ctx, selected, hover);
if (labelDimensions.lineCount >= 1) {
offset += labelDimensions.height / 2;
}
@ -157,8 +155,8 @@ class CircleImageBase extends NodeBase {
if (this.options.label) {
this.labelOffset = offset;
}
this.labelModule.draw(ctx, x, yLabel, selected, 'hanging');
this.labelModule.draw(ctx, x, yLabel, selected, hover, 'hanging');
}
}
export default CircleImageBase;
export default CircleImageBase;

+ 15
- 13
lib/network/modules/components/nodes/util/NodeBase.js View File

@ -42,17 +42,17 @@ class NodeBase {
Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth;
}
enableShadow(ctx) {
if (this.options.shadow.enabled === true) {
ctx.shadowColor = this.options.shadow.color;
ctx.shadowBlur = this.options.shadow.size;
ctx.shadowOffsetX = this.options.shadow.x;
ctx.shadowOffsetY = this.options.shadow.y;
enableShadow(ctx, values) {
if (values.shadow) {
ctx.shadowColor = values.shadowColor;
ctx.shadowBlur = values.shadowSize;
ctx.shadowOffsetX = values.shadowX;
ctx.shadowOffsetY = values.shadowY;
}
}
disableShadow(ctx) {
if (this.options.shadow.enabled === true) {
disableShadow(ctx, values) {
if (values.shadow) {
ctx.shadowColor = 'rgba(0,0,0,0)';
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
@ -60,10 +60,10 @@ class NodeBase {
}
}
enableBorderDashes(ctx) {
if (this.options.shapeProperties.borderDashes !== false) {
enableBorderDashes(ctx, values) {
if (values.borderDashes !== false) {
if (ctx.setLineDash !== undefined) {
let dashes = this.options.shapeProperties.borderDashes;
let dashes = values.borderDashes;
if (dashes === true) {
dashes = [5,15]
}
@ -72,18 +72,20 @@ class NodeBase {
else {
console.warn("setLineDash is not supported in this browser. The dashed borders cannot be used.");
this.options.shapeProperties.borderDashes = false;
values.borderDashes = false;
}
}
}
disableBorderDashes(ctx) {
if (this.options.shapeProperties.borderDashes !== false) {
disableBorderDashes(ctx, values) {
if (values.borderDashes !== false) {
if (ctx.setLineDash !== undefined) {
ctx.setLineDash([0]);
}
else {
console.warn("setLineDash is not supported in this browser. The dashed borders cannot be used.");
this.options.shapeProperties.borderDashes = false;
values.borderDashes = false;
}
}
}

+ 15
- 17
lib/network/modules/components/nodes/util/ShapeBase.js View File

@ -5,52 +5,50 @@ class ShapeBase extends NodeBase {
super(options, body, labelModule)
}
_resizeShape() {
if (this.width === undefined) {
var size = 2 * this.options.size;
_resizeShape(selected = this.selected, hover = this.hover, values = { size: this.options.size }) {
if ((this.width === undefined) || (this.labelModule.differentState(selected, hover))) {
var size = 2 * values.size;
this.width = size;
this.height = size;
this.radius = 0.5*this.width;
}
}
_drawShape(ctx, shape, sizeMultiplier, x, y, selected, hover) {
this._resizeShape();
_drawShape(ctx, shape, sizeMultiplier, x, y, selected, hover, values) {
this._resizeShape(selected, hover, values);
this.left = x - this.width / 2;
this.top = y - this.height / 2;
var neutralborderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
var borderWidth = values.borderWidth / this.body.view.scale;
ctx.lineWidth = Math.min(this.width, borderWidth);
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx[shape](x, y, this.options.size);
ctx.strokeStyle = values.borderColor;
ctx.fillStyle = values.color;
ctx[shape](x, y, values.size);
// draw shadow if enabled
this.enableShadow(ctx);
this.enableShadow(ctx, values);
// draw the background
ctx.fill();
// disable shadows for other elements.
this.disableShadow(ctx);
this.disableShadow(ctx, values);
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
// if borders are zero width, they will be drawn with width 1 by default. This prevents that
if (borderWidth > 0) {
this.enableBorderDashes(ctx);
this.enableBorderDashes(ctx, values);
//draw the border
ctx.stroke();
//disable dashed border for other elements
this.disableBorderDashes(ctx);
this.disableBorderDashes(ctx, values);
}
ctx.restore();
if (this.options.label !== undefined) {
let yLabel = y + 0.5 * this.height + 3; // the + 3 is to offset it a bit below the node.
this.labelModule.draw(ctx, x, yLabel, selected, 'hanging');
this.labelModule.draw(ctx, x, yLabel, selected, hover, 'hanging');
}
this.updateBoundingBox(x,y);
@ -73,4 +71,4 @@ class ShapeBase extends NodeBase {
}
export default ShapeBase;
export default ShapeBase;

+ 83
- 53
lib/network/modules/components/shared/Label.js View File

@ -95,6 +95,23 @@ class Label {
}
}
// set the selected functions based on 'nearest' value
choosify(elementOptions, options, defaultOptions) {
this.fontOptions.chooser = true;
let pile = [options, elementOptions, defaultOptions];
let chosen = util.topMost(pile, 'chosen');
if (typeof chosen === 'boolean') {
this.fontOptions.chooser = chosen;
} else if (typeof chosen === 'object') {
let chosenLabel = util.topMost(pile, ['chosen', 'label']);
if ((typeof chosenLabel === 'boolean') || (typeof chosenLabel === 'function')) {
this.fontOptions.chooser = chosenLabel;
}
}
}
// When margins are set in an element, adjust sizes is called to remove them
// from the width/height constraints. This must be done prior to label sizing.
adjustSizes(margins) {
@ -239,7 +256,7 @@ class Label {
* @param selected
* @param baseline
*/
draw(ctx, x, y, selected, baseline = 'middle') {
draw(ctx, x, y, selected, hover, baseline = 'middle') {
// if no label, return
if (this.elementOptions.label === undefined)
return;
@ -250,12 +267,12 @@ class Label {
return;
// update the size cache if required
this.calculateLabelSize(ctx, selected, x, y, baseline);
this.calculateLabelSize(ctx, selected, hover, x, y, baseline);
// create the fontfill background
this._drawBackground(ctx);
// draw text
this._drawText(ctx, selected, x, y, baseline);
this._drawText(ctx, selected, hover, x, y, baseline);
}
/**
@ -298,7 +315,7 @@ class Label {
* @param baseline
* @private
*/
_drawText(ctx, selected, x, y, baseline = 'middle') {
_drawText(ctx, selected, hover, x, y, baseline = 'middle') {
let fontSize = this.fontOptions.size;
let viewFontSize = fontSize * this.body.view.scale;
// this ensures that there will not be HUGE letters on screen by setting an upper limit on the visible text size (regardless of zoomLevel)
@ -332,14 +349,17 @@ class Label {
for (let j = 0; j < this.lines[i].blocks.length; j++) {
let block = this.lines[i].blocks[j];
ctx.font = block.font;
let [fontColor, strokeColor] = this._getColor(block.color, viewFontSize);
if (this.fontOptions.strokeWidth > 0) {
ctx.lineWidth = this.fontOptions.strokeWidth;
let [fontColor, strokeColor] = this._getColor(block.color, viewFontSize, block.strokeColor);
if (block.strokeWidth > 0) {
ctx.lineWidth = block.strokeWidth;
ctx.strokeStyle = strokeColor;
ctx.lineJoin = 'round';
ctx.strokeText(block.text, x + width, yLine + block.vadjust);
}
ctx.fillStyle = fontColor;
if (block.strokeWidth > 0) {
ctx.strokeText(block.text, x + width, yLine + block.vadjust);
}
ctx.fillText(block.text, x + width, yLine + block.vadjust);
width += block.width;
}
@ -382,9 +402,9 @@ class Label {
* @returns {*[]}
* @private
*/
_getColor(color, viewFontSize) {
_getColor(color, viewFontSize, initialStrokeColor) {
let fontColor = color || '#000000';
let strokeColor = this.fontOptions.strokeColor || '#ffffff';
let strokeColor = initialStrokeColor || '#ffffff';
if (viewFontSize <= this.elementOptions.scaling.label.drawThreshold) {
let opacity = Math.max(0, Math.min(1, 1 - (this.elementOptions.scaling.label.drawThreshold - viewFontSize)));
fontColor = util.overrideOpacity(fontColor, opacity);
@ -400,8 +420,8 @@ class Label {
* @param selected
* @returns {{width: number, height: number}}
*/
getTextSize(ctx, selected = false) {
this._processLabel(ctx, selected);
getTextSize(ctx, selected = false, hover = false) {
this._processLabel(ctx, selected, hover);
return {
width: this.size.width,
height: this.size.height,
@ -418,9 +438,9 @@ class Label {
* @param y
* @param baseline
*/
calculateLabelSize(ctx, selected, x = 0, y = 0, baseline = 'middle') {
calculateLabelSize(ctx, selected, hover, x = 0, y = 0, baseline = 'middle') {
if (this.labelDirty === true) {
this._processLabel(ctx, selected);
this._processLabel(ctx, selected, hover);
}
this.size.left = x - this.size.width * 0.5;
this.size.top = y - this.size.height * 0.5;
@ -696,29 +716,37 @@ class Label {
return blocks;
}
setFont(ctx, selected, mod) {
let height
let vadjust
let color
if (mod === 'normal') {
ctx.font = (selected && this.elementOptions.labelHighlightBold ? 'bold ' : '') +
this.fontOptions.size + "px " + this.fontOptions.face;
color = this.fontOptions.color;
height = this.fontOptions.size;
vadjust = this.fontOptions.vadjust;
getFormattingValues(ctx, selected, hover, mod) {
let values = {
color: (mod === "normal") ? this.fontOptions.color : this.fontOptions[mod].color,
size: (mod === "normal") ? this.fontOptions.size : this.fontOptions[mod].size,
face: (mod === "normal") ? this.fontOptions.face : this.fontOptions[mod].face,
mod: (mod === "normal") ? "" : this.fontOptions[mod].mod,
vadjust: (mod === "normal") ? this.fontOptions.vadjust : this.fontOptions[mod].vadjust,
strokeWidth: this.fontOptions.strokeWidth,
strokeColor: this.fontOptions.strokeColor
};
if (mod === "normal") {
if (selected || hover) {
if ((this.fontOptions.chooser === true) && (this.elementOptions.labelHighlightBold)) {
values.mod = 'bold';
} else if (typeof this.fontOptions.chooser === 'function') {
this.fontOptions.chooser(ctx, values, this.elementOptions.id, selected, hover);
}
}
} else {
ctx.font = this.fontOptions[mod].mod + " " +
this.fontOptions[mod].size + "px " + this.fontOptions[mod].face;
color = this.fontOptions[mod].color;
height = this.fontOptions[mod].size;
vadjust = this.fontOptions[mod].vadjust || 0;
}
return {
font: ctx.font.replace(/"/g, ""),
color: color,
height: height,
vadjust: vadjust
if ((selected || hover) && (typeof this.fontOptions.chooser === 'function')) {
this.fontOptions.chooser(ctx, values, this.elementOptions.id, selected, hover);
}
}
ctx.font = (values.mod + " " + values.size + "px " + values.face).replace(/"/g, "");
values.font = ctx.font;
values.height = values.size;
return values;
}
differentState(selected, hover) {
return ((selected !== this.fontOptions.selectedState) && (hover !== this.fontOptions.hoverState));
}
/**
@ -727,24 +755,24 @@ class Label {
* @param selected
* @private
*/
_processLabel(ctx, selected) {
_processLabel(ctx, selected, hover) {
let width = 0;
let height = 0;
let nlLines = [];
let lines = [];
let k = 0;
lines.add = function(l, text, font, color, width, height, vadjust) {
lines.add = function(l, text, font, color, width, height, vadjust, mod, strokeWidth, strokeColor) {
if (this.length == l) {
this[l] = { width: 0, height: 0, blocks: [] };
}
this[l].blocks.push({ text, font, color, width, height, vadjust });
this[l].blocks.push({ text, font, color, width, height, vadjust, mod, strokeWidth, strokeColor });
}
lines.accumulate = function(l, width, height) {
this[l].width += width;
this[l].height = height > this[l].height ? height : this[l].height;
}
lines.addAndAccumulate = function(l, text, font, color, width, height, vadjust) {
this.add(l, text, font, color, width, height, vadjust);
lines.addAndAccumulate = function(l, text, font, color, width, height, vadjust, mod, strokeWidth, strokeColor) {
this.add(l, text, font, color, width, height, vadjust, mod, strokeWidth, strokeColor);
this.accumulate(l, width, height);
}
if (this.elementOptions.label !== undefined) {
@ -757,15 +785,15 @@ class Label {
let lineHeight = 0;
if (blocks) {
if (blocks.length == 0) {
this.setFont(ctx, selected, "normal");
lines.addAndAccumulate(k, "", ctx.font, "#000000", 0, this.fontOptions.size, this.fontOptions.vadjust);
let values = this.getFormattingValues(ctx, selected, hover, "normal");
lines.addAndAccumulate(k, "", values.font, values.color, 0, values.size, values.vadjust, "normal", values.strokeWidth, values.strokeColor);
height += lines[k].height;
k++;
continue;
}
for (let j = 0; j < blocks.length; j++) {
if (this.fontOptions.maxWdt > 0) {
let metrics = this.setFont(ctx, selected, blocks[j].mod);
let values = this.getFormattingValues(ctx, selected, hover, blocks[j].mod);
let words = blocks[j].text.split(" ");
let atStart = true
let text = "";
@ -777,8 +805,8 @@ class Label {
lastMeasure = measure;
measure = ctx.measureText(text + pre + words[w]);
if (lineWidth + measure.width > this.fontOptions.maxWdt) {
lineHeight = (metrics.height > lineHeight) ? metrics.height : lineHeight;
lines.add(k, text, ctx.font, metrics.color, lastMeasure.width, metrics.height, metrics.vadjust);
lineHeight = (values.height > lineHeight) ? values.height : lineHeight;
lines.add(k, text, values.font, values.color, lastMeasure.width, values.height, values.vadjust, blocks[j].mod, values.strokeWidth, values.strokeColor);
lines.accumulate(k, lastMeasure.width, lineHeight);
text = "";
atStart = true;
@ -789,9 +817,9 @@ class Label {
} else {
text = text + pre + words[w];
if (w === words.length-1) {
lineHeight = (metrics.height > lineHeight) ? metrics.height : lineHeight;
lineHeight = (values.height > lineHeight) ? values.height : lineHeight;
lineWidth += measure.width;
lines.add(k, text, ctx.font, metrics.color, measure.width, metrics.height, metrics.vadjust);
lines.add(k, text, values.font, values.color, measure.width, values.height, values.vadjust, blocks[j].mod, values.strokeWidth, values.strokeColor);
lines.accumulate(k, measure.width, lineHeight);
if (j === blocks.length-1) {
width = lines[k].width > width ? lines[k].width : width;
@ -804,9 +832,9 @@ class Label {
}
}
} else {
let metrics = this.setFont(ctx, selected, blocks[j].mod)
let values = this.getFormattingValues(ctx, selected, hover, blocks[j].mod);
let measure = ctx.measureText(blocks[j].text);
lines.addAndAccumulate(k, blocks[j].text, ctx.font, metrics.color, measure.width, metrics.height, metrics.vadjust);
lines.addAndAccumulate(k, blocks[j].text, values.font, values.color, measure.width, values.height, values.vadjust, blocks[j].mod, values.strokeWidth, values.strokeColor);
width = lines[k].width > width ? lines[k].width : width;
if (blocks.length-1 === j) {
height += lines[k].height;
@ -818,7 +846,7 @@ class Label {
}
} else {
for (let i = 0; i < lineCount; i++) {
ctx.font = (selected && this.elementOptions.labelHighlightBold ? 'bold ' : '') + this.fontOptions.size + "px " + this.fontOptions.face;
let values = this.getFormattingValues(ctx, selected, hover, "normal");
if (this.fontOptions.maxWdt > 0) {
let words = nlLines[i].split(" ");
let text = "";
@ -830,7 +858,7 @@ class Label {
lastMeasure = measure;
measure = ctx.measureText(text + pre + words[w]);
if (measure.width > this.fontOptions.maxWdt) {
lines.addAndAccumulate(k, text, ctx.font, this.fontOptions.color, lastMeasure.width, this.fontOptions.size, this.fontOptions.vadjust)
lines.addAndAccumulate(k, text, values.font, values.color, lastMeasure.width, values.size, values.vadjust, "normal", values.strokeWidth, values.strokeColor)
width = lines[k].width > width ? lines[k].width : width;
height += lines[k].height;
text = "";
@ -838,7 +866,7 @@ class Label {
} else {
text = text + pre + words[w];
if (w === words.length-1) {
lines.addAndAccumulate(k, text, ctx.font, this.fontOptions.color, measure.width, this.fontOptions.size, this.fontOptions.vadjust)
lines.addAndAccumulate(k, text, values.font, values.color, measure.width, values.size, values.vadjust, "normal", values.strokeWidth, values.strokeColor)
width = lines[k].width > width ? lines[k].width : width;
height += lines[k].height;
k++;
@ -849,7 +877,7 @@ class Label {
} else {
let text = nlLines[i];
let measure = ctx.measureText(text);
lines.addAndAccumulate(k, text, ctx.font, this.fontOptions.color, measure.width, this.fontOptions.size, this.fontOptions.vadjust);
lines.addAndAccumulate(k, text, values.font, values.color, measure.width, values.size, values.vadjust, "normal", values.strokeWidth, values.strokeColor);
width = lines[k].width > width ? lines[k].width : width;
height += lines[k].height;
k++;
@ -868,6 +896,8 @@ class Label {
this.lineCount = lines.length;
this.size.width = width;
this.size.height = height;
this.selectedState = selected;
this.hoverState = hover;
}
}

+ 10
- 0
lib/network/options.js View File

@ -30,6 +30,11 @@ let allOptions = {
__type__: { string: ['from', 'to', 'middle'], object }
},
arrowStrikethrough: { boolean: bool },
chosen: {
label: { boolean: bool, 'function': 'function' },
edge: { boolean: bool, 'function': 'function' },
__type__: { object, boolean: bool }
},
color: {
color: { string },
highlight: { string },
@ -191,6 +196,11 @@ let allOptions = {
borderWidth: { number },
borderWidthSelected: { number, 'undefined': 'undefined' },
brokenImage: { string, 'undefined': 'undefined' },
chosen: {
label: { boolean: bool, 'function': 'function' },
node: { boolean: bool, 'function': 'function' },
__type__: { object, boolean: bool }
},
color: {
border: { string },
background: { string },

+ 1
- 1
lib/util.js View File

@ -1514,7 +1514,7 @@ exports.topMost = function (pile, accessors) {
continue;
}
}
if (candidate) {
if (typeof candidate != 'undefined') {
break;
}
}

Loading…
Cancel
Save