@fusion.dev/helix-graph 0.202.0 → 0.204.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/connect-graph/looks.d.ts +1 -1
- package/dist/overlay/overlay.js +2 -2
- package/dist/sigma/edge-program.d.ts +87 -0
- package/dist/sigma/edge-program.js +316 -0
- package/dist/sigma/index.d.ts +1 -0
- package/dist/sigma/index.js +1 -0
- package/dist/sigma/node-program.d.ts +1 -0
- package/dist/sigma/node-program.js +19 -4
- package/dist/sigma/sigma-driver.d.ts +4 -3
- package/dist/sigma/sigma-driver.js +12 -2
- package/dist/snapshot/snapshot.js +2 -2
- package/package.json +4 -4
|
@@ -66,7 +66,7 @@ export interface NodeLook {
|
|
|
66
66
|
/** How strongly it glows, from 0 to 1: the selected note's halo. */
|
|
67
67
|
glow: number;
|
|
68
68
|
/** What it is drawn as made of, where the note says. */
|
|
69
|
-
material?: 'frosted' | 'glass' | undefined;
|
|
69
|
+
material?: 'frosted' | 'glass' | 'mark' | undefined;
|
|
70
70
|
/**
|
|
71
71
|
* The note the keys are on in the frame's list or search field, which a
|
|
72
72
|
* renderer marks as it marks the note under the pointer, so a reader moving
|
package/dist/overlay/overlay.js
CHANGED
|
@@ -90,7 +90,7 @@ export const ease = (at) => (at < 0.5 ? 2 * at * at : 1 - (-2 * at + 2) ** 2 / 2
|
|
|
90
90
|
const SAMPLED = 96;
|
|
91
91
|
const nameGroups = (context, groups, looks, at, avoid) => {
|
|
92
92
|
context.font = `650 11px ${looks.font}`;
|
|
93
|
-
context.letterSpacing = '0.
|
|
93
|
+
context.letterSpacing = '0.02em';
|
|
94
94
|
context.textAlign = 'center';
|
|
95
95
|
context.textBaseline = 'middle';
|
|
96
96
|
context.shadowColor = looks.ground;
|
|
@@ -121,7 +121,7 @@ const nameGroups = (context, groups, looks, at, avoid) => {
|
|
|
121
121
|
if (spread < 12) {
|
|
122
122
|
continue;
|
|
123
123
|
}
|
|
124
|
-
const name = group.name
|
|
124
|
+
const name = group.name;
|
|
125
125
|
const half = context.measureText(name).width / 2 + 4;
|
|
126
126
|
const boxAt = (middle) => ({
|
|
127
127
|
bottom: middle + 9,
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { EdgeProgram, type EdgeProgramType } from 'sigma/rendering';
|
|
2
|
+
import type { EdgeDisplayData, NodeDisplayData, RenderParams } from 'sigma/types';
|
|
3
|
+
/** What the edge program reads off a link, beyond what Sigma gives every link. */
|
|
4
|
+
export interface HelixEdgeData {
|
|
5
|
+
/** How strongly the link glows, from 0 to 1: a link on the selected note's path. */
|
|
6
|
+
glow?: number;
|
|
7
|
+
/** Whether the link is drawn heavy, with an arrowhead, as a link the selection lights is. */
|
|
8
|
+
strong?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare const UNIFORMS: readonly ['u_matrix', 'u_zoomRatio', 'u_sizeRatio', 'u_correctionRatio', 'u_pixelRatio', 'u_feather', 'u_minEdgeThickness'];
|
|
11
|
+
/**
|
|
12
|
+
* Draws a link as a line that reads in its direction, faint where it leaves
|
|
13
|
+
* a note and full where it arrives, with a glow where the selection lights
|
|
14
|
+
* it: one quad a link, as Sigma's own rectangle is, widened where it glows.
|
|
15
|
+
*/
|
|
16
|
+
export declare class HelixEdgeLineProgram extends EdgeProgram<(typeof UNIFORMS)[number]> {
|
|
17
|
+
getDefinition(): {
|
|
18
|
+
ATTRIBUTES: ({
|
|
19
|
+
name: string;
|
|
20
|
+
size: number;
|
|
21
|
+
type: 5126;
|
|
22
|
+
normalized?: never;
|
|
23
|
+
} | {
|
|
24
|
+
name: string;
|
|
25
|
+
normalized: boolean;
|
|
26
|
+
size: number;
|
|
27
|
+
type: 5121;
|
|
28
|
+
})[];
|
|
29
|
+
CONSTANT_ATTRIBUTES: {
|
|
30
|
+
name: string;
|
|
31
|
+
size: number;
|
|
32
|
+
type: 5126;
|
|
33
|
+
}[];
|
|
34
|
+
CONSTANT_DATA: number[][];
|
|
35
|
+
FRAGMENT_SHADER_SOURCE: string;
|
|
36
|
+
METHOD: 4;
|
|
37
|
+
UNIFORMS: readonly ["u_matrix", "u_zoomRatio", "u_sizeRatio", "u_correctionRatio", "u_pixelRatio", "u_feather", "u_minEdgeThickness"];
|
|
38
|
+
VERTEX_SHADER_SOURCE: string;
|
|
39
|
+
VERTICES: number;
|
|
40
|
+
};
|
|
41
|
+
processVisibleItem(edgeIndex: number, startIndex: number, sourceData: NodeDisplayData, targetData: NodeDisplayData, data: EdgeDisplayData & HelixEdgeData): void;
|
|
42
|
+
setUniforms(params: RenderParams, { gl, uniformLocations, }: {
|
|
43
|
+
gl: WebGLRenderingContext;
|
|
44
|
+
uniformLocations: Record<string, WebGLUniformLocation>;
|
|
45
|
+
}): void;
|
|
46
|
+
}
|
|
47
|
+
declare const HEAD_UNIFORMS: readonly ['u_matrix', 'u_sizeRatio', 'u_correctionRatio', 'u_minEdgeThickness', 'u_lengthToThicknessRatio', 'u_widenessToThicknessRatio'];
|
|
48
|
+
/**
|
|
49
|
+
* An arrowhead on a strong link only, at the note it arrives at: Sigma's own
|
|
50
|
+
* head, one triangle a link, drawn transparent where the link is not strong.
|
|
51
|
+
* Every link already reads in its direction by its gradient, and a head on
|
|
52
|
+
* each of a graph's thousands of links is a field of chevrons.
|
|
53
|
+
*/
|
|
54
|
+
export declare class HelixArrowHeadProgram extends EdgeProgram<(typeof HEAD_UNIFORMS)[number]> {
|
|
55
|
+
getDefinition(): {
|
|
56
|
+
ATTRIBUTES: ({
|
|
57
|
+
normalized?: never;
|
|
58
|
+
name: string;
|
|
59
|
+
size: number;
|
|
60
|
+
type: 5126;
|
|
61
|
+
} | {
|
|
62
|
+
name: string;
|
|
63
|
+
normalized: boolean;
|
|
64
|
+
size: number;
|
|
65
|
+
type: 5121;
|
|
66
|
+
})[];
|
|
67
|
+
CONSTANT_ATTRIBUTES: {
|
|
68
|
+
name: string;
|
|
69
|
+
size: number;
|
|
70
|
+
type: 5126;
|
|
71
|
+
}[];
|
|
72
|
+
CONSTANT_DATA: number[][];
|
|
73
|
+
FRAGMENT_SHADER_SOURCE: string;
|
|
74
|
+
METHOD: 4;
|
|
75
|
+
UNIFORMS: readonly ["u_matrix", "u_sizeRatio", "u_correctionRatio", "u_minEdgeThickness", "u_lengthToThicknessRatio", "u_widenessToThicknessRatio"];
|
|
76
|
+
VERTEX_SHADER_SOURCE: string;
|
|
77
|
+
VERTICES: number;
|
|
78
|
+
};
|
|
79
|
+
processVisibleItem(edgeIndex: number, startIndex: number, sourceData: NodeDisplayData, targetData: NodeDisplayData, data: EdgeDisplayData & HelixEdgeData): void;
|
|
80
|
+
setUniforms(params: RenderParams, { gl, uniformLocations, }: {
|
|
81
|
+
gl: WebGLRenderingContext;
|
|
82
|
+
uniformLocations: Record<string, WebGLUniformLocation>;
|
|
83
|
+
}): void;
|
|
84
|
+
}
|
|
85
|
+
/** The line and its head, as one program a link is drawn with. */
|
|
86
|
+
export declare const HelixEdgeProgram: EdgeProgramType;
|
|
87
|
+
export {};
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { createEdgeCompoundProgram, EdgeProgram } from 'sigma/rendering';
|
|
2
|
+
import { floatColor } from 'sigma/utils';
|
|
3
|
+
const REACH = 4;
|
|
4
|
+
const NONE = 'rgba(0, 0, 0, 0)';
|
|
5
|
+
const VERTEX = `
|
|
6
|
+
attribute vec4 a_id;
|
|
7
|
+
attribute vec4 a_color;
|
|
8
|
+
attribute vec2 a_normal;
|
|
9
|
+
attribute float a_normalCoef;
|
|
10
|
+
attribute vec2 a_positionStart;
|
|
11
|
+
attribute vec2 a_positionEnd;
|
|
12
|
+
attribute float a_positionCoef;
|
|
13
|
+
attribute float a_glow;
|
|
14
|
+
|
|
15
|
+
uniform mat3 u_matrix;
|
|
16
|
+
uniform float u_sizeRatio;
|
|
17
|
+
uniform float u_zoomRatio;
|
|
18
|
+
uniform float u_pixelRatio;
|
|
19
|
+
uniform float u_correctionRatio;
|
|
20
|
+
uniform float u_minEdgeThickness;
|
|
21
|
+
uniform float u_feather;
|
|
22
|
+
|
|
23
|
+
varying vec4 v_color;
|
|
24
|
+
varying vec2 v_normal;
|
|
25
|
+
varying float v_thickness;
|
|
26
|
+
varying float v_feather;
|
|
27
|
+
varying float v_along;
|
|
28
|
+
varying float v_glow;
|
|
29
|
+
varying float v_spread;
|
|
30
|
+
|
|
31
|
+
const float bias = 255.0 / 254.0;
|
|
32
|
+
|
|
33
|
+
void main() {
|
|
34
|
+
float minThickness = u_minEdgeThickness;
|
|
35
|
+
|
|
36
|
+
vec2 normal = a_normal * a_normalCoef;
|
|
37
|
+
vec2 position = a_positionStart * (1.0 - a_positionCoef) + a_positionEnd * a_positionCoef;
|
|
38
|
+
|
|
39
|
+
float normalLength = length(normal);
|
|
40
|
+
vec2 unitNormal = normal / normalLength;
|
|
41
|
+
|
|
42
|
+
/* At least the minimum thickness on screen, in the WebGL referential, as
|
|
43
|
+
Sigma's own rectangle does it. */
|
|
44
|
+
float pixelsThickness = max(normalLength, minThickness * u_sizeRatio);
|
|
45
|
+
float webGLThickness = pixelsThickness * u_correctionRatio / u_sizeRatio;
|
|
46
|
+
|
|
47
|
+
/* The quad reaches past the line by the room its glow needs, and only
|
|
48
|
+
where it glows: a resting link's quad is the line's own width. */
|
|
49
|
+
float spread = 1.0 + a_glow * ${REACH.toFixed(1)};
|
|
50
|
+
gl_Position = vec4((u_matrix * vec3(position + unitNormal * webGLThickness * spread, 1)).xy, 0, 1);
|
|
51
|
+
|
|
52
|
+
v_thickness = webGLThickness / u_zoomRatio;
|
|
53
|
+
v_normal = unitNormal;
|
|
54
|
+
v_feather = u_feather * u_correctionRatio / u_zoomRatio / u_pixelRatio * 2.0;
|
|
55
|
+
v_along = a_positionCoef;
|
|
56
|
+
v_glow = a_glow;
|
|
57
|
+
v_spread = spread;
|
|
58
|
+
|
|
59
|
+
#ifdef PICKING_MODE
|
|
60
|
+
v_color = a_id;
|
|
61
|
+
#else
|
|
62
|
+
v_color = a_color;
|
|
63
|
+
#endif
|
|
64
|
+
|
|
65
|
+
v_color.a *= bias;
|
|
66
|
+
}
|
|
67
|
+
`;
|
|
68
|
+
const FRAGMENT = `
|
|
69
|
+
precision mediump float;
|
|
70
|
+
|
|
71
|
+
varying vec4 v_color;
|
|
72
|
+
varying vec2 v_normal;
|
|
73
|
+
varying float v_thickness;
|
|
74
|
+
varying float v_feather;
|
|
75
|
+
varying float v_along;
|
|
76
|
+
varying float v_glow;
|
|
77
|
+
varying float v_spread;
|
|
78
|
+
|
|
79
|
+
void main(void) {
|
|
80
|
+
#ifdef PICKING_MODE
|
|
81
|
+
gl_FragColor = v_color;
|
|
82
|
+
#else
|
|
83
|
+
/* Across the quad, from the line's middle out: the normal interpolates
|
|
84
|
+
through zero at the middle, so its length is the distance in half-widths
|
|
85
|
+
of the quad, and the quad is the line widened by its spread. */
|
|
86
|
+
float dist = length(v_normal) * v_spread * v_thickness;
|
|
87
|
+
float line = 1.0 - smoothstep(v_thickness - v_feather, v_thickness, dist);
|
|
88
|
+
|
|
89
|
+
/* The glow, outside the line: a soft light falling away from its edge, in
|
|
90
|
+
the link's own color, as a note's halo falls away from its rim. */
|
|
91
|
+
float past = max(dist - v_thickness, 0.0) / max(v_thickness * ${REACH.toFixed(1)}, 0.0001);
|
|
92
|
+
float halo = v_glow * (1.0 - line) * exp(-past * 3.2) * (1.0 - smoothstep(0.7, 1.0, past)) * 0.55;
|
|
93
|
+
|
|
94
|
+
/* Faint where the link leaves and full where it arrives, so the direction
|
|
95
|
+
reads along every link, and the one lit by the selection as a path. */
|
|
96
|
+
float along = mix(0.4, 1.0, smoothstep(0.0, 1.0, v_along));
|
|
97
|
+
|
|
98
|
+
float alpha = (line + halo) * along * v_color.a;
|
|
99
|
+
/* Premultiplied, as Sigma blends. */
|
|
100
|
+
gl_FragColor = vec4(v_color.rgb * alpha, alpha);
|
|
101
|
+
#endif
|
|
102
|
+
}
|
|
103
|
+
`;
|
|
104
|
+
const { FLOAT, UNSIGNED_BYTE } = WebGLRenderingContext;
|
|
105
|
+
const UNIFORMS = [
|
|
106
|
+
'u_matrix',
|
|
107
|
+
'u_zoomRatio',
|
|
108
|
+
'u_sizeRatio',
|
|
109
|
+
'u_correctionRatio',
|
|
110
|
+
'u_pixelRatio',
|
|
111
|
+
'u_feather',
|
|
112
|
+
'u_minEdgeThickness',
|
|
113
|
+
];
|
|
114
|
+
export class HelixEdgeLineProgram extends EdgeProgram {
|
|
115
|
+
getDefinition() {
|
|
116
|
+
return {
|
|
117
|
+
ATTRIBUTES: [
|
|
118
|
+
{ name: 'a_positionStart', size: 2, type: FLOAT },
|
|
119
|
+
{ name: 'a_positionEnd', size: 2, type: FLOAT },
|
|
120
|
+
{ name: 'a_normal', size: 2, type: FLOAT },
|
|
121
|
+
{ name: 'a_color', normalized: true, size: 4, type: UNSIGNED_BYTE },
|
|
122
|
+
{ name: 'a_id', normalized: true, size: 4, type: UNSIGNED_BYTE },
|
|
123
|
+
{ name: 'a_glow', size: 1, type: FLOAT },
|
|
124
|
+
],
|
|
125
|
+
CONSTANT_ATTRIBUTES: [
|
|
126
|
+
{ name: 'a_positionCoef', size: 1, type: FLOAT },
|
|
127
|
+
{ name: 'a_normalCoef', size: 1, type: FLOAT },
|
|
128
|
+
],
|
|
129
|
+
CONSTANT_DATA: [
|
|
130
|
+
[0, 1],
|
|
131
|
+
[0, -1],
|
|
132
|
+
[1, 1],
|
|
133
|
+
[1, 1],
|
|
134
|
+
[0, -1],
|
|
135
|
+
[1, -1],
|
|
136
|
+
],
|
|
137
|
+
FRAGMENT_SHADER_SOURCE: FRAGMENT,
|
|
138
|
+
METHOD: WebGLRenderingContext.TRIANGLES,
|
|
139
|
+
UNIFORMS,
|
|
140
|
+
VERTEX_SHADER_SOURCE: VERTEX,
|
|
141
|
+
VERTICES: 6,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
processVisibleItem(edgeIndex, startIndex, sourceData, targetData, data) {
|
|
145
|
+
const thickness = data.size || 1;
|
|
146
|
+
const dx = targetData.x - sourceData.x;
|
|
147
|
+
const dy = targetData.y - sourceData.y;
|
|
148
|
+
let len = dx * dx + dy * dy;
|
|
149
|
+
let n1 = 0;
|
|
150
|
+
let n2 = 0;
|
|
151
|
+
if (len) {
|
|
152
|
+
len = 1 / Math.sqrt(len);
|
|
153
|
+
n1 = -dy * len * thickness;
|
|
154
|
+
n2 = dx * len * thickness;
|
|
155
|
+
}
|
|
156
|
+
const array = this.array;
|
|
157
|
+
let at = startIndex;
|
|
158
|
+
array[at++] = sourceData.x;
|
|
159
|
+
array[at++] = sourceData.y;
|
|
160
|
+
array[at++] = targetData.x;
|
|
161
|
+
array[at++] = targetData.y;
|
|
162
|
+
array[at++] = n1;
|
|
163
|
+
array[at++] = n2;
|
|
164
|
+
array[at++] = floatColor(data.color);
|
|
165
|
+
array[at++] = edgeIndex;
|
|
166
|
+
array[at] = data.glow ?? 0;
|
|
167
|
+
}
|
|
168
|
+
setUniforms(params, { gl, uniformLocations, }) {
|
|
169
|
+
gl.uniformMatrix3fv(uniformLocations.u_matrix, false, params.matrix);
|
|
170
|
+
gl.uniform1f(uniformLocations.u_zoomRatio, params.zoomRatio);
|
|
171
|
+
gl.uniform1f(uniformLocations.u_sizeRatio, params.sizeRatio);
|
|
172
|
+
gl.uniform1f(uniformLocations.u_correctionRatio, params.correctionRatio);
|
|
173
|
+
gl.uniform1f(uniformLocations.u_pixelRatio, params.pixelRatio);
|
|
174
|
+
gl.uniform1f(uniformLocations.u_feather, params.antiAliasingFeather);
|
|
175
|
+
gl.uniform1f(uniformLocations.u_minEdgeThickness, params.minEdgeThickness);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const HEAD_VERTEX = `
|
|
179
|
+
attribute vec2 a_position;
|
|
180
|
+
attribute vec2 a_normal;
|
|
181
|
+
attribute float a_radius;
|
|
182
|
+
attribute vec3 a_barycentric;
|
|
183
|
+
attribute vec4 a_id;
|
|
184
|
+
attribute vec4 a_color;
|
|
185
|
+
|
|
186
|
+
uniform mat3 u_matrix;
|
|
187
|
+
uniform float u_sizeRatio;
|
|
188
|
+
uniform float u_correctionRatio;
|
|
189
|
+
uniform float u_minEdgeThickness;
|
|
190
|
+
uniform float u_lengthToThicknessRatio;
|
|
191
|
+
uniform float u_widenessToThicknessRatio;
|
|
192
|
+
|
|
193
|
+
varying vec4 v_color;
|
|
194
|
+
|
|
195
|
+
const float bias = 255.0 / 254.0;
|
|
196
|
+
|
|
197
|
+
void main() {
|
|
198
|
+
float minThickness = u_minEdgeThickness;
|
|
199
|
+
|
|
200
|
+
float normalLength = length(a_normal);
|
|
201
|
+
vec2 unitNormal = a_normal / normalLength;
|
|
202
|
+
|
|
203
|
+
/* As Sigma's own arrowhead: the thickness on screen, the note's radius,
|
|
204
|
+
and the head's length and width from the thickness. */
|
|
205
|
+
float pixelsThickness = max(normalLength / u_sizeRatio, minThickness);
|
|
206
|
+
float webGLThickness = pixelsThickness * u_correctionRatio;
|
|
207
|
+
float webGLNodeRadius = a_radius * 2.0 * u_correctionRatio / u_sizeRatio;
|
|
208
|
+
float webGLArrowHeadLength = webGLThickness * u_lengthToThicknessRatio * 2.0;
|
|
209
|
+
float webGLArrowHeadThickness = webGLThickness * u_widenessToThicknessRatio;
|
|
210
|
+
|
|
211
|
+
float da = a_barycentric.x;
|
|
212
|
+
float db = a_barycentric.y;
|
|
213
|
+
float dc = a_barycentric.z;
|
|
214
|
+
|
|
215
|
+
vec2 delta = vec2(
|
|
216
|
+
da * (webGLNodeRadius * unitNormal.y)
|
|
217
|
+
+ db * ((webGLNodeRadius + webGLArrowHeadLength) * unitNormal.y + webGLArrowHeadThickness * unitNormal.x)
|
|
218
|
+
+ dc * ((webGLNodeRadius + webGLArrowHeadLength) * unitNormal.y - webGLArrowHeadThickness * unitNormal.x),
|
|
219
|
+
|
|
220
|
+
da * (-webGLNodeRadius * unitNormal.x)
|
|
221
|
+
+ db * (-(webGLNodeRadius + webGLArrowHeadLength) * unitNormal.x + webGLArrowHeadThickness * unitNormal.y)
|
|
222
|
+
+ dc * (-(webGLNodeRadius + webGLArrowHeadLength) * unitNormal.x - webGLArrowHeadThickness * unitNormal.y)
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
gl_Position = vec4((u_matrix * vec3(a_position + delta, 1)).xy, 0, 1);
|
|
226
|
+
|
|
227
|
+
#ifdef PICKING_MODE
|
|
228
|
+
v_color = a_id;
|
|
229
|
+
#else
|
|
230
|
+
v_color = a_color;
|
|
231
|
+
#endif
|
|
232
|
+
|
|
233
|
+
v_color.a *= bias;
|
|
234
|
+
}
|
|
235
|
+
`;
|
|
236
|
+
const HEAD_FRAGMENT = `
|
|
237
|
+
precision mediump float;
|
|
238
|
+
|
|
239
|
+
varying vec4 v_color;
|
|
240
|
+
|
|
241
|
+
void main(void) {
|
|
242
|
+
#ifdef PICKING_MODE
|
|
243
|
+
gl_FragColor = v_color;
|
|
244
|
+
#else
|
|
245
|
+
/* Premultiplied, as Sigma blends. */
|
|
246
|
+
gl_FragColor = vec4(v_color.rgb * v_color.a, v_color.a);
|
|
247
|
+
#endif
|
|
248
|
+
}
|
|
249
|
+
`;
|
|
250
|
+
const HEAD_UNIFORMS = [
|
|
251
|
+
'u_matrix',
|
|
252
|
+
'u_sizeRatio',
|
|
253
|
+
'u_correctionRatio',
|
|
254
|
+
'u_minEdgeThickness',
|
|
255
|
+
'u_lengthToThicknessRatio',
|
|
256
|
+
'u_widenessToThicknessRatio',
|
|
257
|
+
];
|
|
258
|
+
const HEAD = { length: 2.5, wideness: 2 };
|
|
259
|
+
export class HelixArrowHeadProgram extends EdgeProgram {
|
|
260
|
+
getDefinition() {
|
|
261
|
+
return {
|
|
262
|
+
ATTRIBUTES: [
|
|
263
|
+
{ name: 'a_position', size: 2, type: FLOAT },
|
|
264
|
+
{ name: 'a_normal', size: 2, type: FLOAT },
|
|
265
|
+
{ name: 'a_radius', size: 1, type: FLOAT },
|
|
266
|
+
{ name: 'a_color', normalized: true, size: 4, type: UNSIGNED_BYTE },
|
|
267
|
+
{ name: 'a_id', normalized: true, size: 4, type: UNSIGNED_BYTE },
|
|
268
|
+
],
|
|
269
|
+
CONSTANT_ATTRIBUTES: [{ name: 'a_barycentric', size: 3, type: FLOAT }],
|
|
270
|
+
CONSTANT_DATA: [
|
|
271
|
+
[1, 0, 0],
|
|
272
|
+
[0, 1, 0],
|
|
273
|
+
[0, 0, 1],
|
|
274
|
+
],
|
|
275
|
+
FRAGMENT_SHADER_SOURCE: HEAD_FRAGMENT,
|
|
276
|
+
METHOD: WebGLRenderingContext.TRIANGLES,
|
|
277
|
+
UNIFORMS: HEAD_UNIFORMS,
|
|
278
|
+
VERTEX_SHADER_SOURCE: HEAD_VERTEX,
|
|
279
|
+
VERTICES: 3,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
processVisibleItem(edgeIndex, startIndex, sourceData, targetData, data) {
|
|
283
|
+
const thickness = data.size || 1;
|
|
284
|
+
const dx = targetData.x - sourceData.x;
|
|
285
|
+
const dy = targetData.y - sourceData.y;
|
|
286
|
+
let len = dx * dx + dy * dy;
|
|
287
|
+
let n1 = 0;
|
|
288
|
+
let n2 = 0;
|
|
289
|
+
if (len) {
|
|
290
|
+
len = 1 / Math.sqrt(len);
|
|
291
|
+
n1 = -dy * len * thickness;
|
|
292
|
+
n2 = dx * len * thickness;
|
|
293
|
+
}
|
|
294
|
+
const array = this.array;
|
|
295
|
+
let at = startIndex;
|
|
296
|
+
array[at++] = targetData.x;
|
|
297
|
+
array[at++] = targetData.y;
|
|
298
|
+
array[at++] = -n1;
|
|
299
|
+
array[at++] = -n2;
|
|
300
|
+
array[at++] = targetData.size || 1;
|
|
301
|
+
array[at++] = floatColor(data.strong ? data.color : NONE);
|
|
302
|
+
array[at] = edgeIndex;
|
|
303
|
+
}
|
|
304
|
+
setUniforms(params, { gl, uniformLocations, }) {
|
|
305
|
+
gl.uniformMatrix3fv(uniformLocations.u_matrix, false, params.matrix);
|
|
306
|
+
gl.uniform1f(uniformLocations.u_sizeRatio, params.sizeRatio);
|
|
307
|
+
gl.uniform1f(uniformLocations.u_correctionRatio, params.correctionRatio);
|
|
308
|
+
gl.uniform1f(uniformLocations.u_minEdgeThickness, params.minEdgeThickness);
|
|
309
|
+
gl.uniform1f(uniformLocations.u_lengthToThicknessRatio, HEAD.length);
|
|
310
|
+
gl.uniform1f(uniformLocations.u_widenessToThicknessRatio, HEAD.wideness);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
export const HelixEdgeProgram = createEdgeCompoundProgram([
|
|
314
|
+
HelixEdgeLineProgram,
|
|
315
|
+
HelixArrowHeadProgram,
|
|
316
|
+
]);
|
package/dist/sigma/index.d.ts
CHANGED
package/dist/sigma/index.js
CHANGED
|
@@ -2,8 +2,8 @@ import { NodeProgram } from 'sigma/rendering';
|
|
|
2
2
|
import { floatColor } from 'sigma/utils';
|
|
3
3
|
export const SHAPES = { circle: 0, diamond: 2, ring: 3, square: 1 };
|
|
4
4
|
export const EMPHASES = { outlined: 1, solid: 0, subtle: 2 };
|
|
5
|
-
export const MATERIALS = { flat: 0, frosted: 2, glass: 1 };
|
|
6
|
-
const REACH =
|
|
5
|
+
export const MATERIALS = { flat: 0, frosted: 2, glass: 1, mark: 3 };
|
|
6
|
+
const REACH = 3.4;
|
|
7
7
|
const VERTEX = `
|
|
8
8
|
attribute vec4 a_id;
|
|
9
9
|
attribute vec4 a_color;
|
|
@@ -104,6 +104,11 @@ void main(void) {
|
|
|
104
104
|
color = mix(color, vec3(1.0), highlight * mix(0.25, 0.6, drawn));
|
|
105
105
|
color = mix(color, vec3(1.0), rim * 0.22 * drawn);
|
|
106
106
|
alpha = 0.94;
|
|
107
|
+
} else if (v_material > 2.5) {
|
|
108
|
+
/* Mark: a flat dot of its color, as a marker on a table is. No fall of
|
|
109
|
+
light and no highlight; what says it is a mark is the ring and the glow
|
|
110
|
+
drawn around it below. */
|
|
111
|
+
alpha = 1.0;
|
|
107
112
|
} else if (v_material > 1.5) {
|
|
108
113
|
/* Frosted: a milky body, a soft fall of light, and no sharp highlight. */
|
|
109
114
|
color = mix(color * mix(0.86, 1.06, lit), vec3(1.0), 0.16);
|
|
@@ -123,8 +128,18 @@ void main(void) {
|
|
|
123
128
|
soft light falling away beyond it, both in the note's own color. */
|
|
124
129
|
float reach = ${(REACH - 1).toFixed(2)};
|
|
125
130
|
float ring = 1.0 - smoothstep(0.0, 0.07 + aa, abs(d - 0.32));
|
|
126
|
-
|
|
127
|
-
|
|
131
|
+
/* The light falls away more slowly and further than it did, so the
|
|
132
|
+
selected note sits in a bloom rather than wearing a ring: the halo the
|
|
133
|
+
aura gives the stars its pointer gathers. */
|
|
134
|
+
float falloff = exp(-d * 1.7) * (1.0 - smoothstep(reach * 0.8, reach, d));
|
|
135
|
+
float halo = v_glow * step(0.0, d) * clamp(ring * 0.8 + falloff * 0.85, 0.0, 1.0) * v_color.a;
|
|
136
|
+
/* A mark's own halo, selected or not: a band of its color at a fifth just
|
|
137
|
+
outside the dot, and a soft glow beyond, the way a marker on a table
|
|
138
|
+
carries a ring of its color and a light around it. */
|
|
139
|
+
float band = (1.0 - smoothstep(0.34, 0.42, d)) * 0.22;
|
|
140
|
+
float light = exp(-d * 2.0) * (1.0 - smoothstep(reach * 0.8, reach, d)) * 0.3;
|
|
141
|
+
float mark = v_material > 2.5 ? step(0.0, d) * (band + light) * v_color.a : 0.0;
|
|
142
|
+
halo = clamp(halo + mark, 0.0, 1.0);
|
|
128
143
|
/* Premultiplied, as Sigma blends: the body over its glow. */
|
|
129
144
|
gl_FragColor = vec4(color * body + v_color.rgb * halo * (1.0 - body), body + halo * (1.0 - body));
|
|
130
145
|
#endif
|
|
@@ -92,7 +92,7 @@ export interface SigmaRenderer<G extends SigmaGraph = SigmaGraph> {
|
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
94
|
/** The settings the driver sets, and puts back as they were when it stops. */
|
|
95
|
-
type SigmaSetting = 'defaultDrawNodeHover' | 'defaultDrawNodeLabel' | 'edgeReducer' | 'enableCameraPanning' | 'enableCameraZooming' | 'labelColor' | 'labelFont' | 'labelGridCellSize' | 'labelRenderedSizeThreshold' | 'labelSize' | 'minEdgeThickness' | 'nodeProgramClasses' | 'nodeReducer';
|
|
95
|
+
type SigmaSetting = 'defaultDrawNodeHover' | 'defaultDrawNodeLabel' | 'defaultEdgeType' | 'edgeProgramClasses' | 'edgeReducer' | 'enableCameraPanning' | 'enableCameraZooming' | 'labelColor' | 'labelFont' | 'labelGridCellSize' | 'labelRenderedSizeThreshold' | 'labelSize' | 'minEdgeThickness' | 'nodeProgramClasses' | 'nodeReducer';
|
|
96
96
|
/** A layout that runs over a graphology graph until it is stopped, as ForceAtlas2's worker does. */
|
|
97
97
|
export interface SigmaLayout {
|
|
98
98
|
kill(): void;
|
|
@@ -125,8 +125,9 @@ export interface SigmaDriverOptions<G extends SigmaGraph = SigmaGraph> {
|
|
|
125
125
|
emphasis?: NodeLook['emphasis'];
|
|
126
126
|
/**
|
|
127
127
|
* What a note is drawn as made of where it does not say: `flat` by default,
|
|
128
|
-
* `glass`, a shaded sphere with a highlight and a lit rim
|
|
129
|
-
* milky body with a soft fall of light
|
|
128
|
+
* `glass`, a shaded sphere with a highlight and a lit rim; `frosted`, a
|
|
129
|
+
* milky body with a soft fall of light; or `mark`, a flat dot of its color
|
|
130
|
+
* with a faint ring and a soft glow around it, as a marker on a table is.
|
|
130
131
|
*/
|
|
131
132
|
material?: NodeLook['material'] | 'flat';
|
|
132
133
|
/** A note's shape where it does not say: `circle` by default, `square`, `diamond` or `ring`. */
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { isRtl } from '@fusion.dev/helix-core';
|
|
2
2
|
import { pixelsOf } from '../connect-graph/sizes.js';
|
|
3
3
|
import { chromeOver, clearOf, ease, gesturesHeld, groupsOver, nameStart, signalsOver, } from '../overlay/overlay.js';
|
|
4
|
+
import { HelixEdgeProgram } from './edge-program.js';
|
|
4
5
|
import { EMPHASES, HelixNodeProgram, MATERIALS, SHAPES } from './node-program.js';
|
|
5
6
|
const SETTINGS = [
|
|
6
7
|
'defaultDrawNodeHover',
|
|
7
8
|
'defaultDrawNodeLabel',
|
|
9
|
+
'defaultEdgeType',
|
|
10
|
+
'edgeProgramClasses',
|
|
8
11
|
'edgeReducer',
|
|
9
12
|
'enableCameraPanning',
|
|
10
13
|
'enableCameraZooming',
|
|
@@ -88,6 +91,9 @@ export const sigmaDriver = (sigma, options = {}) => {
|
|
|
88
91
|
const before = new Map(SETTINGS.map((name) => [name, sigma.getSetting(name)]));
|
|
89
92
|
const programs = before.get('nodeProgramClasses');
|
|
90
93
|
sigma.setSetting('nodeProgramClasses', { ...programs, helix: HelixNodeProgram });
|
|
94
|
+
const edgePrograms = before.get('edgeProgramClasses');
|
|
95
|
+
sigma.setSetting('edgeProgramClasses', { ...edgePrograms, helix: HelixEdgeProgram });
|
|
96
|
+
sigma.setSetting('defaultEdgeType', 'helix');
|
|
91
97
|
const sized = typeof ResizeObserver === 'function'
|
|
92
98
|
? new ResizeObserver(() => {
|
|
93
99
|
sigma.resize(true);
|
|
@@ -276,12 +282,16 @@ export const sigmaDriver = (sigma, options = {}) => {
|
|
|
276
282
|
const look = looks.link(String(data.from), String(data.to));
|
|
277
283
|
const near = hovered ?? looks.keyed;
|
|
278
284
|
const lit = near !== undefined && (data.from === near || data.to === near);
|
|
285
|
+
const strong = look.raised || lit;
|
|
279
286
|
return {
|
|
280
287
|
...data,
|
|
281
288
|
color: lit ? looks.node(near).color : look.color,
|
|
289
|
+
glow: strong ? 1 : 0,
|
|
282
290
|
hidden: look.hidden,
|
|
283
|
-
size:
|
|
284
|
-
|
|
291
|
+
size: strong ? 1.3 : 0.8,
|
|
292
|
+
strong,
|
|
293
|
+
type: 'helix',
|
|
294
|
+
zIndex: strong ? 1 : 0,
|
|
285
295
|
};
|
|
286
296
|
});
|
|
287
297
|
sigma.refresh();
|
|
@@ -174,7 +174,7 @@ export const graphSnapshot = (nodes, links, options = {}) => {
|
|
|
174
174
|
if (points.length < 2 || spread < 12) {
|
|
175
175
|
continue;
|
|
176
176
|
}
|
|
177
|
-
const name = group
|
|
177
|
+
const name = group;
|
|
178
178
|
const half = (widthOf(name, 11) * 1.14) / 2 + 4;
|
|
179
179
|
const boxAt = (y) => ({
|
|
180
180
|
bottom: y + 9,
|
|
@@ -192,7 +192,7 @@ export const graphSnapshot = (nodes, links, options = {}) => {
|
|
|
192
192
|
const tinted = members.find((node) => node.tone === undefined) ?? members[0];
|
|
193
193
|
const color = mix(tinted ? own(tinted) : token('foreground-muted'), token('foreground'), 60);
|
|
194
194
|
const fade = selected !== undefined && ownGroup !== group ? 0.3 : 0.92;
|
|
195
|
-
regions.push(`<text dominant-baseline="middle" fill-opacity="${fade}" font-size="11" font-weight="650" letter-spacing="0.
|
|
195
|
+
regions.push(`<text dominant-baseline="middle" fill-opacity="${fade}" font-size="11" font-weight="650" letter-spacing="0.02em" style="fill:${color};stroke:${ground}" text-anchor="middle" x="${short(middle.x)}" y="${short(y)}">${escaped(name)}</text>`);
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
return (`<div aria-hidden="true" data-helix-graph-snapshot style="inset:0;overflow:hidden;pointer-events:none;position:absolute">` +
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusion.dev/helix-graph",
|
|
3
3
|
"description": "Connects the Helix Graph frame to a graph renderer: Sigma.js, cosmos.gl, three.js, or a driver of your own.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.204.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ross Sheppard <ross.sheppard@fusion.dev>",
|
|
7
7
|
"repository": {
|
|
@@ -59,12 +59,12 @@
|
|
|
59
59
|
},
|
|
60
60
|
"bugs": "https://github.com/project-fusion/fusion/issues",
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@fusion.dev/helix-core": "0.
|
|
62
|
+
"@fusion.dev/helix-core": "0.204.0"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@cosmos.gl/graph": "^3.4.2",
|
|
66
|
-
"@fusion.dev/helix-headless": "0.
|
|
67
|
-
"@fusion.dev/helix-testing": "0.
|
|
66
|
+
"@fusion.dev/helix-headless": "0.204.0",
|
|
67
|
+
"@fusion.dev/helix-testing": "0.204.0",
|
|
68
68
|
"@types/bun": "^1.4.2",
|
|
69
69
|
"@types/three": "^0.186.0",
|
|
70
70
|
"d3-force-3d": "^3.0.6",
|