Skip to content

Commit

Permalink
*-endpoint: outside-to-node-or-label | outside-to-line-or-label #2151
Browse files Browse the repository at this point in the history
- Add docs
- Add property values
- Add implementation for source and target sides
  • Loading branch information
maxkfranz committed Jul 9, 2018
1 parent 0733599 commit 0f64d67
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 12 deletions.
16 changes: 9 additions & 7 deletions documentation/md/style.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ In addition to specifying the value of a property outright, the developer may al

* **`data()`** specifies a direct mapping to an element's data field. For example, `data(descr)` would map a property to the value in an element's `descr` field in its data (i.e. `ele.data("descr")`). This is useful for mapping to properties like label text content (the `content` property).
* **`mapData()`** specifies a linear mapping to an element's data field. For example, `mapData(weight, 0, 100, blue, red)` maps an element's weight to colours between blue and red for weights between 0 and 100. An element with `ele.data("weight") === 0` would be mapped to blue, for instance. Elements whose values fall outside of the specified range are mapped to the extremity values. In the previous example, an element with `ele.data("weight") === -1` would be mapped to blue.
* **`function( ele ){ ... }`** A function may be passed as the value of a style property. The function has a single `ele` argument which specifies the element for which the style property value is being calculated.
* **`function( ele ){ ... }`** A function may be passed as the value of a style property. The function has a single `ele` argument which specifies the element for which the style property value is being calculated.
* **Do** specify a valid value for the corresponding style property for all elements that its corresponding selector block applies.
* **Do not** create cyclic dependencies (i.e. one style property reads the value of another style property).
* **Do** use pure functions that depend on only
Expand Down Expand Up @@ -242,7 +242,7 @@ Compound parent sizing:

A background image may be applied to a node's body. The following properties support multiple values (space separated or array) with associated indices.

