Skip to content

Commit 53b6f8a

Browse files
committed
Stroke width and opacity
1 parent 3af0c37 commit 53b6f8a

4 files changed

Lines changed: 44 additions & 10 deletions

File tree

src/App.vue

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ let colorScale: (value: number | string) => string = () => 'rgba(0,0,0,0.5)';
4545
let program: WebGLProgram | null = null;
4646
let uMatrixLocation: WebGLUniformLocation | null = null;
4747
let uScreenWidthPixelsLocation: WebGLUniformLocation | null = null;
48+
let uStrokeWidthLocation: WebGLUniformLocation | null = null;
49+
let uStrokeOpacityLocation: WebGLUniformLocation | null = null;
4850
let positionBuffer: WebGLBuffer | null = null;
4951
let offsetBuffer: WebGLBuffer | null = null;
5052
let colorBuffer: WebGLBuffer | null = null;
@@ -71,6 +73,8 @@ const sendToWorker = (name: string, reference: Ref<any>) => {
7173
7274
const edgeWidth = ref(5.0);
7375
const edgeOpacity = ref(0.5);
76+
const strokeWidth = ref(1.0);
77+
const strokeOpacity = ref(0.5);
7478
const nodeOpacity = ref(0.5);
7579
const size = ref(0.5);
7680
const sizeField = ref('degree');
@@ -466,6 +470,8 @@ const drawScene = (gl: WebGL2RenderingContext) => {
466470
467471
gl.uniformMatrix3fv(uMatrixLocation, false, matrix);
468472
gl.uniform1f(uScreenWidthPixelsLocation, gl.canvas.width);
473+
gl.uniform1f(uStrokeWidthLocation, strokeWidth.value);
474+
gl.uniform1f(uStrokeOpacityLocation, strokeOpacity.value);
469475
gl.drawArraysInstanced(gl.TRIANGLE_FAN, 0, positions.length / 2, graph.nodes.length || 0);
470476
};
471477
@@ -596,6 +602,8 @@ onMounted(() => {
596602
597603
uMatrixLocation = gl.getUniformLocation(program, 'uMatrix');
598604
uScreenWidthPixelsLocation = gl.getUniformLocation(program, 'uScreenWidthPixels');
605+
uStrokeWidthLocation = gl.getUniformLocation(program, 'uStrokeWidth');
606+
uStrokeOpacityLocation = gl.getUniformLocation(program, 'uStrokeOpacity');
599607
600608
setupBuffersAndAttributes(gl, program);
601609
@@ -781,7 +789,15 @@ const showLayoutControls = ref(true);
781789
<input type="range" v-model.number="edgeOpacity" :min="0" :max="1" :step="epsilon" class="w-full mt-1">
782790
</div>
783791
<div class="mt-2">
784-
<label class="block text-sm font-medium text-gray-300">Node Opacity</label>
792+
<label class="block text-sm font-medium text-gray-300">Stroke Width</label>
793+
<input type="range" v-model.number="strokeWidth" :min="0" :max="50" :step="epsilon" class="w-full mt-1">
794+
</div>
795+
<div class="mt-2">
796+
<label class="block text-sm font-medium text-gray-300">Stroke Opacity</label>
797+
<input type="range" v-model.number="strokeOpacity" :min="0" :max="1" :step="epsilon" class="w-full mt-1">
798+
</div>
799+
<div class="mt-2">
800+
<label class="block text-sm font-medium text-gray-300">Fill Opacity</label>
785801
<input type="range" v-model.number="nodeOpacity" :min="0" :max="1" :step="epsilon" class="w-full mt-1">
786802
</div>
787803
<div class="mt-2">

src/shaders/node.frag

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,31 @@ in vec4 vColor;
55
in vec2 vPosition;
66

77
in float vAntialiasDistance;
8+
in highp float vStrokePosition;
9+
10+
uniform highp float uStrokeWidth;
11+
uniform float uStrokeOpacity;
812

913
out vec4 outColor;
1014

1115
void main() {
1216
float dist = length(vPosition);
13-
float radius = 1.0;
14-
if (dist > radius + vAntialiasDistance / 2.0) {
15-
discard;
17+
if (uStrokeOpacity > 0.0 && uStrokeWidth > 0.0) {
18+
float radius = 1.0;
19+
if (dist > radius + vAntialiasDistance / 2.0) {
20+
discard;
21+
}
22+
float alpha = 1.0 - smoothstep(radius - vAntialiasDistance / 2.0, radius + vAntialiasDistance / 2.0, dist);
23+
vec3 strokeColor = vec3(0.0, 0.0, 0.0);
24+
float colorBlend = smoothstep(vStrokePosition - vAntialiasDistance / 2.0, vStrokePosition + vAntialiasDistance / 2.0, dist);
25+
outColor = vec4(mix(vColor.rgb, strokeColor, colorBlend), mix(vColor.a, uStrokeOpacity, colorBlend) * alpha);
26+
} else {
27+
// Extend node fill to center of stroke if no stroke
28+
float radius = (1.0 + vStrokePosition) / 2.0;
29+
if (dist > radius + vAntialiasDistance / 2.0) {
30+
discard;
31+
}
32+
float alpha = 1.0 - smoothstep(radius - vAntialiasDistance / 2.0, radius + vAntialiasDistance / 2.0, dist);
33+
outColor = vec4(vColor.rgb, vColor.a * alpha);
1634
}
17-
float alpha = 1.0 - smoothstep(radius - vAntialiasDistance / 2.0, radius + vAntialiasDistance / 2.0, dist);
18-
outColor = vec4(vColor.rgb, vColor.a * alpha);
1935
}

src/shaders/node.vert

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@ in float aRadius;
66

77
uniform mat3 uMatrix;
88
uniform float uScreenWidthPixels;
9+
uniform float uStrokeWidth;
910

1011
out vec4 vColor;
1112
out vec2 vPosition;
1213
out float vAntialiasDistance;
14+
out float vStrokePosition;
1315

1416
void main() {
15-
vec2 position = aPosition * aRadius + aOffset;
17+
float fullRadius = aRadius + uStrokeWidth / 2.0;
18+
vec2 position = aPosition * fullRadius + aOffset;
1619
position = (uMatrix * vec3(position, 1.0)).xy;
1720
vPosition = aPosition;
1821
gl_Position = vec4(position, 0.0, 1.0);
@@ -27,5 +30,6 @@ void main() {
2730
// position / pixel = (position / screen) * (screen / pixel)
2831
// = (1 / (aRadius * uMatrix[0][0])) * (2 / uScreenWidthPixels)
2932
// = 2 / (aRadius * uMatrix[0][0] * uScreenWidthPixels)
30-
vAntialiasDistance = 2.0 / (aRadius * uMatrix[0][0] * uScreenWidthPixels);
33+
vAntialiasDistance = 2.0 / (fullRadius * uMatrix[0][0] * uScreenWidthPixels);
34+
vStrokePosition = (aRadius - uStrokeWidth / 2.0) / fullRadius;
3135
}

src/worker.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,6 @@ onmessage = function(e) {
111111
} else if (e.data.type === 'chargeStrength') {
112112
simulation.force('charge', e.data.value ? charge : null);
113113
charge.strength(-e.data.value);
114-
} else if (e.data.type === 'chargeFactor') {
115-
console.log('Use chargeStrength to change charge');
116114
} else if (e.data.type === 'collideFactor') {
117115
simulation.force('collide', e.data.value ? collide : null);
118116
collide.strength(e.data.value);

0 commit comments

Comments
 (0)