|
1 | 1 | import { Dom } from '../../core/dom'; |
2 | 2 | import { Vector } from '../../core/vector'; |
3 | 3 |
|
| 4 | +const EPS = 0.5; // Epsilon, a tiny offset to avoid rendering issues |
| 5 | + |
4 | 6 | export class JoinView { |
5 | 7 | public static createStraightJoin(parent: SVGElement, start: Vector, height: number) { |
| 8 | + const dy = Math.sign(height); |
6 | 9 | const join = Dom.svg('line', { |
7 | 10 | class: 'sqd-join', |
8 | 11 | x1: start.x, |
9 | | - y1: start.y, |
| 12 | + y1: start.y - EPS * dy, |
10 | 13 | x2: start.x, |
11 | | - y2: start.y + height |
| 14 | + y2: start.y + height + EPS * dy |
12 | 15 | }); |
13 | 16 | parent.insertBefore(join, parent.firstChild); |
14 | 17 | } |
15 | 18 |
|
16 | 19 | public static createJoins(parent: SVGElement, start: Vector, targets: Vector[]) { |
17 | 20 | const firstTarget = targets[0]; |
18 | 21 | const h = Math.abs(firstTarget.y - start.y) / 2; // half height |
19 | | - const y = Math.sign(firstTarget.y - start.y); // y direction |
| 22 | + const dy = Math.sign(firstTarget.y - start.y); // direction y |
20 | 23 |
|
21 | 24 | switch (targets.length) { |
22 | 25 | case 1: |
23 | 26 | if (start.x === targets[0].x) { |
24 | | - JoinView.createStraightJoin(parent, start, firstTarget.y * y); |
| 27 | + JoinView.createStraightJoin(parent, start, firstTarget.y * dy); |
25 | 28 | } else { |
26 | | - appendCurvedJoins(parent, start, targets, h, y); |
| 29 | + appendCurvedJoins(parent, start, targets, h, dy); |
27 | 30 | } |
28 | 31 | break; |
29 | 32 |
|
30 | 33 | case 2: |
31 | | - appendCurvedJoins(parent, start, targets, h, y); |
| 34 | + appendCurvedJoins(parent, start, targets, h, dy); |
32 | 35 | break; |
33 | 36 |
|
34 | 37 | default: |
35 | 38 | { |
36 | 39 | const f = targets[0]; // first |
37 | 40 | const l = targets[targets.length - 1]; // last |
| 41 | + const eps = EPS * dy; |
38 | 42 | appendJoin( |
39 | 43 | parent, |
40 | | - `M ${f.x} ${f.y} q ${h * 0.3} ${h * -y * 0.8} ${h} ${h * -y} ` + |
41 | | - `l ${l.x - f.x - h * 2} 0 q ${h * 0.8} ${-h * -y * 0.3} ${h} ${-h * -y}` |
| 44 | + `M ${f.x} ${f.y + eps} l 0 ${-eps} q ${h * 0.3} ${h * -dy * 0.8} ${h} ${h * -dy} ` + |
| 45 | + `l ${l.x - f.x - h * 2} 0 q ${h * 0.8} ${-h * -dy * 0.3} ${h} ${-h * -dy} l 0 ${eps}` |
42 | 46 | ); |
43 | 47 |
|
44 | 48 | for (let i = 1; i < targets.length - 1; i++) { |
45 | | - JoinView.createStraightJoin(parent, targets[i], h * -y); |
| 49 | + JoinView.createStraightJoin(parent, targets[i], h * -dy); |
46 | 50 | } |
47 | | - JoinView.createStraightJoin(parent, start, h * y); |
| 51 | + JoinView.createStraightJoin(parent, start, h * dy); |
48 | 52 | } |
49 | 53 | break; |
50 | 54 | } |
51 | 55 | } |
52 | 56 | } |
53 | 57 |
|
54 | | -function appendCurvedJoins(parent: SVGElement, start: Vector, targets: Vector[], h: number, y: number) { |
| 58 | +function appendCurvedJoins(parent: SVGElement, start: Vector, targets: Vector[], h: number, dy: number) { |
| 59 | + const eps = EPS * dy; |
55 | 60 | for (const target of targets) { |
56 | | - const l = Math.abs(target.x - start.x) - h * 2; // line size |
57 | | - const x = Math.sign(target.x - start.x); // x direction |
58 | | - |
| 61 | + const l = Math.abs(target.x - start.x) - h * 2; // straight line length |
| 62 | + const dx = Math.sign(target.x - start.x); // direction x |
59 | 63 | appendJoin( |
60 | 64 | parent, |
61 | | - `M ${start.x} ${start.y} q ${x * h * 0.3} ${y * h * 0.8} ${x * h} ${y * h} ` + |
62 | | - `l ${x * l} 0 q ${x * h * 0.7} ${y * h * 0.2} ${x * h} ${y * h}` |
| 65 | + `M ${start.x} ${start.y - eps} l 0 ${eps} q ${dx * h * 0.3} ${dy * h * 0.8} ${dx * h} ${dy * h} ` + |
| 66 | + `l ${dx * l} 0 q ${dx * h * 0.7} ${dy * h * 0.2} ${dx * h} ${dy * h} l 0 ${eps}` |
63 | 67 | ); |
64 | 68 | } |
65 | 69 | } |
|
0 commit comments