@yurialvesbordin/graphium 0.0.0-stage → 2.0.1
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/LICENSE +21 -0
- package/README.md +112 -2
- package/dist/Graphium.d.ts +156 -0
- package/dist/Graphium.d.ts.map +1 -0
- package/dist/Graphium.js +413 -0
- package/dist/Graphium.js.map +1 -0
- package/dist/core/FocusController.d.ts +16 -0
- package/dist/core/FocusController.d.ts.map +1 -0
- package/dist/core/FocusController.js +53 -0
- package/dist/core/FocusController.js.map +1 -0
- package/dist/core/GraphEditor.d.ts +61 -0
- package/dist/core/GraphEditor.d.ts.map +1 -0
- package/dist/core/GraphEditor.js +165 -0
- package/dist/core/GraphEditor.js.map +1 -0
- package/dist/core/GraphModel.d.ts +166 -0
- package/dist/core/GraphModel.d.ts.map +1 -0
- package/dist/core/GraphModel.js +730 -0
- package/dist/core/GraphModel.js.map +1 -0
- package/dist/core/SelectionController.d.ts +26 -0
- package/dist/core/SelectionController.d.ts.map +1 -0
- package/dist/core/SelectionController.js +78 -0
- package/dist/core/SelectionController.js.map +1 -0
- package/dist/core/colors.d.ts +27 -0
- package/dist/core/colors.d.ts.map +1 -0
- package/dist/core/colors.js +141 -0
- package/dist/core/colors.js.map +1 -0
- package/dist/core/events.d.ts +21 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +64 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/handles.d.ts +60 -0
- package/dist/core/handles.d.ts.map +1 -0
- package/dist/core/handles.js +116 -0
- package/dist/core/handles.js.map +1 -0
- package/dist/core/theme.d.ts +9 -0
- package/dist/core/theme.d.ts.map +1 -0
- package/dist/core/theme.js +167 -0
- package/dist/core/theme.js.map +1 -0
- package/dist/core/themes.d.ts +9 -0
- package/dist/core/themes.d.ts.map +1 -0
- package/dist/core/themes.js +103 -0
- package/dist/core/themes.js.map +1 -0
- package/dist/core/types.d.ts +287 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +7 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction/InteractionBinder.d.ts +43 -0
- package/dist/interaction/InteractionBinder.d.ts.map +1 -0
- package/dist/interaction/InteractionBinder.js +121 -0
- package/dist/interaction/InteractionBinder.js.map +1 -0
- package/dist/interaction/PointerController.d.ts +83 -0
- package/dist/interaction/PointerController.d.ts.map +1 -0
- package/dist/interaction/PointerController.js +294 -0
- package/dist/interaction/PointerController.js.map +1 -0
- package/dist/physics/PhysicsEngine.d.ts +82 -0
- package/dist/physics/PhysicsEngine.d.ts.map +1 -0
- package/dist/physics/PhysicsEngine.js +469 -0
- package/dist/physics/PhysicsEngine.js.map +1 -0
- package/dist/physics/SpatialHash.d.ts +36 -0
- package/dist/physics/SpatialHash.d.ts.map +1 -0
- package/dist/physics/SpatialHash.js +126 -0
- package/dist/physics/SpatialHash.js.map +1 -0
- package/dist/physics/presets.d.ts +14 -0
- package/dist/physics/presets.d.ts.map +1 -0
- package/dist/physics/presets.js +108 -0
- package/dist/physics/presets.js.map +1 -0
- package/dist/render/Camera.d.ts +55 -0
- package/dist/render/Camera.d.ts.map +1 -0
- package/dist/render/Camera.js +94 -0
- package/dist/render/Camera.js.map +1 -0
- package/dist/render/LabelLayer.d.ts +32 -0
- package/dist/render/LabelLayer.d.ts.map +1 -0
- package/dist/render/LabelLayer.js +142 -0
- package/dist/render/LabelLayer.js.map +1 -0
- package/dist/render/RenderLoop.d.ts +67 -0
- package/dist/render/RenderLoop.d.ts.map +1 -0
- package/dist/render/RenderLoop.js +126 -0
- package/dist/render/RenderLoop.js.map +1 -0
- package/dist/render/Renderer.d.ts +73 -0
- package/dist/render/Renderer.d.ts.map +1 -0
- package/dist/render/Renderer.js +512 -0
- package/dist/render/Renderer.js.map +1 -0
- package/dist/render/TextureAtlas.d.ts +51 -0
- package/dist/render/TextureAtlas.d.ts.map +1 -0
- package/dist/render/TextureAtlas.js +160 -0
- package/dist/render/TextureAtlas.js.map +1 -0
- package/dist/render/ViewportController.d.ts +34 -0
- package/dist/render/ViewportController.d.ts.map +1 -0
- package/dist/render/ViewportController.js +57 -0
- package/dist/render/ViewportController.js.map +1 -0
- package/dist/render/geometry.d.ts +19 -0
- package/dist/render/geometry.d.ts.map +1 -0
- package/dist/render/geometry.js +71 -0
- package/dist/render/geometry.js.map +1 -0
- package/dist/render/shaders.d.ts +13 -0
- package/dist/render/shaders.d.ts.map +1 -0
- package/dist/render/shaders.js +183 -0
- package/dist/render/shaders.js.map +1 -0
- package/package.json +73 -4
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manages a GPU texture atlas that packs node images into a fixed grid.
|
|
3
|
+
* Images load asynchronously, are drawn into an offscreen canvas using cover
|
|
4
|
+
* or contain framing, and are uploaded in a single texture update per frame.
|
|
5
|
+
*/
|
|
6
|
+
export class TextureAtlas {
|
|
7
|
+
constructor(gl, size = 1024, grid = 8) {
|
|
8
|
+
this.revision = 0;
|
|
9
|
+
this.loadedCount = 0;
|
|
10
|
+
this.entries = new Map();
|
|
11
|
+
this.pending = new Set();
|
|
12
|
+
this.nextSlot = 0;
|
|
13
|
+
this.onEvent = null;
|
|
14
|
+
this.uploadedRevision = -1;
|
|
15
|
+
this.gl = gl;
|
|
16
|
+
this.size = size;
|
|
17
|
+
this.grid = grid;
|
|
18
|
+
this.cellSize = size / grid;
|
|
19
|
+
this.maxSlots = grid * grid;
|
|
20
|
+
if (typeof OffscreenCanvas !== 'undefined') {
|
|
21
|
+
this.canvas = new OffscreenCanvas(size, size);
|
|
22
|
+
this.context = this.canvas.getContext('2d');
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
this.canvas = document.createElement('canvas');
|
|
26
|
+
this.canvas.width = size;
|
|
27
|
+
this.canvas.height = size;
|
|
28
|
+
this.context = this.canvas.getContext('2d');
|
|
29
|
+
}
|
|
30
|
+
this.texture = gl.createTexture();
|
|
31
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
32
|
+
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
|
33
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
34
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
35
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
36
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
37
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
|
38
|
+
}
|
|
39
|
+
/** Returns the GPU texture handle for binding during node rendering. */
|
|
40
|
+
getTexture() {
|
|
41
|
+
return this.texture;
|
|
42
|
+
}
|
|
43
|
+
/** Returns the slot for a URL, requesting the image if it is new. */
|
|
44
|
+
request(url, mode = 'cover') {
|
|
45
|
+
const entry = this.entries.get(url);
|
|
46
|
+
if (entry) {
|
|
47
|
+
entry.used = true;
|
|
48
|
+
entry.mode = mode;
|
|
49
|
+
return entry.slot;
|
|
50
|
+
}
|
|
51
|
+
if (this.nextSlot >= this.maxSlots || typeof Image === 'undefined') {
|
|
52
|
+
return -1;
|
|
53
|
+
}
|
|
54
|
+
const record = {
|
|
55
|
+
slot: this.nextSlot++,
|
|
56
|
+
ready: false,
|
|
57
|
+
failed: false,
|
|
58
|
+
used: true,
|
|
59
|
+
mode,
|
|
60
|
+
image: null,
|
|
61
|
+
};
|
|
62
|
+
this.entries.set(url, record);
|
|
63
|
+
this.pending.add(url);
|
|
64
|
+
const image = new Image();
|
|
65
|
+
image.crossOrigin = 'anonymous';
|
|
66
|
+
image.onload = () => {
|
|
67
|
+
if (!this.entries.has(url)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
record.ready = true;
|
|
71
|
+
record.image = image;
|
|
72
|
+
this.pending.delete(url);
|
|
73
|
+
this.drawEntry(record);
|
|
74
|
+
this.loadedCount++;
|
|
75
|
+
if (this.onEvent) {
|
|
76
|
+
this.onEvent({ type: 'imageload', url, slot: record.slot });
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
image.onerror = () => {
|
|
80
|
+
record.failed = true;
|
|
81
|
+
this.pending.delete(url);
|
|
82
|
+
if (this.onEvent) {
|
|
83
|
+
this.onEvent({ type: 'imageerror', url, slot: record.slot });
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
image.src = url;
|
|
87
|
+
return record.slot;
|
|
88
|
+
}
|
|
89
|
+
/** Paints one entry into its atlas cell respecting the framing mode. */
|
|
90
|
+
drawEntry(record) {
|
|
91
|
+
const context = this.context;
|
|
92
|
+
const image = record.image;
|
|
93
|
+
if (!context || !image) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const cell = this.cellSize;
|
|
97
|
+
const x = (record.slot % this.grid) * cell;
|
|
98
|
+
const y = Math.floor(record.slot / this.grid) * cell;
|
|
99
|
+
const naturalWidth = image.naturalWidth || image.width;
|
|
100
|
+
const naturalHeight = image.naturalHeight || image.height;
|
|
101
|
+
const scale = record.mode === 'contain' ? Math.min(cell / naturalWidth, cell / naturalHeight) : Math.max(cell / naturalWidth, cell / naturalHeight);
|
|
102
|
+
const width = naturalWidth * scale;
|
|
103
|
+
const height = naturalHeight * scale;
|
|
104
|
+
context.clearRect(x, y, cell, cell);
|
|
105
|
+
context.drawImage(image, x + (cell - width) * 0.5, y + (cell - height) * 0.5, width, height);
|
|
106
|
+
this.revision++;
|
|
107
|
+
}
|
|
108
|
+
/** Uploads the atlas canvas to the GPU when new images arrived. */
|
|
109
|
+
update() {
|
|
110
|
+
if (this.revision === this.uploadedRevision) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
this.uploadedRevision = this.revision;
|
|
114
|
+
const gl = this.gl;
|
|
115
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
116
|
+
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
|
117
|
+
if (this.canvas) {
|
|
118
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.canvas);
|
|
119
|
+
}
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
/** Marks all entries unused and drops the ones ignored for a full frame. */
|
|
123
|
+
sweep() {
|
|
124
|
+
for (const [url, entry] of this.entries) {
|
|
125
|
+
if (!entry.used) {
|
|
126
|
+
this.entries.delete(url);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
entry.used = false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** Resolves once every pending image finished loading or failed. */
|
|
134
|
+
loadAll() {
|
|
135
|
+
if (this.pending.size === 0) {
|
|
136
|
+
return Promise.resolve();
|
|
137
|
+
}
|
|
138
|
+
return new Promise(resolve => {
|
|
139
|
+
const check = () => {
|
|
140
|
+
if (this.pending.size === 0) {
|
|
141
|
+
resolve();
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
};
|
|
146
|
+
const previous = this.onEvent;
|
|
147
|
+
this.onEvent = event => {
|
|
148
|
+
if (previous) {
|
|
149
|
+
previous(event);
|
|
150
|
+
}
|
|
151
|
+
check();
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
/** Reports whether a URL finished loading successfully. */
|
|
156
|
+
isReady(url) {
|
|
157
|
+
return this.entries.get(url)?.ready ?? false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=TextureAtlas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TextureAtlas.js","sourceRoot":"","sources":["../../src/render/TextureAtlas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owns view framing and navigation: fitting the graph, centering, zooming,
|
|
3
|
+
* resizing the renderer to the canvas and screen to world conversion.
|
|
4
|
+
*/
|
|
5
|
+
import type { GraphModel } from '../core/GraphModel.js';
|
|
6
|
+
import type { Camera } from './Camera.js';
|
|
7
|
+
import type { Renderer } from './Renderer.js';
|
|
8
|
+
/** Collaborators the viewport control needs from the main facade. */
|
|
9
|
+
export interface ViewportDeps {
|
|
10
|
+
model: GraphModel;
|
|
11
|
+
camera: Camera;
|
|
12
|
+
renderer: Renderer;
|
|
13
|
+
invalidate: () => void;
|
|
14
|
+
}
|
|
15
|
+
export declare class ViewportController {
|
|
16
|
+
private readonly deps;
|
|
17
|
+
constructor(deps: ViewportDeps);
|
|
18
|
+
/** Scales the view so the whole graph fits with padding. */
|
|
19
|
+
fit(padding?: number): void;
|
|
20
|
+
/** Centers the view on a world point. */
|
|
21
|
+
centerOn(x: number, y: number): void;
|
|
22
|
+
/** Multiplies the current zoom level. */
|
|
23
|
+
zoomBy(factor: number): void;
|
|
24
|
+
/** Sets an absolute zoom level. */
|
|
25
|
+
zoomTo(zoom: number): void;
|
|
26
|
+
/** Resizes the renderer to the canvas client size. */
|
|
27
|
+
resize(): void;
|
|
28
|
+
/** Returns the world position under a screen position. */
|
|
29
|
+
screenToWorld(screenX: number, screenY: number): {
|
|
30
|
+
x: number;
|
|
31
|
+
y: number;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=ViewportController.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ViewportController.d.ts","sourceRoot":"","sources":["../../src/render/ViewportController.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,qEAAqE;AACrE,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,qBAAa,kBAAkB;IACjB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,YAAY;IAE/C,4DAA4D;IAC5D,GAAG,CAAC,OAAO,SAAK,GAAG,IAAI;IAoBvB,yCAAyC;IACzC,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAKpC,yCAAyC;IACzC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAK5B,mCAAmC;IACnC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK1B,sDAAsD;IACtD,MAAM,IAAI,IAAI;IAQd,0DAA0D;IAC1D,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE;CAG1E"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owns view framing and navigation: fitting the graph, centering, zooming,
|
|
3
|
+
* resizing the renderer to the canvas and screen to world conversion.
|
|
4
|
+
*/
|
|
5
|
+
export class ViewportController {
|
|
6
|
+
constructor(deps) {
|
|
7
|
+
this.deps = deps;
|
|
8
|
+
}
|
|
9
|
+
/** Scales the view so the whole graph fits with padding. */
|
|
10
|
+
fit(padding = 60) {
|
|
11
|
+
const model = this.deps.model;
|
|
12
|
+
if (model.nodeCount === 0) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
let minX = Infinity;
|
|
16
|
+
let minY = Infinity;
|
|
17
|
+
let maxX = -Infinity;
|
|
18
|
+
let maxY = -Infinity;
|
|
19
|
+
for (let index = 0; index < model.nodeCount; index++) {
|
|
20
|
+
const radius = model.visualRadius[index];
|
|
21
|
+
minX = Math.min(minX, model.x[index] - radius);
|
|
22
|
+
minY = Math.min(minY, model.y[index] - radius);
|
|
23
|
+
maxX = Math.max(maxX, model.x[index] + radius);
|
|
24
|
+
maxY = Math.max(maxY, model.y[index] + radius);
|
|
25
|
+
}
|
|
26
|
+
this.deps.camera.fit(minX, minY, maxX, maxY, padding);
|
|
27
|
+
this.deps.invalidate();
|
|
28
|
+
}
|
|
29
|
+
/** Centers the view on a world point. */
|
|
30
|
+
centerOn(x, y) {
|
|
31
|
+
this.deps.camera.setPosition(x, y);
|
|
32
|
+
this.deps.invalidate();
|
|
33
|
+
}
|
|
34
|
+
/** Multiplies the current zoom level. */
|
|
35
|
+
zoomBy(factor) {
|
|
36
|
+
this.deps.camera.setZoom(this.deps.camera.zoom * factor);
|
|
37
|
+
this.deps.invalidate();
|
|
38
|
+
}
|
|
39
|
+
/** Sets an absolute zoom level. */
|
|
40
|
+
zoomTo(zoom) {
|
|
41
|
+
this.deps.camera.setZoom(zoom);
|
|
42
|
+
this.deps.invalidate();
|
|
43
|
+
}
|
|
44
|
+
/** Resizes the renderer to the canvas client size. */
|
|
45
|
+
resize() {
|
|
46
|
+
const canvas = this.deps.renderer.canvas;
|
|
47
|
+
const width = canvas.clientWidth || canvas.width || 1;
|
|
48
|
+
const height = canvas.clientHeight || canvas.height || 1;
|
|
49
|
+
this.deps.renderer.resize(width, height, window.devicePixelRatio || 1);
|
|
50
|
+
this.deps.invalidate();
|
|
51
|
+
}
|
|
52
|
+
/** Returns the world position under a screen position. */
|
|
53
|
+
screenToWorld(screenX, screenY) {
|
|
54
|
+
return this.deps.camera.screenToWorld(screenX, screenY, { x: 0, y: 0 });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=ViewportController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ViewportController.js","sourceRoot":"","sources":["../../src/render/ViewportController.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hosts the quadratic bezier geometry helpers shared by the renderer and the
|
|
3
|
+
* picking code so curved edges look and hit test exactly the same way.
|
|
4
|
+
*/
|
|
5
|
+
export interface Point2D {
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
}
|
|
9
|
+
/** Computes the quadratic bezier control point for an edge with curvature. */
|
|
10
|
+
export declare function controlPoint(ax: number, ay: number, bx: number, by: number, curvature: number, out: Point2D): Point2D;
|
|
11
|
+
/** Evaluates a point on the quadratic bezier defined by an edge. */
|
|
12
|
+
export declare function bezierPoint(ax: number, ay: number, cx: number, cy: number, bx: number, by: number, t: number, out: Point2D): Point2D;
|
|
13
|
+
/** Estimates the arc length of a curved edge using fixed sampling. */
|
|
14
|
+
export declare function bezierLength(ax: number, ay: number, cx: number, cy: number, bx: number, by: number, samples?: number): number;
|
|
15
|
+
/** Computes the shortest distance from a point to a quadratic bezier edge. */
|
|
16
|
+
export declare function distanceToEdge(px: number, py: number, ax: number, ay: number, bx: number, by: number, curvature: number): number;
|
|
17
|
+
/** Computes the shortest distance from a point to a straight segment. */
|
|
18
|
+
export declare function distanceToSegment(px: number, py: number, ax: number, ay: number, bx: number, by: number): number;
|
|
19
|
+
//# sourceMappingURL=geometry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../src/render/geometry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,OAAO;IACtB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAarH;AAED,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAKpI;AAED,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,SAAK,GAAG,MAAM,CAYzH;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAkBhI;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAQhH"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hosts the quadratic bezier geometry helpers shared by the renderer and the
|
|
3
|
+
* picking code so curved edges look and hit test exactly the same way.
|
|
4
|
+
*/
|
|
5
|
+
/** Computes the quadratic bezier control point for an edge with curvature. */
|
|
6
|
+
export function controlPoint(ax, ay, bx, by, curvature, out) {
|
|
7
|
+
const dx = bx - ax;
|
|
8
|
+
const dy = by - ay;
|
|
9
|
+
const length = Math.hypot(dx, dy);
|
|
10
|
+
if (curvature === 0 || length < 0.0001) {
|
|
11
|
+
out.x = (ax + bx) * 0.5;
|
|
12
|
+
out.y = (ay + by) * 0.5;
|
|
13
|
+
return out;
|
|
14
|
+
}
|
|
15
|
+
const offset = curvature * length * 0.35;
|
|
16
|
+
out.x = (ax + bx) * 0.5 - (dy / length) * offset;
|
|
17
|
+
out.y = (ay + by) * 0.5 + (dx / length) * offset;
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
20
|
+
/** Evaluates a point on the quadratic bezier defined by an edge. */
|
|
21
|
+
export function bezierPoint(ax, ay, cx, cy, bx, by, t, out) {
|
|
22
|
+
const u = 1 - t;
|
|
23
|
+
out.x = u * u * ax + 2 * u * t * cx + t * t * bx;
|
|
24
|
+
out.y = u * u * ay + 2 * u * t * cy + t * t * by;
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
/** Estimates the arc length of a curved edge using fixed sampling. */
|
|
28
|
+
export function bezierLength(ax, ay, cx, cy, bx, by, samples = 10) {
|
|
29
|
+
let length = 0;
|
|
30
|
+
let prevX = ax;
|
|
31
|
+
let prevY = ay;
|
|
32
|
+
const point = { x: 0, y: 0 };
|
|
33
|
+
for (let index = 1; index <= samples; index++) {
|
|
34
|
+
bezierPoint(ax, ay, cx, cy, bx, by, index / samples, point);
|
|
35
|
+
length += Math.hypot(point.x - prevX, point.y - prevY);
|
|
36
|
+
prevX = point.x;
|
|
37
|
+
prevY = point.y;
|
|
38
|
+
}
|
|
39
|
+
return length;
|
|
40
|
+
}
|
|
41
|
+
/** Computes the shortest distance from a point to a quadratic bezier edge. */
|
|
42
|
+
export function distanceToEdge(px, py, ax, ay, bx, by, curvature) {
|
|
43
|
+
const control = { x: 0, y: 0 };
|
|
44
|
+
controlPoint(ax, ay, bx, by, curvature, control);
|
|
45
|
+
if (curvature === 0) {
|
|
46
|
+
return distanceToSegment(px, py, ax, ay, bx, by);
|
|
47
|
+
}
|
|
48
|
+
const point = { x: 0, y: 0 };
|
|
49
|
+
let best = Infinity;
|
|
50
|
+
const steps = 12;
|
|
51
|
+
let prevX = ax;
|
|
52
|
+
let prevY = ay;
|
|
53
|
+
for (let index = 1; index <= steps; index++) {
|
|
54
|
+
bezierPoint(ax, ay, control.x, control.y, bx, by, index / steps, point);
|
|
55
|
+
best = Math.min(best, distanceToSegment(px, py, prevX, prevY, point.x, point.y));
|
|
56
|
+
prevX = point.x;
|
|
57
|
+
prevY = point.y;
|
|
58
|
+
}
|
|
59
|
+
return best;
|
|
60
|
+
}
|
|
61
|
+
/** Computes the shortest distance from a point to a straight segment. */
|
|
62
|
+
export function distanceToSegment(px, py, ax, ay, bx, by) {
|
|
63
|
+
const dx = bx - ax;
|
|
64
|
+
const dy = by - ay;
|
|
65
|
+
const lengthSq = dx * dx + dy * dy;
|
|
66
|
+
const t = lengthSq > 0 ? Math.max(0, Math.min(1, ((px - ax) * dx + (py - ay) * dy) / lengthSq)) : 0;
|
|
67
|
+
const cx = ax + dx * t;
|
|
68
|
+
const cy = ay + dy * t;
|
|
69
|
+
return Math.hypot(px - cx, py - cy);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=geometry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry.js","sourceRoot":"","sources":["../../src/render/geometry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stores the GLSL program sources. Nodes render as instanced quads with
|
|
3
|
+
* signed distance circles, atlas images and state rings. Edges render as
|
|
4
|
+
* instanced quads bent along a quadratic bezier defined by per link
|
|
5
|
+
* curvature, with dashes measured along the true curve arc length.
|
|
6
|
+
*/
|
|
7
|
+
export declare const NODE_VERTEX = "#version 300 es\nprecision highp float;\nlayout(location=0) in vec2 aCorner;\nlayout(location=1) in vec4 aNode;\nlayout(location=2) in vec4 aFill;\nlayout(location=3) in vec4 aBorder;\nlayout(location=4) in vec4 aStyle;\nlayout(location=5) in vec4 aImage;\nuniform mat3 uCamera;\nout vec2 vLocal;\nout vec2 vAtlasUv;\nout vec4 vFill;\nout vec4 vBorder;\nout vec4 vStyle;\nflat out float vImageActive;\nvoid main() {\n vec2 world = aNode.xy + aCorner * aNode.w;\n gl_Position = vec4((uCamera * vec3(world, 1.0)).xy, 0.0, 1.0);\n vLocal = aCorner;\n vAtlasUv = (aCorner * 0.5 + 0.5 + vec2(mod(aImage.x, 8.0), floor(aImage.x / 8.0))) / 8.0;\n vFill = aFill;\n vBorder = aBorder;\n vStyle = aStyle;\n vImageActive = aImage.y;\n}";
|
|
8
|
+
export declare const NODE_FRAGMENT = "#version 300 es\nprecision highp float;\nin vec2 vLocal;\nin vec2 vAtlasUv;\nin vec4 vFill;\nin vec4 vBorder;\nin vec4 vStyle;\nflat in float vImageActive;\nuniform sampler2D uAtlas;\nuniform float uZoom;\nuniform vec4 uHoverRing;\nuniform vec4 uSelectedRing;\nuniform vec4 uFixedRing;\nuniform float uHoverRingWidth;\nuniform float uSelectedRingWidth;\nuniform float uFixedRingWidth;\nuniform float uDisabledOpacity;\nout vec4 outColor;\nfloat band(float d, float inner, float outer, float aa) {\n return smoothstep(inner - aa, inner + aa, d) * (1.0 - smoothstep(outer - aa, outer + aa, d));\n}\nvoid main() {\n float d = length(vLocal);\n float aa = max(fwidth(d), 0.0008);\n float discRadius = vStyle.x / max(vStyle.w, 0.0001);\n float discAlpha = 1.0 - smoothstep(discRadius - aa, discRadius + aa, d);\n int state = int(vStyle.z + 0.5);\n vec4 ringColor = vec4(0.0);\n float ringWidth = 0.0;\n if (state == 1) { ringColor = uHoverRing; ringWidth = uHoverRingWidth; }\n else if (state == 2 || state == 3) { ringColor = uSelectedRing; ringWidth = uSelectedRingWidth; }\n else if (state == 4) { ringColor = uFixedRing; ringWidth = uFixedRingWidth; }\n float ringOuter = discRadius + ringWidth / max(uZoom * vStyle.w, 0.0001);\n float ring = ringWidth > 0.0 ? band(d, discRadius, ringOuter, aa) : 0.0;\n if (discAlpha <= 0.0 && ring <= 0.0) discard;\n vec4 fill = vFill;\n if (vImageActive > 0.5) {\n vec4 image = texture(uAtlas, vAtlasUv);\n fill.rgb = mix(fill.rgb, image.rgb, image.a);\n }\n float borderSize = vStyle.y / max(uZoom * vStyle.w, 0.0001);\n float border = vStyle.y > 0.0 ? band(d, max(0.0, discRadius - borderSize), discRadius, aa) : 0.0;\n vec4 core = mix(fill, vec4(vBorder.rgb, vBorder.a * vStyle.y), border);\n core.a *= discAlpha * (state == 5 ? uDisabledOpacity : 1.0);\n vec4 halo = vec4(ringColor.rgb, ringColor.a * ring);\n outColor = vec4(mix(halo.rgb, core.rgb, core.a), core.a + halo.a * (1.0 - core.a));\n}";
|
|
9
|
+
export declare const EDGE_VERTEX = "#version 300 es\nprecision highp float;\nlayout(location=0) in vec2 aCorner;\nlayout(location=1) in vec4 aSegment;\nlayout(location=2) in vec4 aColor;\nlayout(location=3) in vec4 aStyle;\nlayout(location=4) in vec4 aMeta;\nuniform mat3 uCamera;\nuniform float uZoom;\nout float vSide;\nout float vDashPosition;\nout vec4 vColor;\nout vec2 vDashPattern;\nflat out float vDashed;\nvoid main() {\n vec2 p0 = aSegment.xy;\n vec2 p1 = aSegment.zw;\n vec2 chord = p1 - p0;\n float chordLength = max(length(chord), 0.00001);\n float curvature = aMeta.x;\n vec2 mid = (p0 + p1) * 0.5;\n vec2 control = mid + vec2(-chord.y, chord.x) / chordLength * (curvature * chordLength * 0.35);\n float t = (aCorner.x + 1.0) * 0.5;\n float u = 1.0 - t;\n vec2 point = u * u * p0 + 2.0 * u * t * control + t * t * p1;\n vec2 tangent = 2.0 * u * (control - p0) + 2.0 * t * (p1 - control);\n float tangentLength = max(length(tangent), 0.00001);\n vec2 normal = vec2(-tangent.y, tangent.x) / tangentLength;\n float widthWorld = aStyle.x / max(uZoom, 0.0001);\n vec2 world = point + normal * aCorner.y * widthWorld * 0.5;\n gl_Position = vec4((uCamera * vec3(world, 1.0)).xy, 0.0, 1.0);\n vSide = aCorner.y;\n float dashScale = aMeta.z > 0.5 ? 1.0 : uZoom;\n vDashPosition = (t * aMeta.w) * dashScale + aStyle.w;\n vColor = aColor;\n vDashPattern = aStyle.yz;\n vDashed = aMeta.y;\n}";
|
|
10
|
+
export declare const EDGE_FRAGMENT = "#version 300 es\nprecision highp float;\nin float vSide;\nin float vDashPosition;\nin vec4 vColor;\nin vec2 vDashPattern;\nflat in float vDashed;\nout vec4 outColor;\nvoid main() {\n float edgeAA = max(fwidth(vSide), 0.002);\n float alpha = 1.0 - smoothstep(1.0 - edgeAA, 1.0 + edgeAA, abs(vSide));\n if (vDashed > 0.5) {\n float cycle = max(0.5, vDashPattern.x + vDashPattern.y);\n float phase = mod(vDashPosition, cycle);\n float dashAA = max(fwidth(vDashPosition), 0.3);\n alpha *= 1.0 - smoothstep(vDashPattern.x - dashAA, vDashPattern.x + dashAA, phase);\n }\n if (alpha <= 0.0) discard;\n outColor = vec4(vColor.rgb, vColor.a * alpha);\n}";
|
|
11
|
+
export declare const ARROW_VERTEX = "#version 300 es\nprecision highp float;\nlayout(location=0) in vec2 aCorner;\nlayout(location=1) in vec4 aArrow;\nlayout(location=2) in vec4 aColor;\nlayout(location=3) in float aHalfWidth;\nuniform mat3 uCamera;\nout vec2 vLocal;\nflat out float vLength;\nflat out float vHalfWidth;\nout vec4 vColor;\nvoid main() {\n vec2 base = aArrow.xy;\n vec2 tip = aArrow.zw;\n vec2 direction = tip - base;\n float worldLength = max(length(direction), 0.00001);\n vec2 dirNorm = direction / worldLength;\n vec2 normal = vec2(-dirNorm.y, dirNorm.x);\n float t = (aCorner.x + 1.0) * 0.5;\n vec2 world = base + dirNorm * (t * worldLength) + normal * aCorner.y * aHalfWidth * (1.0 - t);\n gl_Position = vec4((uCamera * vec3(world, 1.0)).xy, 0.0, 1.0);\n vLocal = vec2(t * worldLength, aCorner.y * aHalfWidth * (1.0 - t));\n vLength = worldLength;\n vHalfWidth = aHalfWidth;\n vColor = aColor;\n}";
|
|
12
|
+
export declare const ARROW_FRAGMENT = "#version 300 es\nprecision highp float;\nin vec2 vLocal;\nflat in float vLength;\nflat in float vHalfWidth;\nin vec4 vColor;\nout vec4 outColor;\nvoid main() {\n float u = vLocal.x;\n float v = vLocal.y;\n float L = vLength;\n float W = vHalfWidth;\n if (L <= 0.00001) discard;\n float dEdges = (W * L - W * u - abs(v) * L) / length(vec2(L, W));\n float d = min(u, dEdges);\n float aa = max(fwidth(d), 0.002);\n float alpha = smoothstep(-aa, aa, d);\n if (alpha <= 0.0) discard;\n outColor = vec4(vColor.rgb, vColor.a * alpha);\n}";
|
|
13
|
+
//# sourceMappingURL=shaders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shaders.d.ts","sourceRoot":"","sources":["../../src/render/shaders.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,WAAW,iuBAwBtB,CAAC;AAEH,eAAO,MAAM,aAAa,k7DA8CxB,CAAC;AAEH,eAAO,MAAM,WAAW,w2CAqCtB,CAAC;AAEH,eAAO,MAAM,aAAa,2pBAmBxB,CAAC;AAEH,eAAO,MAAM,YAAY,m4BAyBvB,CAAC;AAEH,eAAO,MAAM,cAAc,kiBAmBzB,CAAC"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stores the GLSL program sources. Nodes render as instanced quads with
|
|
3
|
+
* signed distance circles, atlas images and state rings. Edges render as
|
|
4
|
+
* instanced quads bent along a quadratic bezier defined by per link
|
|
5
|
+
* curvature, with dashes measured along the true curve arc length.
|
|
6
|
+
*/
|
|
7
|
+
export const NODE_VERTEX = `#version 300 es
|
|
8
|
+
precision highp float;
|
|
9
|
+
layout(location=0) in vec2 aCorner;
|
|
10
|
+
layout(location=1) in vec4 aNode;
|
|
11
|
+
layout(location=2) in vec4 aFill;
|
|
12
|
+
layout(location=3) in vec4 aBorder;
|
|
13
|
+
layout(location=4) in vec4 aStyle;
|
|
14
|
+
layout(location=5) in vec4 aImage;
|
|
15
|
+
uniform mat3 uCamera;
|
|
16
|
+
out vec2 vLocal;
|
|
17
|
+
out vec2 vAtlasUv;
|
|
18
|
+
out vec4 vFill;
|
|
19
|
+
out vec4 vBorder;
|
|
20
|
+
out vec4 vStyle;
|
|
21
|
+
flat out float vImageActive;
|
|
22
|
+
void main() {
|
|
23
|
+
vec2 world = aNode.xy + aCorner * aNode.w;
|
|
24
|
+
gl_Position = vec4((uCamera * vec3(world, 1.0)).xy, 0.0, 1.0);
|
|
25
|
+
vLocal = aCorner;
|
|
26
|
+
vAtlasUv = (aCorner * 0.5 + 0.5 + vec2(mod(aImage.x, 8.0), floor(aImage.x / 8.0))) / 8.0;
|
|
27
|
+
vFill = aFill;
|
|
28
|
+
vBorder = aBorder;
|
|
29
|
+
vStyle = aStyle;
|
|
30
|
+
vImageActive = aImage.y;
|
|
31
|
+
}`;
|
|
32
|
+
export const NODE_FRAGMENT = `#version 300 es
|
|
33
|
+
precision highp float;
|
|
34
|
+
in vec2 vLocal;
|
|
35
|
+
in vec2 vAtlasUv;
|
|
36
|
+
in vec4 vFill;
|
|
37
|
+
in vec4 vBorder;
|
|
38
|
+
in vec4 vStyle;
|
|
39
|
+
flat in float vImageActive;
|
|
40
|
+
uniform sampler2D uAtlas;
|
|
41
|
+
uniform float uZoom;
|
|
42
|
+
uniform vec4 uHoverRing;
|
|
43
|
+
uniform vec4 uSelectedRing;
|
|
44
|
+
uniform vec4 uFixedRing;
|
|
45
|
+
uniform float uHoverRingWidth;
|
|
46
|
+
uniform float uSelectedRingWidth;
|
|
47
|
+
uniform float uFixedRingWidth;
|
|
48
|
+
uniform float uDisabledOpacity;
|
|
49
|
+
out vec4 outColor;
|
|
50
|
+
float band(float d, float inner, float outer, float aa) {
|
|
51
|
+
return smoothstep(inner - aa, inner + aa, d) * (1.0 - smoothstep(outer - aa, outer + aa, d));
|
|
52
|
+
}
|
|
53
|
+
void main() {
|
|
54
|
+
float d = length(vLocal);
|
|
55
|
+
float aa = max(fwidth(d), 0.0008);
|
|
56
|
+
float discRadius = vStyle.x / max(vStyle.w, 0.0001);
|
|
57
|
+
float discAlpha = 1.0 - smoothstep(discRadius - aa, discRadius + aa, d);
|
|
58
|
+
int state = int(vStyle.z + 0.5);
|
|
59
|
+
vec4 ringColor = vec4(0.0);
|
|
60
|
+
float ringWidth = 0.0;
|
|
61
|
+
if (state == 1) { ringColor = uHoverRing; ringWidth = uHoverRingWidth; }
|
|
62
|
+
else if (state == 2 || state == 3) { ringColor = uSelectedRing; ringWidth = uSelectedRingWidth; }
|
|
63
|
+
else if (state == 4) { ringColor = uFixedRing; ringWidth = uFixedRingWidth; }
|
|
64
|
+
float ringOuter = discRadius + ringWidth / max(uZoom * vStyle.w, 0.0001);
|
|
65
|
+
float ring = ringWidth > 0.0 ? band(d, discRadius, ringOuter, aa) : 0.0;
|
|
66
|
+
if (discAlpha <= 0.0 && ring <= 0.0) discard;
|
|
67
|
+
vec4 fill = vFill;
|
|
68
|
+
if (vImageActive > 0.5) {
|
|
69
|
+
vec4 image = texture(uAtlas, vAtlasUv);
|
|
70
|
+
fill.rgb = mix(fill.rgb, image.rgb, image.a);
|
|
71
|
+
}
|
|
72
|
+
float borderSize = vStyle.y / max(uZoom * vStyle.w, 0.0001);
|
|
73
|
+
float border = vStyle.y > 0.0 ? band(d, max(0.0, discRadius - borderSize), discRadius, aa) : 0.0;
|
|
74
|
+
vec4 core = mix(fill, vec4(vBorder.rgb, vBorder.a * vStyle.y), border);
|
|
75
|
+
core.a *= discAlpha * (state == 5 ? uDisabledOpacity : 1.0);
|
|
76
|
+
vec4 halo = vec4(ringColor.rgb, ringColor.a * ring);
|
|
77
|
+
outColor = vec4(mix(halo.rgb, core.rgb, core.a), core.a + halo.a * (1.0 - core.a));
|
|
78
|
+
}`;
|
|
79
|
+
export const EDGE_VERTEX = `#version 300 es
|
|
80
|
+
precision highp float;
|
|
81
|
+
layout(location=0) in vec2 aCorner;
|
|
82
|
+
layout(location=1) in vec4 aSegment;
|
|
83
|
+
layout(location=2) in vec4 aColor;
|
|
84
|
+
layout(location=3) in vec4 aStyle;
|
|
85
|
+
layout(location=4) in vec4 aMeta;
|
|
86
|
+
uniform mat3 uCamera;
|
|
87
|
+
uniform float uZoom;
|
|
88
|
+
out float vSide;
|
|
89
|
+
out float vDashPosition;
|
|
90
|
+
out vec4 vColor;
|
|
91
|
+
out vec2 vDashPattern;
|
|
92
|
+
flat out float vDashed;
|
|
93
|
+
void main() {
|
|
94
|
+
vec2 p0 = aSegment.xy;
|
|
95
|
+
vec2 p1 = aSegment.zw;
|
|
96
|
+
vec2 chord = p1 - p0;
|
|
97
|
+
float chordLength = max(length(chord), 0.00001);
|
|
98
|
+
float curvature = aMeta.x;
|
|
99
|
+
vec2 mid = (p0 + p1) * 0.5;
|
|
100
|
+
vec2 control = mid + vec2(-chord.y, chord.x) / chordLength * (curvature * chordLength * 0.35);
|
|
101
|
+
float t = (aCorner.x + 1.0) * 0.5;
|
|
102
|
+
float u = 1.0 - t;
|
|
103
|
+
vec2 point = u * u * p0 + 2.0 * u * t * control + t * t * p1;
|
|
104
|
+
vec2 tangent = 2.0 * u * (control - p0) + 2.0 * t * (p1 - control);
|
|
105
|
+
float tangentLength = max(length(tangent), 0.00001);
|
|
106
|
+
vec2 normal = vec2(-tangent.y, tangent.x) / tangentLength;
|
|
107
|
+
float widthWorld = aStyle.x / max(uZoom, 0.0001);
|
|
108
|
+
vec2 world = point + normal * aCorner.y * widthWorld * 0.5;
|
|
109
|
+
gl_Position = vec4((uCamera * vec3(world, 1.0)).xy, 0.0, 1.0);
|
|
110
|
+
vSide = aCorner.y;
|
|
111
|
+
float dashScale = aMeta.z > 0.5 ? 1.0 : uZoom;
|
|
112
|
+
vDashPosition = (t * aMeta.w) * dashScale + aStyle.w;
|
|
113
|
+
vColor = aColor;
|
|
114
|
+
vDashPattern = aStyle.yz;
|
|
115
|
+
vDashed = aMeta.y;
|
|
116
|
+
}`;
|
|
117
|
+
export const EDGE_FRAGMENT = `#version 300 es
|
|
118
|
+
precision highp float;
|
|
119
|
+
in float vSide;
|
|
120
|
+
in float vDashPosition;
|
|
121
|
+
in vec4 vColor;
|
|
122
|
+
in vec2 vDashPattern;
|
|
123
|
+
flat in float vDashed;
|
|
124
|
+
out vec4 outColor;
|
|
125
|
+
void main() {
|
|
126
|
+
float edgeAA = max(fwidth(vSide), 0.002);
|
|
127
|
+
float alpha = 1.0 - smoothstep(1.0 - edgeAA, 1.0 + edgeAA, abs(vSide));
|
|
128
|
+
if (vDashed > 0.5) {
|
|
129
|
+
float cycle = max(0.5, vDashPattern.x + vDashPattern.y);
|
|
130
|
+
float phase = mod(vDashPosition, cycle);
|
|
131
|
+
float dashAA = max(fwidth(vDashPosition), 0.3);
|
|
132
|
+
alpha *= 1.0 - smoothstep(vDashPattern.x - dashAA, vDashPattern.x + dashAA, phase);
|
|
133
|
+
}
|
|
134
|
+
if (alpha <= 0.0) discard;
|
|
135
|
+
outColor = vec4(vColor.rgb, vColor.a * alpha);
|
|
136
|
+
}`;
|
|
137
|
+
export const ARROW_VERTEX = `#version 300 es
|
|
138
|
+
precision highp float;
|
|
139
|
+
layout(location=0) in vec2 aCorner;
|
|
140
|
+
layout(location=1) in vec4 aArrow;
|
|
141
|
+
layout(location=2) in vec4 aColor;
|
|
142
|
+
layout(location=3) in float aHalfWidth;
|
|
143
|
+
uniform mat3 uCamera;
|
|
144
|
+
out vec2 vLocal;
|
|
145
|
+
flat out float vLength;
|
|
146
|
+
flat out float vHalfWidth;
|
|
147
|
+
out vec4 vColor;
|
|
148
|
+
void main() {
|
|
149
|
+
vec2 base = aArrow.xy;
|
|
150
|
+
vec2 tip = aArrow.zw;
|
|
151
|
+
vec2 direction = tip - base;
|
|
152
|
+
float worldLength = max(length(direction), 0.00001);
|
|
153
|
+
vec2 dirNorm = direction / worldLength;
|
|
154
|
+
vec2 normal = vec2(-dirNorm.y, dirNorm.x);
|
|
155
|
+
float t = (aCorner.x + 1.0) * 0.5;
|
|
156
|
+
vec2 world = base + dirNorm * (t * worldLength) + normal * aCorner.y * aHalfWidth * (1.0 - t);
|
|
157
|
+
gl_Position = vec4((uCamera * vec3(world, 1.0)).xy, 0.0, 1.0);
|
|
158
|
+
vLocal = vec2(t * worldLength, aCorner.y * aHalfWidth * (1.0 - t));
|
|
159
|
+
vLength = worldLength;
|
|
160
|
+
vHalfWidth = aHalfWidth;
|
|
161
|
+
vColor = aColor;
|
|
162
|
+
}`;
|
|
163
|
+
export const ARROW_FRAGMENT = `#version 300 es
|
|
164
|
+
precision highp float;
|
|
165
|
+
in vec2 vLocal;
|
|
166
|
+
flat in float vLength;
|
|
167
|
+
flat in float vHalfWidth;
|
|
168
|
+
in vec4 vColor;
|
|
169
|
+
out vec4 outColor;
|
|
170
|
+
void main() {
|
|
171
|
+
float u = vLocal.x;
|
|
172
|
+
float v = vLocal.y;
|
|
173
|
+
float L = vLength;
|
|
174
|
+
float W = vHalfWidth;
|
|
175
|
+
if (L <= 0.00001) discard;
|
|
176
|
+
float dEdges = (W * L - W * u - abs(v) * L) / length(vec2(L, W));
|
|
177
|
+
float d = min(u, dEdges);
|
|
178
|
+
float aa = max(fwidth(d), 0.002);
|
|
179
|
+
float alpha = smoothstep(-aa, aa, d);
|
|
180
|
+
if (alpha <= 0.0) discard;
|
|
181
|
+
outColor = vec4(vColor.rgb, vColor.a * alpha);
|
|
182
|
+
}`;
|
|
183
|
+
//# sourceMappingURL=shaders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shaders.js","sourceRoot":"","sources":["../../src/render/shaders.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;EAwBzB,CAAC;AAEH,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8C3B,CAAC;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqCzB,CAAC;AAEH,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;EAmB3B,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;EAyB1B,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;EAmB5B,CAAC"}
|