• 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

99.39
/src/EdgeMesh.ts
1
import {
1✔
2
    AbstractMesh,
3
    Color3,
4
    Engine,
5
    GreasedLineBaseMesh,
6
    GreasedLineMeshColorMode,
7
    GreasedLineMeshWidthDistribution,
8
    GreasedLineTools,
9
    RawTexture,
10
    type Scene,
11
    StandardMaterial,
12
    Vector3,
13
} from "@babylonjs/core";
14
import {CreateGreasedLine} from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";
1✔
15

16
import type {EdgeStyleConfig} from "./config";
17
import {EDGE_CONSTANTS} from "./constants/meshConstants";
1✔
18
import type {MeshCache} from "./MeshCache";
19

20
export interface EdgeMeshOptions {
21
    styleId: string;
22
    width: number;
23
    color: string;
24
}
25

26
export interface ArrowHeadOptions {
27
    type?: string;
28
    width: number;
29
    color: string;
30
}
31

32
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
33
export class EdgeMesh {
1✔
34
    private static readonly UNIT_VECTOR_POINTS = [0, 0, -0.5, 0, 0, 0.5];
1✔
35

36
    static create(
1✔
37
        cache: MeshCache,
14✔
38
        options: EdgeMeshOptions,
14✔
39
        style: EdgeStyleConfig,
14✔
40
        scene: Scene,
14✔
41
    ): AbstractMesh {
14✔
42
        const cacheKey = `edge-style-${options.styleId}`;
14✔
43

44
        return cache.get(cacheKey, () => {
14✔
45
            if (style.line?.animationSpeed) {
13✔
46
                return this.createAnimatedLine(options, style, scene);
4✔
47
            }
4✔
48

49
            return this.createStaticLine(options);
9✔
50
        });
14✔
51
    }
14✔
52

53
    static createArrowHead(
1✔
54
        cache: MeshCache,
7✔
55
        styleId: string,
7✔
56
        options: ArrowHeadOptions,
7✔
57
    ): AbstractMesh | null {
7✔
58
        if (!options.type || options.type === "none") {
7✔
59
            return null;
2✔
60
        }
2✔
61

62
        const cacheKey = `edge-arrowhead-style-${styleId}`;
5✔
63

64
        return cache.get(cacheKey, () => {
5✔
65
            const width = this.calculateArrowWidth(options.width);
4✔
66
            const length = this.calculateArrowLength(options.width);
4✔
67

68
            const cap = GreasedLineTools.GetArrowCap(
4✔
69
                new Vector3(0, 0, -length),
4✔
70
                new Vector3(0, 0, 1),
4✔
71
                length,
4✔
72
                width,
4✔
73
                width,
4✔
74
            );
4✔
75

76
            return CreateGreasedLine(
4✔
77
                "lines",
4✔
78
                {
4✔
79
                    points: cap.points,
4✔
80
                    widths: cap.widths,
4✔
81
                    widthDistribution: GreasedLineMeshWidthDistribution.WIDTH_DISTRIBUTION_START,
4✔
82
                },
4✔
83
                {
4✔
84
                    color: Color3.FromHexString(options.color),
4✔
85
                },
4✔
86
            );
4✔
87
        });
5✔
88
    }
7✔
89

90
    private static createStaticLine(options: EdgeMeshOptions): GreasedLineBaseMesh {
1✔
91
        return CreateGreasedLine(
9✔
92
            "edge-plain",
9✔
93
            {
9✔
94
                points: this.UNIT_VECTOR_POINTS,
9✔
95
            },
9✔
96
            {
9✔
97
                color: Color3.FromHexString(options.color),
9✔
98
                width: options.width,
9✔
99
            },
9✔
100
        );
9✔
101
    }
9✔
102

103
    private static createAnimatedLine(
1✔
104
        options: EdgeMeshOptions,
4✔
105
        style: EdgeStyleConfig,
4✔
106
        scene: Scene,
4✔
107
    ): GreasedLineBaseMesh {
4✔
108
        const baseColor = Color3.FromHexString(EDGE_CONSTANTS.MOVING_LINE_BASE_COLOR);
4✔
109
        const movingColor = Color3.FromHexString(options.color);
4✔
110

111
        const texture = this.createAnimatedTexture(baseColor, movingColor, scene);
4✔
112

113
        const mesh = CreateGreasedLine(
4✔
114
            "edge-moving",
4✔
115
            {
4✔
116
                points: this.UNIT_VECTOR_POINTS,
4✔
117
            },
4✔
118
            {
4✔
119
                width: options.width,
4✔
120
                colorMode: GreasedLineMeshColorMode.COLOR_MODE_MULTIPLY,
4✔
121
            },
4✔
122
        );
4✔
123

124
        this.applyAnimatedTexture(mesh, texture, scene, style.line?.animationSpeed);
4✔
125

126
        return mesh;
4✔
127
    }
4✔
128

129
    private static createAnimatedTexture(
1✔
130
        baseColor: Color3,
4✔
131
        movingColor: Color3,
4✔
132
        scene: Scene,
4✔
133
    ): RawTexture {
4✔
134
        const r1 = Math.floor(baseColor.r * 255);
4✔
135
        const g1 = Math.floor(baseColor.g * 255);
4✔
136
        const b1 = Math.floor(baseColor.b * 255);
4✔
137
        const r2 = Math.floor(movingColor.r * 255);
4✔
138
        const g2 = Math.floor(movingColor.g * 255);
4✔
139
        const b2 = Math.floor(movingColor.b * 255);
4✔
140

141
        const textureData = new Uint8Array([r1, g1, b1, r2, g2, b2]);
4✔
142

143
        const texture = new RawTexture(
4✔
144
            textureData,
4✔
145
            textureData.length / 3,
4✔
146
            1,
4✔
147
            Engine.TEXTUREFORMAT_RGB,
4✔
148
            scene,
4✔
149
            false,
4✔
150
            true,
4✔
151
            Engine.TEXTURE_NEAREST_NEAREST,
4✔
152
        );
4✔
153

154
        texture.wrapU = RawTexture.WRAP_ADDRESSMODE;
4✔
155
        texture.name = "moving-texture";
4✔
156

157
        return texture;
4✔
158
    }
4✔
159

160
    private static applyAnimatedTexture(
1✔
161
        mesh: GreasedLineBaseMesh,
4✔
162
        texture: RawTexture,
4✔
163
        scene: Scene,
4✔
164
        // eslint-disable-next-line @typescript-eslint/no-unused-vars
165
        _animationSpeed?: number,
4✔
166
    ): void {
4✔
167
        const material = mesh.material as StandardMaterial;
4✔
168
        material.emissiveTexture = texture;
4✔
169
        material.disableLighting = true;
4✔
170
        texture.uScale = EDGE_CONSTANTS.MOVING_TEXTURE_U_SCALE;
4✔
171

172
        scene.onBeforeRenderObservable.add(() => {
4✔
NEW
173
            texture.uOffset -= EDGE_CONSTANTS.MOVING_TEXTURE_ANIMATION_SPEED * scene.getAnimationRatio();
×
174
        });
4✔
175
    }
4✔
176

177
    static calculateArrowWidth(lineWidth: number): number {
1✔
178
        return Math.max(EDGE_CONSTANTS.ARROW_CAP_WIDTH_MULTIPLIER * lineWidth, EDGE_CONSTANTS.ARROW_CAP_WIDTH_MINIMUM);
7✔
179
    }
7✔
180

181
    static calculateArrowLength(lineWidth: number): number {
1✔
182
        return Math.max(lineWidth, EDGE_CONSTANTS.ARROW_CAP_LENGTH_MINIMUM);
8✔
183
    }
8✔
184

185
    static transformMesh(
1✔
186
        mesh: AbstractMesh,
2✔
187
        srcPoint: Vector3,
2✔
188
        dstPoint: Vector3,
2✔
189
    ): void {
2✔
190
        const delta = dstPoint.subtract(srcPoint);
2✔
191
        const midPoint = new Vector3(
2✔
192
            srcPoint.x + (delta.x / 2),
2✔
193
            srcPoint.y + (delta.y / 2),
2✔
194
            srcPoint.z + (delta.z / 2),
2✔
195
        );
2✔
196
        const length = delta.length();
2✔
197

198
        mesh.position = midPoint;
2✔
199
        mesh.lookAt(dstPoint);
2✔
200
        mesh.scaling.z = length;
2✔
201
    }
2✔
202
}
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

© 2026 Coveralls, Inc