* **`background-image`** : The URL that points to the image that should be used as the node's background. PNG, JPG, and SVG are supported formats.
* **`background-image`** : The URL that points to the image that should be used as the node's background. PNG, JPG, and SVG are supported formats.
* You may use a [data URI](https://en.wikipedia.org/wiki/Data_URI_scheme) to use embedded images, thereby saving a HTTP request.
* Can specify multiple background images by separating each image with a space (space delimited format), but if using a non-string stylesheet, then using arrays are preferred.
* The images will be applied to the node's body in the order given, layering one on top of each other.
Expand Down Expand Up @@ -402,9 +402,11 @@ Only mid arrows are supported on haystack edges.
- A special, named value may be used.
- `outside-to-node` (default) indicates that the edge should be placed automatically to point towards the node's position and be placed on the outside of the node's shape.
- `outside-to-node-or-label` uses the same rules as `outside-to-node` with the added rule that if the node's label would intersect the edge before the node's body, then the edge points to that intersection point. This avoids overlap of edges with node labels.
- `inside-to-node` indicates the edge should go all the way inside the node and point directly on the node's position. This is the same as specifying `0 0`.
- `outside-to-line` indicates the edge endpoint should be placed outside the node's shape where it would intersect the imaginary line from the source position to the target position. This value is useful for automatically avoiding invalid cases for bezier edges, especially with compound nodes.
- Two numbers may specify the endpoint. The numbers indicate a position relative to the source node's position. The numbers can be specified as percent values (e.g. `50%`, which are relative to the node's width and height respectively) or as absolute distances (e.g. `100px` or `2em`).
- `outside-to-line-or-label` uses the same rules as `outside-to-line` with the added rule that if the node's label would intersect the imaginary line before the node's body, then the edge points to that intersection point. This avoids overlap of edges with node labels.
- Two numbers may specify the endpoint. The numbers indicate a position relative to the source node's position. The numbers can be specified as percent values (e.g. `50%`, which are relative to the node's width and height respectively) or as absolute distances (e.g. `100px` or `2em`).
- A single angle value (e.g. `90deg` or `1.57rad`) may specify that the endpoint should be placed at where the line formed from the node's position with the specified angle would intersect the node's shape. The angle starts at 12 o'clock and progresses clockwise.
The endpoints for edges can be shifted away from the source and target node:
Expand Down Expand Up @@ -563,19 +565,19 @@ The ghost properties allow for creating a ghosting effect, a semitransparent dup
* `ease-in-out-sine`,
* `ease-in-quad`,
* `ease-out-quad`,
* `ease-in-out-quad`,
* `ease-in-out-quad`,
* `ease-in-cubic`,
* `ease-out-cubic`,
* `ease-in-out-cubic`,
* `ease-in-out-cubic`,
* `ease-in-quart`,
* `ease-out-quart`,
* `ease-in-out-quart`,
* `ease-in-out-quart`,
* `ease-in-quint`,
* `ease-out-quint`,
* `ease-in-out-quint`,
* `ease-in-expo`,
* `ease-out-expo`,
* `ease-in-out-expo`,
* `ease-in-out-expo`,
* `ease-in-circ`,
* `ease-out-circ`,
* `ease-in-out-circ`.
Expand Down
88 changes: 84 additions & 4 deletions src/extensions/renderer/base/coord-ele-math/edge-endpoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ BRp.findEndpoints = function( edge ){
} else if( tgtManEndptVal === 'outside-to-line' ){
intersect = rs.tgtIntn; // use cached value from ctrlpt calc
} else {
if( tgtManEndptVal === 'outside-to-node' ){
if( tgtManEndptVal === 'outside-to-node' || tgtManEndptVal === 'outside-to-node-or-label' ){
p1_i = p1;
} else if( tgtManEndptVal === 'outside-to-line' ){
} else if( tgtManEndptVal === 'outside-to-line' || tgtManEndptVal === 'outside-to-line-or-label' ){
p1_i = [ srcPos.x, srcPos.y ];
}

Expand All @@ -123,6 +123,46 @@ BRp.findEndpoints = function( edge ){
p1_i[1],
0
);

if( tgtManEndptVal === 'outside-to-node-or-label' || tgtManEndptVal === 'outside-to-line-or-label' ){
let trs = target._private.rscratch;
let lw = trs.labelWidth;
let lh = trs.labelHeight;
let lx = trs.labelX;
let ly = trs.labelY;

let va = target.pstyle('text-valign').value;
if( va === 'top' ){
ly -= lh/2;
} else if( va === 'bottom' ){
ly += lh/2;
}

let ha = target.pstyle('text-halign').value;
if( ha === 'left' ){
lx -= lw/2;
} else if( ha === 'right' ){
lx += lw/2;
}

let labelIntersect = r.nodeShapes['rectangle'].intersectLine(
lx,
ly,
lw,
lh,
p1_i[0],
p1_i[1],
0
);

let refPt = srcPos;
let intSqdist = math.sqdist( refPt, math.array2point(intersect) );
let labIntSqdist = math.sqdist( refPt, math.array2point(labelIntersect) );

if( labIntSqdist < intSqdist ){
intersect = labelIntersect;
}
}
}

let arrowEnd = math.shortenIntersection(
Expand All @@ -149,9 +189,9 @@ BRp.findEndpoints = function( edge ){
} else if( srcManEndptVal === 'outside-to-line' ){
intersect = rs.srcIntn; // use cached value from ctrlpt calc
} else {
if( srcManEndptVal === 'outside-to-node' ){
if( srcManEndptVal === 'outside-to-node' || srcManEndptVal === 'outside-to-node-or-label' ){
p2_i = p2;
} else if( srcManEndptVal === 'outside-to-line' ){
} else if( srcManEndptVal === 'outside-to-line' || srcManEndptVal === 'outside-to-line-or-label' ){
p2_i = [ tgtPos.x, tgtPos.y ];
}

Expand All @@ -164,6 +204,46 @@ BRp.findEndpoints = function( edge ){
p2_i[1],
0
);

if( srcManEndptVal === 'outside-to-node-or-label' || srcManEndptVal === 'outside-to-line-or-label' ){
let srs = source._private.rscratch;
let lw = srs.labelWidth;
let lh = srs.labelHeight;
let lx = srs.labelX;
let ly = srs.labelY;

let va = source.pstyle('text-valign').value;
if( va === 'top' ){
ly -= lh/2;
} else if( va === 'bottom' ){
ly += lh/2;
}

let ha = source.pstyle('text-halign').value;
if( ha === 'left' ){
lx -= lw/2;
} else if( ha === 'right' ){
lx += lw/2;
}

let labelIntersect = r.nodeShapes['rectangle'].intersectLine(
lx,
ly,
lw,
lh,
p2_i[0],
p2_i[1],
0
);

let refPt = tgtPos;
let intSqdist = math.sqdist( refPt, math.array2point(intersect) );
let labIntSqdist = math.sqdist( refPt, math.array2point(labelIntersect) );

if( labIntSqdist < intSqdist ){
intersect = labelIntersect;
}
}
}

let arrowStart = math.shortenIntersection(
Expand Down
2 changes: 1 addition & 1 deletion src/style/properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ const styfn = {};
edgeDistances: { enums: ['intersection', 'node-position'] },
edgeEndpoint: {
number: true, multiple: true, units: '%|px|em|deg|rad', implicitUnits: 'px',
enums: [ 'inside-to-node', 'outside-to-node', 'outside-to-line' ], singleEnum: true,
enums: [ 'inside-to-node', 'outside-to-node', 'outside-to-node-or-label', 'outside-to-line', 'outside-to-line-or-label' ], singleEnum: true,
validate: function( valArr, unitsArr ){
switch( valArr.length ){
case 2: // can be % or px only
Expand Down

0 comments on commit 0f64d67

Please sign in to comment.