• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

graphty-org / graphty-element / 16214082367

11 Jul 2025 07:07AM UTC coverage: 68.182% (+1.1%) from 67.128%
16214082367

push

github

apowers313
refactor: extract mesh creation logic into NodeMesh and EdgeMesh classes

546 of 780 branches covered (70.0%)

Branch coverage included in aggregate %.

333 of 334 new or added lines in 3 files covered. (99.7%)

80 existing lines in 5 files now uncovered.

3954 of 5820 relevant lines covered (67.94%)

994.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

32.02
/src/camera/TwoDInputController.ts
1
// TwoDInputController.ts
2
import {PointerEventTypes} from "@babylonjs/core";
1✔
3
import Hammer from "hammerjs";
1!
4

5
import {TwoDCameraController, TwoDCameraControlsConfigType} from "./TwoDCameraController";
6

7
interface GestureSession {
8
    panX: number;
9
    panY: number;
10
    panStartX: number;
11
    panStartY: number;
12
    ortho: {
13
        left: number;
14
        right: number;
15
        top: number;
16
        bottom: number;
17
    };
18
    scale: number;
19
    rotation: number;
20
    startRotDeg: number;
21
}
22

23
export class InputController {
1✔
24
    private keyState: Record<string, boolean> = {};
1✔
25
    private gestureSession: GestureSession | null = null;
1✔
26
    private hammer: HammerManager | null = null;
1✔
27
    private enabled = false;
1✔
28

29
    private pointerDownHandler = (): void => {
1✔
30
        this.cam.canvas.focus();
×
31
    };
×
32

33
    private keyDownHandler = (e: KeyboardEvent): void => {
1✔
34
        this.keyState[e.key] = true;
×
35
    };
×
36

37
    private keyUpHandler = (e: KeyboardEvent): void => {
1✔
38
        this.keyState[e.key] = false;
×
39
    };
×
40

41
    constructor(
1✔
42
        private cam: TwoDCameraController,
61✔
43
        private canvas: HTMLCanvasElement,
61✔
44
        private config: TwoDCameraControlsConfigType,
61✔
45
    ) {
61✔
46
        this.canvas.setAttribute("tabindex", "0"); // Make focusable
61✔
47
        this.setupMouse();
61✔
48
        this.setupTouch();
61✔
49
    }
61✔
50

51
    private setupMouse(): void {
1✔
52
        let isPanning = false;
61✔
53
        let lastX = 0;
61✔
54
        let lastY = 0;
61✔
55

56
        this.cam.scene.onPointerObservable.add((pi) => {
61✔
57
            const e = pi.event as PointerEvent;
×
58

59
            switch (pi.type) {
×
60
                case PointerEventTypes.POINTERDOWN:
×
61
                    isPanning = true;
×
62
                    lastX = e.clientX;
×
63
                    lastY = e.clientY;
×
64
                    this.pointerDownHandler();
×
65
                    break;
×
66

67
                case PointerEventTypes.POINTERUP:
×
68
                    isPanning = false;
×
69
                    break;
×
70

71
                case PointerEventTypes.POINTERMOVE:
×
72
                    if (isPanning && e.buttons === 1) {
×
73
                        const orthoRight = this.cam.camera.orthoRight ?? 1;
×
74
                        const orthoLeft = this.cam.camera.orthoLeft ?? 1;
×
75
                        const orthoTop = this.cam.camera.orthoTop ?? 1;
×
76
                        const orthoBottom = this.cam.camera.orthoBottom ?? 1;
×
77
                        const scaleX = (orthoRight - orthoLeft) / this.cam.engine.getRenderWidth();
×
78
                        const scaleY = (orthoTop - orthoBottom) / this.cam.engine.getRenderHeight();
×
79

80
                        const dx = e.clientX - lastX;
×
81
                        const dy = e.clientY - lastY;
×
82

83
                        this.cam.pan(-dx * scaleX * this.config.mousePanScale, dy * scaleY * this.config.mousePanScale);
×
84

85
                        lastX = e.clientX;
×
86
                        lastY = e.clientY;
×
87
                    }
×
88

89
                    break;
×
90

91
                default:
×
92
                    break;
×
93
            }
×
94
        });
61✔
95

96
        this.cam.scene.onPrePointerObservable.add((pi) => {
61✔
97
            const e = pi.event as WheelEvent;
×
98
            if (pi.type === PointerEventTypes.POINTERWHEEL) {
×
99
                const delta = e.deltaY > 0 ? this.config.mouseWheelZoomSpeed : 1 / this.config.mouseWheelZoomSpeed;
×
100
                this.cam.zoom(delta);
×
101
                e.preventDefault();
×
102
            }
×
103
        }, PointerEventTypes.POINTERWHEEL);
61✔
104
    }
61✔
105

106
    private setupTouch(): void {
1✔
107
        this.hammer = new Hammer.Manager(this.canvas);
61✔
108
        const pan = new Hammer.Pan({threshold: 0, pointers: 0});
61✔
109
        const pinch = new Hammer.Pinch();
61✔
110
        const rotate = new Hammer.Rotate();
61✔
111

112
        this.hammer.add([pan, pinch, rotate]);
61✔
113
        this.hammer.get("pinch").recognizeWith(this.hammer.get("rotate"));
61✔
114
        this.hammer.get("pan").requireFailure(this.hammer.get("pinch"));
61✔
115

116
        this.hammer.on("panstart pinchstart rotatestart", (ev) => {
61✔
117
            this.gestureSession = {
×
118
                panX: ev.center.x,
×
119
                panY: ev.center.y,
×
120
                panStartX: this.cam.camera.position.x,
×
121
                panStartY: this.cam.camera.position.y,
×
122
                ortho: {
×
123
                    left: this.cam.camera.orthoLeft ?? 1,
×
124
                    right: this.cam.camera.orthoRight ?? 1,
×
125
                    top: this.cam.camera.orthoTop ?? 1,
×
126
                    bottom: this.cam.camera.orthoBottom ?? 1,
×
127
                },
×
128
                scale: ev.scale || 1,
×
129
                rotation: this.cam.parent.rotation.z,
×
130
                startRotDeg: ev.rotation || 0,
×
131
            };
×
132
        });
61✔
133

134
        this.hammer.on("panmove pinchmove rotatemove", (ev) => {
61✔
135
            if (!this.gestureSession) {
×
136
                return;
×
137
            }
×
138

139
            const orthoRight = this.cam.camera.orthoRight ?? 1;
×
140
            const orthoLeft = this.cam.camera.orthoLeft ?? 1;
×
141
            const orthoTop = this.cam.camera.orthoTop ?? 1;
×
142
            const orthoBottom = this.cam.camera.orthoBottom ?? 1;
×
143
            const scaleX = (orthoRight - orthoLeft) / this.cam.engine.getRenderWidth();
×
144
            const scaleY = (orthoTop - orthoBottom) / this.cam.engine.getRenderHeight();
×
145

146
            const dx = ev.center.x - this.gestureSession.panX;
×
147
            const dy = ev.center.y - this.gestureSession.panY;
×
148

149
            this.cam.camera.position.x = this.gestureSession.panStartX - (dx * scaleX * this.config.touchPanScale);
×
150
            this.cam.camera.position.y = this.gestureSession.panStartY + (dy * scaleY * this.config.touchPanScale);
×
151

152
            const pinch = (ev.scale || 1) / this.gestureSession.scale;
×
153
            this.cam.camera.orthoLeft = this.gestureSession.ortho.left / pinch;
×
154
            this.cam.camera.orthoRight = this.gestureSession.ortho.right / pinch;
×
155
            this.cam.camera.orthoTop = this.gestureSession.ortho.top / pinch;
×
156
            this.cam.camera.orthoBottom = this.gestureSession.ortho.bottom / pinch;
×
157

158
            const rotRad = (-(ev.rotation - this.gestureSession.startRotDeg) * Math.PI) / 180;
×
159
            this.cam.parent.rotation.z = this.gestureSession.rotation + rotRad;
×
160
        });
61✔
161

162
        this.hammer.on("panend pinchend rotateend", () => {
61✔
163
            this.gestureSession = null;
×
164
        });
61✔
165
    }
61✔
166

167
    public enable(): void {
1✔
168
        if (this.enabled) {
1!
169
            return;
×
170
        }
×
171

172
        this.enabled = true;
1✔
173

174
        this.canvas.addEventListener("keydown", this.keyDownHandler);
1✔
175
        this.canvas.addEventListener("keyup", this.keyUpHandler);
1✔
176
    }
1✔
177

178
    public disable(): void {
1✔
179
        if (!this.enabled) {
×
180
            return;
×
181
        }
×
182

183
        this.enabled = false;
×
184

185
        this.canvas.removeEventListener("keydown", this.keyDownHandler);
×
186
        this.canvas.removeEventListener("keyup", this.keyUpHandler);
×
187
    }
×
188

189
    public applyKeyboardInertia(): void {
1✔
UNCOV
190
        if (!this.enabled) {
×
191
            return;
×
192
        }
×
193

UNCOV
194
        const v = this.cam.velocity;
×
UNCOV
195
        const c = this.config;
×
196

UNCOV
197
        if (this.keyState.w || this.keyState.ArrowUp) {
×
198
            v.y += c.panAcceleration;
×
199
        }
×
200

UNCOV
201
        if (this.keyState.s || this.keyState.ArrowDown) {
×
202
            v.y -= c.panAcceleration;
×
203
        }
×
204

UNCOV
205
        if (this.keyState.a || this.keyState.ArrowLeft) {
×
206
            v.x -= c.panAcceleration;
×
207
        }
×
208

UNCOV
209
        if (this.keyState.d || this.keyState.ArrowRight) {
×
210
            v.x += c.panAcceleration;
×
211
        }
×
212

UNCOV
213
        if (this.keyState["+"] || this.keyState["="]) {
×
214
            v.zoom -= c.zoomFactorPerFrame;
×
215
        }
×
216

UNCOV
217
        if (this.keyState["-"] || this.keyState._) {
×
218
            v.zoom += c.zoomFactorPerFrame;
×
219
        }
×
220

UNCOV
221
        if (this.keyState.q) {
×
222
            v.rotate += c.rotateSpeedPerFrame;
×
223
        }
×
224

UNCOV
225
        if (this.keyState.e) {
×
226
            v.rotate -= c.rotateSpeedPerFrame;
×
227
        }
×
UNCOV
228
    }
×
229

230
    public update(): void {
1✔
UNCOV
231
        this.applyKeyboardInertia();
×
UNCOV
232
        this.cam.applyInertia();
×
UNCOV
233
    }
×
234
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc