|
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