diff --git a/documentation/md/style.md b/documentation/md/style.md index 4538b21e18..ce28bc764a 100644 --- a/documentation/md/style.md +++ b/documentation/md/style.md @@ -369,7 +369,9 @@ These properties affect the styling of an edge's line: * **`line-color`** : The colour of the edge's line. * **`line-style`** : The style of the edge's line; may be `solid`, `dotted`, or `dashed`. * **`line-cap`** : The cap style of the edge's line; may be `butt` (default), `round`, or `square`. The cap may or may not be visible, depending on the shape of the node and the relative size of the node and edge. Caps other than `butt` extend beyond the specified endpoint of the edge. - * **`line-opacity`** : The opacity of the edge's line and arrow. Useful if you wish to have a separate opacity for the edge label versus the edge line. Note that the opacity value of the edge element affects the effective opacity of its line and label subcomponents. + * **`line-outline-width`** : The width of the edge's outline. + * **`line-outline-color`** : The colour of the edge's outline. + * **`line-opacity`** : The opacity of the edge's line, outline and arrow. Useful if you wish to have a separate opacity for the edge label versus the edge line. Note that the opacity value of the edge element affects the effective opacity of its line and label subcomponents. * **`line-fill`** : The filling style of the edge's line; may be `solid` (default), `linear-gradient` (source to target), or `radial-gradient` (midpoint outwards). * **`line-dash-pattern`** : The `dashed` line pattern which specifies alternating lengths of lines and gaps. (e.g. `[6, 3]`). * **`line-dash-offset`** : The `dashed` line offset (e.g. `24`). It is useful for creating edge animations. diff --git a/src/extensions/renderer/canvas/drawing-edges.js b/src/extensions/renderer/canvas/drawing-edges.js index e7a42137f2..7f9257ee78 100644 --- a/src/extensions/renderer/canvas/drawing-edges.js +++ b/src/extensions/renderer/canvas/drawing-edges.js @@ -30,6 +30,8 @@ CRp.drawEdge = function( context, edge, shiftToOriginWithBb, drawLabel = true, s let lineStyle = edge.pstyle('line-style').value; let edgeWidth = edge.pstyle('width').pfValue; let lineCap = edge.pstyle('line-cap').value; + let lineOutlineWidth = edge.pstyle('line-outline-width').value; + let lineOutlineColor = edge.pstyle('line-outline-color').value; let effectiveLineOpacity = opacity * lineOpacity; // separate arrow opacity would require arrow-opacity property @@ -59,6 +61,36 @@ CRp.drawEdge = function( context, edge, shiftToOriginWithBb, drawLabel = true, s } }; + let drawLineOutline = ( strokeOpacity = effectiveLineOpacity) => { + context.lineWidth = edgeWidth + lineOutlineWidth; + context.lineCap = lineCap; + + if (lineOutlineWidth > 0) { + r.colorStrokeStyle( context, lineOutlineColor[0], lineOutlineColor[1], lineOutlineColor[2], strokeOpacity ) + } else { + // do not draw any lineOutline + context.lineCap = 'butt'; // reset for other drawing functions + return + } + + if (curveStyle === 'straight-triangle') { + r.drawEdgeTrianglePath( + edge, + context, + rs.allpts + ); + } else { + r.drawEdgePath( + edge, + context, + rs.allpts, + lineStyle + ); + + context.lineCap = 'butt'; // reset for other drawing functions + } + }; + let drawOverlay = () => { if( !shouldDrawOverlay ){ return; } @@ -95,6 +127,8 @@ CRp.drawEdge = function( context, edge, shiftToOriginWithBb, drawLabel = true, s drawArrows( effectiveGhostOpacity ); context.translate( -gx, -gy ); + } else { + drawLineOutline(); } drawUnderlay(); diff --git a/src/style/properties.js b/src/style/properties.js index 668f1678e8..d4e8b018d7 100644 --- a/src/style/properties.js +++ b/src/style/properties.js @@ -357,6 +357,8 @@ const styfn = {}; { name: 'line-opacity', type: t.zeroOneNumber}, { name: 'line-dash-pattern', type: t.numbers }, { name: 'line-dash-offset', type: t.number }, + { name: 'line-outline-width', type: t.size }, + { name: 'line-outline-color', type: t.color }, { name: 'line-gradient-stop-colors', type: t.colors }, { name: 'line-gradient-stop-positions', type: t.percentages }, { name: 'curve-style', type: t.curveStyle, triggersBounds: diff.any, triggersBoundsOfParallelBeziers: true }, @@ -717,6 +719,8 @@ styfn.getDefaultProperties = function(){ 'line-fill': 'solid', 'line-cap': 'butt', 'line-opacity' : 1, + 'line-outline-width' : 0, + 'line-outline-color' : '#000', 'line-gradient-stop-colors': '#999', 'line-gradient-stop-positions': '0%', 'control-point-step-size': 40,