@bruno00o/graph 0.3.0 → 0.4.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/README.md +2 -2
- package/dist/db.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/{mount-graph-DQLST9-_.d.ts → mount-graph-Br5IAZbP.d.ts} +2 -2
- package/dist/{mount-graph-CzVfiIte.js → mount-graph-mObhwJ3e.js} +279 -170
- package/dist/mount-graph-mObhwJ3e.js.map +1 -0
- package/dist/query.d.ts +1 -1
- package/dist/react.d.ts +2 -2
- package/dist/react.js +1 -1
- package/dist/theme.css +3 -0
- package/dist/{types-BaflHDaf.d.ts → types-DJEdpHUo.d.ts} +6 -1
- package/package.json +1 -1
- package/dist/mount-graph-CzVfiIte.js.map +0 -1
|
@@ -835,10 +835,13 @@ function compileNodeMark(mark) {
|
|
|
835
835
|
y: channel(options.y),
|
|
836
836
|
label: channel(typeof label === "object" ? label.text : label),
|
|
837
837
|
secondary: channel(typeof label === "object" ? label.secondary : void 0),
|
|
838
|
+
labelBackground: style(typeof label === "object" ? label.background : void 0),
|
|
838
839
|
shape: style(options.shape),
|
|
839
840
|
fill: style(options.fill),
|
|
840
841
|
stroke: style(options.stroke),
|
|
841
842
|
strokeWidth: style(options.strokeWidth),
|
|
843
|
+
outline: style(options.outline),
|
|
844
|
+
outlineWidth: style(options.outlineWidth),
|
|
842
845
|
opacity: style(options.opacity),
|
|
843
846
|
image: style(options.image),
|
|
844
847
|
badges,
|
|
@@ -1001,6 +1004,7 @@ const lightTheme = {
|
|
|
1001
1004
|
"focus-ring": "#c93700",
|
|
1002
1005
|
halo: "#c9370047",
|
|
1003
1006
|
"label-halo": "#f7f7f4",
|
|
1007
|
+
"label-background": "#ffffff",
|
|
1004
1008
|
"node-ring": "#f7f7f4",
|
|
1005
1009
|
"badge-fill": "#191d22",
|
|
1006
1010
|
"badge-ink": "#f7f7f4",
|
|
@@ -1025,6 +1029,9 @@ const defaults = {
|
|
|
1025
1029
|
nodeFill: themeColor("node"),
|
|
1026
1030
|
nodeStroke: themeColor("node-ring"),
|
|
1027
1031
|
nodeStrokeWidth: 1,
|
|
1032
|
+
nodeOutline: themeColor("node-ring"),
|
|
1033
|
+
nodeOutlineWidth: 2,
|
|
1034
|
+
labelBackground: themeColor("label-background"),
|
|
1028
1035
|
edgeWidth: 1.5,
|
|
1029
1036
|
edgeWidthRange: [1, 6],
|
|
1030
1037
|
edgeColor: themeColor("edge"),
|
|
@@ -1212,6 +1219,11 @@ function grow$1(array, length) {
|
|
|
1212
1219
|
next.set(array);
|
|
1213
1220
|
return next;
|
|
1214
1221
|
}
|
|
1222
|
+
function growColor(array, length) {
|
|
1223
|
+
const next = new Uint32Array(length).fill(noColor);
|
|
1224
|
+
next.set(array);
|
|
1225
|
+
return next;
|
|
1226
|
+
}
|
|
1215
1227
|
function nextCapacity(capacity, index) {
|
|
1216
1228
|
return Math.max(64, capacity * 2, index + 1);
|
|
1217
1229
|
}
|
|
@@ -1225,10 +1237,13 @@ var NodeColumns = class {
|
|
|
1225
1237
|
fill = /* @__PURE__ */ new Uint32Array(0);
|
|
1226
1238
|
stroke = /* @__PURE__ */ new Uint32Array(0);
|
|
1227
1239
|
strokeWidth = /* @__PURE__ */ new Float32Array(0);
|
|
1240
|
+
outline = /* @__PURE__ */ new Uint32Array(0);
|
|
1241
|
+
outlineWidth = /* @__PURE__ */ new Float32Array(0);
|
|
1228
1242
|
opacity = /* @__PURE__ */ new Float32Array(0);
|
|
1229
1243
|
screenUnits = /* @__PURE__ */ new Uint8Array(0);
|
|
1230
1244
|
label = [];
|
|
1231
1245
|
secondary = [];
|
|
1246
|
+
labelBackground = /* @__PURE__ */ new Uint32Array(0);
|
|
1232
1247
|
image = [];
|
|
1233
1248
|
imageScale = /* @__PURE__ */ new Float32Array(0);
|
|
1234
1249
|
imageColor = /* @__PURE__ */ new Uint32Array(0);
|
|
@@ -1243,10 +1258,13 @@ var NodeColumns = class {
|
|
|
1243
1258
|
this.fill = grow$1(this.fill, capacity);
|
|
1244
1259
|
this.stroke = grow$1(this.stroke, capacity);
|
|
1245
1260
|
this.strokeWidth = grow$1(this.strokeWidth, capacity);
|
|
1261
|
+
this.outline = grow$1(this.outline, capacity);
|
|
1262
|
+
this.outlineWidth = grow$1(this.outlineWidth, capacity);
|
|
1246
1263
|
this.opacity = grow$1(this.opacity, capacity);
|
|
1247
1264
|
this.screenUnits = grow$1(this.screenUnits, capacity);
|
|
1265
|
+
this.labelBackground = growColor(this.labelBackground, capacity);
|
|
1248
1266
|
this.imageScale = grow$1(this.imageScale, capacity);
|
|
1249
|
-
this.imageColor =
|
|
1267
|
+
this.imageColor = growColor(this.imageColor, capacity);
|
|
1250
1268
|
this.capacity = capacity;
|
|
1251
1269
|
}
|
|
1252
1270
|
clear(index) {
|
|
@@ -1532,6 +1550,11 @@ function readBadges(mark, datum, palette) {
|
|
|
1532
1550
|
}
|
|
1533
1551
|
return badges.length === 0 ? null : badges;
|
|
1534
1552
|
}
|
|
1553
|
+
function readBackground(value, palette) {
|
|
1554
|
+
if (value === true) return palette.id(defaults.labelBackground);
|
|
1555
|
+
const color = toColor(value);
|
|
1556
|
+
return color ? palette.id(color) : noColor;
|
|
1557
|
+
}
|
|
1535
1558
|
function readImage(value) {
|
|
1536
1559
|
if (typeof value === "string") return value === "" ? null : {
|
|
1537
1560
|
src: value,
|
|
@@ -1631,10 +1654,14 @@ function createScene() {
|
|
|
1631
1654
|
nodes.fill[index] = palette.id(fill);
|
|
1632
1655
|
nodes.stroke[index] = palette.id(toColor(mark.stroke?.(datum)) ?? defaults.nodeStroke);
|
|
1633
1656
|
nodes.strokeWidth[index] = finiteOr(mark.strokeWidth?.(datum), defaults.nodeStrokeWidth);
|
|
1657
|
+
const outline = mark.outline ? toColor(mark.outline(datum)) : null;
|
|
1658
|
+
nodes.outline[index] = palette.id(outline ?? defaults.nodeOutline);
|
|
1659
|
+
nodes.outlineWidth[index] = mark.outline && !outline ? 0 : Math.max(0, finiteOr(mark.outlineWidth?.(datum), outline ? defaults.nodeOutlineWidth : 0));
|
|
1634
1660
|
nodes.opacity[index] = Math.min(1, Math.max(0, finiteOr(mark.opacity?.(datum), 1)));
|
|
1635
1661
|
nodes.screenUnits[index] = mark.screenUnits ? 1 : 0;
|
|
1636
1662
|
nodes.label[index] = toText(mark.label?.(datum));
|
|
1637
1663
|
nodes.secondary[index] = toText(mark.secondary?.(datum));
|
|
1664
|
+
nodes.labelBackground[index] = readBackground(mark.labelBackground?.(datum), palette);
|
|
1638
1665
|
const image = readImage(mark.image?.(datum));
|
|
1639
1666
|
nodes.image[index] = image?.src ?? null;
|
|
1640
1667
|
nodes.imageScale[index] = image?.scale ?? 1;
|
|
@@ -1840,6 +1867,12 @@ var DirtyRange = class {
|
|
|
1840
1867
|
return range;
|
|
1841
1868
|
}
|
|
1842
1869
|
};
|
|
1870
|
+
const bits = /* @__PURE__ */ new Float32Array(1);
|
|
1871
|
+
const word = new Uint32Array(bits.buffer);
|
|
1872
|
+
function floatWord(value) {
|
|
1873
|
+
bits[0] = value;
|
|
1874
|
+
return word[0] ?? 0;
|
|
1875
|
+
}
|
|
1843
1876
|
function grow(array, capacity) {
|
|
1844
1877
|
if (capacity <= array.length) return array;
|
|
1845
1878
|
const next = new Uint32Array(Math.max(capacity, array.length * 2));
|
|
@@ -1882,6 +1915,8 @@ var StateBuffers = class {
|
|
|
1882
1915
|
this.numbers[at + 3] = style?.label === void 0 ? -1 : style.label ? 1 : 0;
|
|
1883
1916
|
this.paint[at] = style?.fill ?? 4294967295;
|
|
1884
1917
|
this.paint[at + 1] = style?.stroke ?? 4294967295;
|
|
1918
|
+
this.paint[at + 2] = style?.outline ?? 4294967295;
|
|
1919
|
+
this.paint[at + 3] = style?.outlineWidth === void 0 ? noPaint : floatWord(Math.max(0, style.outlineWidth));
|
|
1885
1920
|
if (kind === "nodes") this.labelFlags[bit] = this.numbers[at + 3] ?? -1;
|
|
1886
1921
|
this.tableVersion++;
|
|
1887
1922
|
}
|
|
@@ -2450,149 +2485,12 @@ var ImageAtlas = class {
|
|
|
2450
2485
|
return true;
|
|
2451
2486
|
}
|
|
2452
2487
|
};
|
|
2453
|
-
const primarySize = 12;
|
|
2454
|
-
const lineHeight = 1.25;
|
|
2455
|
-
const labelMin = 8;
|
|
2456
|
-
const cell = 8;
|
|
2457
|
-
const maxLabels = 4e3;
|
|
2458
|
-
const cullMargin = 400;
|
|
2459
|
-
const forcedStates = 6;
|
|
2460
|
-
var GlyphBuffer = class {
|
|
2461
|
-
data = /* @__PURE__ */ new ArrayBuffer(8192);
|
|
2462
|
-
count = 0;
|
|
2463
|
-
#u32 = new Uint32Array(this.data);
|
|
2464
|
-
#f32 = new Float32Array(this.data);
|
|
2465
|
-
#u16 = new Uint16Array(this.data);
|
|
2466
|
-
clear() {
|
|
2467
|
-
this.count = 0;
|
|
2468
|
-
}
|
|
2469
|
-
push(node, kind, line, atlasHeight) {
|
|
2470
|
-
for (const { glyph, x } of line.glyphs) {
|
|
2471
|
-
if ((this.count + 1) * 32 > this.data.byteLength) this.#grow();
|
|
2472
|
-
const at = this.count * 8;
|
|
2473
|
-
this.#u32[at] = node;
|
|
2474
|
-
this.#u32[at + 1] = kind;
|
|
2475
|
-
this.#f32[at + 2] = x;
|
|
2476
|
-
this.#f32[at + 3] = glyph.top;
|
|
2477
|
-
this.#f32[at + 4] = glyph.width;
|
|
2478
|
-
this.#f32[at + 5] = glyph.height;
|
|
2479
|
-
const uv = at * 2 + 12;
|
|
2480
|
-
this.#u16[uv] = Math.round(glyph.x / atlasWidth * 65535);
|
|
2481
|
-
this.#u16[uv + 1] = Math.round(glyph.y / atlasHeight * 65535);
|
|
2482
|
-
this.#u16[uv + 2] = Math.round((glyph.x + glyph.width) / atlasWidth * 65535);
|
|
2483
|
-
this.#u16[uv + 3] = Math.round((glyph.y + glyph.height) / atlasHeight * 65535);
|
|
2484
|
-
this.count++;
|
|
2485
|
-
}
|
|
2486
|
-
}
|
|
2487
|
-
#grow() {
|
|
2488
|
-
const data = /* @__PURE__ */ new ArrayBuffer(this.data.byteLength * 2);
|
|
2489
|
-
new Uint8Array(data).set(new Uint8Array(this.data));
|
|
2490
|
-
this.data = data;
|
|
2491
|
-
this.#u32 = new Uint32Array(data);
|
|
2492
|
-
this.#f32 = new Float32Array(data);
|
|
2493
|
-
this.#u16 = new Uint16Array(data);
|
|
2494
|
-
}
|
|
2495
|
-
};
|
|
2496
|
-
function labelVisible(mask, flags) {
|
|
2497
|
-
let bits = mask >>> 0;
|
|
2498
|
-
while (bits !== 0) {
|
|
2499
|
-
const bit = 31 - Math.clz32(bits & -bits);
|
|
2500
|
-
bits &= bits - 1;
|
|
2501
|
-
const flag = flags[bit] ?? -1;
|
|
2502
|
-
if (flag >= 0) return flag === 1;
|
|
2503
|
-
}
|
|
2504
|
-
return true;
|
|
2505
|
-
}
|
|
2506
|
-
var LabelLayer = class {
|
|
2507
|
-
main = new GlyphBuffer();
|
|
2508
|
-
highlight = new GlyphBuffer();
|
|
2509
|
-
#occupancy = /* @__PURE__ */ new Uint8Array(0);
|
|
2510
|
-
select(frame, atlas) {
|
|
2511
|
-
this.main.clear();
|
|
2512
|
-
this.highlight.clear();
|
|
2513
|
-
const { nodes, positions, view, width, height } = frame;
|
|
2514
|
-
const cols = Math.ceil(width / cell) + 1;
|
|
2515
|
-
const rows = Math.ceil(height / cell) + 1;
|
|
2516
|
-
if (this.#occupancy.length < cols * rows) this.#occupancy = new Uint8Array(cols * rows);
|
|
2517
|
-
else this.#occupancy.fill(0, 0, cols * rows);
|
|
2518
|
-
const occupancy = this.#occupancy;
|
|
2519
|
-
const highlighted = new Set(frame.highlighted);
|
|
2520
|
-
const worldPrimary = primarySize * Math.min(1, view.zoom);
|
|
2521
|
-
let placed = 0;
|
|
2522
|
-
const forced = (index) => ((frame.nodeMask[index] ?? 0) & forcedStates) !== 0;
|
|
2523
|
-
const place = (index, highlight) => {
|
|
2524
|
-
const force = highlight && forced(index);
|
|
2525
|
-
const label = nodes.label[index];
|
|
2526
|
-
if (!label || nodes.alive[index] !== 1) return;
|
|
2527
|
-
if (!labelVisible(frame.nodeMask[index] ?? 0, frame.labelFlags)) return;
|
|
2528
|
-
const screenUnits = nodes.screenUnits[index] === 1;
|
|
2529
|
-
const primary = screenUnits ? primarySize : worldPrimary;
|
|
2530
|
-
if (primary < labelMin) return;
|
|
2531
|
-
const diameter = screenUnits ? nodes.size[index] ?? 0 : (nodes.size[index] ?? 0) * view.zoom;
|
|
2532
|
-
const radius = Math.max(diameter / 2, 1.25);
|
|
2533
|
-
const x = (positions.x(index) - view.x) * view.zoom + width / 2;
|
|
2534
|
-
const y = (positions.y(index) - view.y) * view.zoom + height / 2;
|
|
2535
|
-
if (x < -400 || x > width + cullMargin) return;
|
|
2536
|
-
if (y + radius > height || y + radius + primary * lineHeight * 2 < -3) return;
|
|
2537
|
-
const line = atlas.line(label, "500");
|
|
2538
|
-
const secondaryText = nodes.secondary[index];
|
|
2539
|
-
const secondary = secondaryText ? atlas.line(secondaryText, "400") : null;
|
|
2540
|
-
const scale = primary / 24;
|
|
2541
|
-
const textWidth = Math.max(line.width * scale, secondary ? secondary.width * scale * 11 / 12 : 0);
|
|
2542
|
-
const top = y + radius + 3;
|
|
2543
|
-
const bottom = top + primary * lineHeight * (secondary ? 2 : 1);
|
|
2544
|
-
const left = x - textWidth / 2;
|
|
2545
|
-
const right = x + textWidth / 2;
|
|
2546
|
-
if (right < 0 || left > width || bottom < 0 || top > height) return;
|
|
2547
|
-
const c0 = Math.max(0, Math.floor(left / cell));
|
|
2548
|
-
const c1 = Math.min(cols - 1, Math.floor(right / cell));
|
|
2549
|
-
const r0 = Math.max(0, Math.floor(top / cell));
|
|
2550
|
-
const r1 = Math.min(rows - 1, Math.floor(bottom / cell));
|
|
2551
|
-
if (!force) {
|
|
2552
|
-
for (let row = r0; row <= r1; row++) for (let col = c0; col <= c1; col++) if (occupancy[row * cols + col] === 1) return;
|
|
2553
|
-
}
|
|
2554
|
-
for (let row = r0; row <= r1; row++) occupancy.fill(1, row * cols + c0, row * cols + c1 + 1);
|
|
2555
|
-
const target = highlight ? this.highlight : this.main;
|
|
2556
|
-
target.push(index, 0, line, atlas.height);
|
|
2557
|
-
if (secondary) target.push(index, 1, secondary, atlas.height);
|
|
2558
|
-
placed++;
|
|
2559
|
-
};
|
|
2560
|
-
for (const index of highlighted) if (forced(index)) place(index, true);
|
|
2561
|
-
for (const index of highlighted) if (!forced(index)) place(index, true);
|
|
2562
|
-
if (worldPrimary < labelMin && !frame.screenLabels) return;
|
|
2563
|
-
const xy = positions.xy;
|
|
2564
|
-
const order = frame.order;
|
|
2565
|
-
const left = view.x - (width / 2 + cullMargin) / view.zoom;
|
|
2566
|
-
const right = view.x + (width / 2 + cullMargin) / view.zoom;
|
|
2567
|
-
const largest = nodes.size[order[0] ?? 0] ?? 0;
|
|
2568
|
-
const reach = cullMargin + (frame.screenLabels ? largest : largest * view.zoom) / 2;
|
|
2569
|
-
const top = view.y - (height / 2 + reach) / view.zoom;
|
|
2570
|
-
const bottom = view.y + height / 2 / view.zoom;
|
|
2571
|
-
for (let at = 0; at < frame.orderLength && placed < maxLabels; at++) {
|
|
2572
|
-
const index = order[at] ?? 0;
|
|
2573
|
-
const x = xy[index * 2] ?? 0;
|
|
2574
|
-
const y = xy[index * 2 + 1] ?? 0;
|
|
2575
|
-
if (x < left || x > right || y < top || y > bottom) continue;
|
|
2576
|
-
if (!highlighted.has(index)) place(index, false);
|
|
2577
|
-
}
|
|
2578
|
-
}
|
|
2579
|
-
};
|
|
2580
|
-
function sortBySize(nodes, order) {
|
|
2581
|
-
let length = 0;
|
|
2582
|
-
let screenLabels = false;
|
|
2583
|
-
for (let index = 0; index < nodes.capacity; index++) if (nodes.alive[index] === 1 && nodes.label[index]) {
|
|
2584
|
-
order[length++] = index;
|
|
2585
|
-
if (nodes.screenUnits[index] === 1) screenLabels = true;
|
|
2586
|
-
}
|
|
2587
|
-
const sizes = nodes.size;
|
|
2588
|
-
order.subarray(0, length).sort((a, b) => (sizes[b] ?? 0) - (sizes[a] ?? 0));
|
|
2589
|
-
return {
|
|
2590
|
-
length,
|
|
2591
|
-
screenLabels
|
|
2592
|
-
};
|
|
2593
|
-
}
|
|
2594
2488
|
const badgeFont = .66;
|
|
2595
2489
|
const badgeRing = 1.5;
|
|
2490
|
+
const platePadX = .45;
|
|
2491
|
+
const plateHalfOne = .75;
|
|
2492
|
+
const plateHalfTwo = 1.32;
|
|
2493
|
+
const plateRadius = .25;
|
|
2596
2494
|
const header = `#version 300 es
|
|
2597
2495
|
precision highp float;
|
|
2598
2496
|
precision highp int;
|
|
@@ -2627,7 +2525,7 @@ vec4 toClip(vec2 screen) {
|
|
|
2627
2525
|
}
|
|
2628
2526
|
ivec2 texel(uint index) { return ivec2(int(index & 1023u), int(index >> 10u)); }
|
|
2629
2527
|
vec4 paletteColor(uint id) { return texelFetch(palette, ivec2(int(id & 255u), int(id >> 8u)), 0); }
|
|
2630
|
-
struct Look { float opacity; float strokeWidth; float halo; float label; uint fill; uint stroke; };
|
|
2528
|
+
struct Look { float opacity; float strokeWidth; float halo; float label; uint fill; uint stroke; uint outline; float outlineWidth; };
|
|
2631
2529
|
Look resolve(uint mask, Look look, int table) {
|
|
2632
2530
|
bool opacity = false;
|
|
2633
2531
|
bool strokeWidth = false;
|
|
@@ -2635,6 +2533,8 @@ Look resolve(uint mask, Look look, int table) {
|
|
|
2635
2533
|
bool label = false;
|
|
2636
2534
|
bool fill = false;
|
|
2637
2535
|
bool stroke = false;
|
|
2536
|
+
bool outline = false;
|
|
2537
|
+
bool outlineWidth = false;
|
|
2638
2538
|
float base = look.opacity;
|
|
2639
2539
|
for (int bit = 0; bit < 32; bit++) {
|
|
2640
2540
|
if (mask == 0u) break;
|
|
@@ -2649,6 +2549,8 @@ Look resolve(uint mask, Look look, int table) {
|
|
|
2649
2549
|
if (!label && numbers.w >= 0.0) { look.label = numbers.w; label = true; }
|
|
2650
2550
|
if (!fill && paint.x != none) { look.fill = paint.x; fill = true; }
|
|
2651
2551
|
if (!stroke && paint.y != none) { look.stroke = paint.y; stroke = true; }
|
|
2552
|
+
if (!outline && paint.z != none) { look.outline = paint.z; outline = true; }
|
|
2553
|
+
if (!outlineWidth && paint.w != none) { look.outlineWidth = uintBitsToFloat(paint.w); outlineWidth = true; }
|
|
2652
2554
|
}
|
|
2653
2555
|
return look;
|
|
2654
2556
|
}
|
|
@@ -2658,6 +2560,11 @@ uniform sampler2D nodePosition;
|
|
|
2658
2560
|
uniform sampler2D nodeStyle;
|
|
2659
2561
|
uniform usampler2D nodePaint;
|
|
2660
2562
|
uniform usampler2D nodeState;
|
|
2563
|
+
uniform usampler2D nodeDecor;
|
|
2564
|
+
Look nodeLook(ivec2 t, vec4 style, uvec4 paint, uint mask) {
|
|
2565
|
+
float outlineWidth = uintBitsToFloat(texelFetch(nodeDecor, t, 0).w);
|
|
2566
|
+
return resolve(mask, Look(style.z, style.y, 0.0, 1.0, paint.x, paint.y, paint.w, outlineWidth), 0);
|
|
2567
|
+
}
|
|
2661
2568
|
float nodeDiameter(vec4 style) {
|
|
2662
2569
|
uint flags = uint(style.w + 0.5);
|
|
2663
2570
|
return (flags & 4u) != 0u ? style.x : style.x * zoom;
|
|
@@ -2677,7 +2584,6 @@ uniform sampler2D edgeStyle;
|
|
|
2677
2584
|
uniform usampler2D edgeState;
|
|
2678
2585
|
`;
|
|
2679
2586
|
const nodeVertex = `${header}${nodeData}
|
|
2680
|
-
uniform usampler2D nodeImage;
|
|
2681
2587
|
in vec2 corner;
|
|
2682
2588
|
in uint instance;
|
|
2683
2589
|
out vec2 vLocal;
|
|
@@ -2687,9 +2593,11 @@ flat out vec4 vImageColor;
|
|
|
2687
2593
|
out float vRadius;
|
|
2688
2594
|
out float vStrokeWidth;
|
|
2689
2595
|
out float vHaloWidth;
|
|
2596
|
+
out float vOutlineWidth;
|
|
2690
2597
|
flat out uint vShape;
|
|
2691
2598
|
flat out vec4 vFill;
|
|
2692
2599
|
flat out vec4 vStroke;
|
|
2600
|
+
flat out vec4 vOutline;
|
|
2693
2601
|
flat out float vOpacity;
|
|
2694
2602
|
void main() {
|
|
2695
2603
|
ivec2 t = texel(instance);
|
|
@@ -2702,19 +2610,22 @@ void main() {
|
|
|
2702
2610
|
gl_Position = hidden;
|
|
2703
2611
|
return;
|
|
2704
2612
|
}
|
|
2705
|
-
Look look =
|
|
2613
|
+
Look look = nodeLook(t, style, paint, mask);
|
|
2706
2614
|
vec2 xy = texelFetch(nodePosition, t, 0).xy;
|
|
2707
2615
|
float radius = nodeRadius(style);
|
|
2708
2616
|
float halo = look.halo > 0.5 ? haloWidth : 0.0;
|
|
2709
|
-
|
|
2617
|
+
float outline = max(look.outlineWidth, 0.0);
|
|
2618
|
+
vLocal = corner * (radius + outline + halo + 1.5);
|
|
2710
2619
|
vRadius = radius;
|
|
2711
2620
|
vStrokeWidth = min(look.strokeWidth, radius * 0.5);
|
|
2712
2621
|
vHaloWidth = halo;
|
|
2622
|
+
vOutlineWidth = outline;
|
|
2623
|
+
vOutline = paletteColor(look.outline);
|
|
2713
2624
|
vShape = flags & 3u;
|
|
2714
2625
|
vFill = paletteColor(look.fill);
|
|
2715
2626
|
vStroke = paletteColor(look.stroke);
|
|
2716
2627
|
vOpacity = look.opacity;
|
|
2717
|
-
uvec4 image = texelFetch(
|
|
2628
|
+
uvec4 image = texelFetch(nodeDecor, t, 0);
|
|
2718
2629
|
vImageLayer = float(image.x) - 1.0;
|
|
2719
2630
|
vImageScale = max(uintBitsToFloat(image.z), 0.001);
|
|
2720
2631
|
vImageColor = image.y == none ? vec4(-1.0) : paletteColor(image.y);
|
|
@@ -2730,9 +2641,11 @@ flat in vec4 vImageColor;
|
|
|
2730
2641
|
in float vRadius;
|
|
2731
2642
|
in float vStrokeWidth;
|
|
2732
2643
|
in float vHaloWidth;
|
|
2644
|
+
in float vOutlineWidth;
|
|
2733
2645
|
flat in uint vShape;
|
|
2734
2646
|
flat in vec4 vFill;
|
|
2735
2647
|
flat in vec4 vStroke;
|
|
2648
|
+
flat in vec4 vOutline;
|
|
2736
2649
|
flat in float vOpacity;
|
|
2737
2650
|
out vec4 fragColor;
|
|
2738
2651
|
float shapeDistance(vec2 p, float r) {
|
|
@@ -2759,8 +2672,12 @@ void main() {
|
|
|
2759
2672
|
}
|
|
2760
2673
|
vec4 color = mix(fill, vec4(vStroke.rgb * vStroke.a, vStroke.a), ring);
|
|
2761
2674
|
vec4 result = color * inside * vOpacity;
|
|
2675
|
+
if (vOutlineWidth > 0.0) {
|
|
2676
|
+
float outer = 1.0 - smoothstep(vOutlineWidth - aa, vOutlineWidth + aa, d);
|
|
2677
|
+
result = mix(vec4(vOutline.rgb * vOutline.a, vOutline.a), color, inside) * outer * vOpacity;
|
|
2678
|
+
}
|
|
2762
2679
|
if (vHaloWidth > 0.0) {
|
|
2763
|
-
float h = haloColor.a * (1.0 - smoothstep(0.0, vHaloWidth, d)) * vOpacity;
|
|
2680
|
+
float h = haloColor.a * (1.0 - smoothstep(0.0, vHaloWidth, d - vOutlineWidth)) * vOpacity;
|
|
2764
2681
|
result += vec4(haloColor.rgb * h, h) * (1.0 - result.a);
|
|
2765
2682
|
}
|
|
2766
2683
|
if (result.a < 0.002) discard;
|
|
@@ -2796,7 +2713,7 @@ void main() {
|
|
|
2796
2713
|
gl_Position = hidden;
|
|
2797
2714
|
return;
|
|
2798
2715
|
}
|
|
2799
|
-
Look look = resolve(mask, Look(style.y, style.x, 0.0, 1.0, none, topology.z), 32);
|
|
2716
|
+
Look look = resolve(mask, Look(style.y, style.x, 0.0, 1.0, none, topology.z, none, 0.0), 32);
|
|
2800
2717
|
ivec2 s = texel(topology.x);
|
|
2801
2718
|
ivec2 e = texel(topology.y);
|
|
2802
2719
|
vec2 ps = toScreen(texelFetch(nodePosition, s, 0).xy);
|
|
@@ -2898,7 +2815,7 @@ void main() {
|
|
|
2898
2815
|
gl_Position = hidden;
|
|
2899
2816
|
return;
|
|
2900
2817
|
}
|
|
2901
|
-
Look look = resolve(mask, Look(style.y, style.x, 0.0, 1.0, none, topology.z), 32);
|
|
2818
|
+
Look look = resolve(mask, Look(style.y, style.x, 0.0, 1.0, none, topology.z, none, 0.0), 32);
|
|
2902
2819
|
ivec2 s = texel(topology.x);
|
|
2903
2820
|
ivec2 e = texel(topology.y);
|
|
2904
2821
|
vec2 a = toScreen(texelFetch(nodePosition, s, 0).xy);
|
|
@@ -3043,14 +2960,16 @@ out vec2 vUv;
|
|
|
3043
2960
|
out float vScale;
|
|
3044
2961
|
flat out vec4 vInk;
|
|
3045
2962
|
flat out float vHalo;
|
|
2963
|
+
flat out vec4 vPlate;
|
|
3046
2964
|
flat out float vOpacity;
|
|
3047
2965
|
void main() {
|
|
2966
|
+
vPlate = vec4(0.0);
|
|
3048
2967
|
ivec2 t = texel(glyphNode);
|
|
3049
2968
|
vec4 style = texelFetch(nodeStyle, t, 0);
|
|
3050
2969
|
uvec4 paint = texelFetch(nodePaint, t, 0);
|
|
3051
2970
|
uint flags = uint(style.w + 0.5);
|
|
3052
2971
|
uint mask = texelFetch(nodeState, t, 0).r;
|
|
3053
|
-
Look look =
|
|
2972
|
+
Look look = nodeLook(t, style, paint, mask);
|
|
3054
2973
|
vUv = mix(glyphUv.xy, glyphUv.zw, corner);
|
|
3055
2974
|
vOpacity = look.opacity;
|
|
3056
2975
|
uint kind = glyphKind & 3u;
|
|
@@ -3074,13 +2993,28 @@ void main() {
|
|
|
3074
2993
|
gl_Position = hidden;
|
|
3075
2994
|
return;
|
|
3076
2995
|
}
|
|
2996
|
+
float below = nodeRadius(style) + max(look.outlineWidth, 0.0) + 3.0;
|
|
2997
|
+
vec2 top = toScreen(texelFetch(nodePosition, t, 0).xy) + vec2(0.0, below);
|
|
2998
|
+
if (kind == 3u) {
|
|
2999
|
+
bool two = glyphRect.y > 1.5;
|
|
3000
|
+
vec2 extent = vec2(
|
|
3001
|
+
glyphRect.x * primary / atlasFontSize * 0.5 + primary * ${platePadX.toFixed(2)},
|
|
3002
|
+
primary * (two ? ${plateHalfTwo.toFixed(2)} : ${plateHalfOne.toFixed(2)})
|
|
3003
|
+
);
|
|
3004
|
+
vUv = (corner * 2.0 - 1.0) * (extent + 1.0);
|
|
3005
|
+
vPlate = vec4(extent, primary * ${plateRadius.toFixed(2)}, 1.0);
|
|
3006
|
+
vScale = 1.0;
|
|
3007
|
+
vInk = paletteColor(glyphKind >> 4u);
|
|
3008
|
+
vHalo = 0.0;
|
|
3009
|
+
gl_Position = toClip(top + vec2(0.0, primary * (two ? ${plateHalfTwo.toFixed(2)} : ${plateHalfOne.toFixed(2)})) + vUv);
|
|
3010
|
+
return;
|
|
3011
|
+
}
|
|
3077
3012
|
float size = kind == 0u ? primary : primary * 11.0 / 12.0;
|
|
3078
3013
|
float scale = size / atlasFontSize;
|
|
3079
|
-
|
|
3080
|
-
vec2 anchor = toScreen(texelFetch(nodePosition, t, 0).xy) + vec2(0.0, below);
|
|
3014
|
+
vec2 anchor = top + vec2(0.0, kind == 1u ? primary * 1.25 : 0.0);
|
|
3081
3015
|
vScale = scale;
|
|
3082
3016
|
vInk = kind == 0u ? labelInk : labelMuted;
|
|
3083
|
-
vHalo = 1.0;
|
|
3017
|
+
vHalo = (glyphKind & 4u) != 0u ? 0.0 : 1.0;
|
|
3084
3018
|
gl_Position = toClip(anchor + (glyphRect.xy + corner * glyphRect.zw) * scale);
|
|
3085
3019
|
}
|
|
3086
3020
|
`;
|
|
@@ -3090,9 +3024,19 @@ in vec2 vUv;
|
|
|
3090
3024
|
in float vScale;
|
|
3091
3025
|
flat in vec4 vInk;
|
|
3092
3026
|
flat in float vHalo;
|
|
3027
|
+
flat in vec4 vPlate;
|
|
3093
3028
|
flat in float vOpacity;
|
|
3094
3029
|
out vec4 fragColor;
|
|
3095
3030
|
void main() {
|
|
3031
|
+
if (vPlate.w > 0.5) {
|
|
3032
|
+
vec2 q = abs(vUv) - vPlate.xy + vPlate.z;
|
|
3033
|
+
float edge = length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - vPlate.z;
|
|
3034
|
+
float aa = 0.5 / pixelRatio + 0.25;
|
|
3035
|
+
float cover = vInk.a * (1.0 - smoothstep(-aa, aa, edge)) * vOpacity;
|
|
3036
|
+
if (cover < 0.002) discard;
|
|
3037
|
+
fragColor = vec4(vInk.rgb * cover, cover);
|
|
3038
|
+
return;
|
|
3039
|
+
}
|
|
3096
3040
|
float d = texture(atlas, vUv).r;
|
|
3097
3041
|
float gamma = 0.08 / max(vScale * pixelRatio, 0.05);
|
|
3098
3042
|
float ink = smoothstep(0.75 - gamma, 0.75 + gamma, d);
|
|
@@ -3127,7 +3071,7 @@ void main() {
|
|
|
3127
3071
|
gl_Position = hidden;
|
|
3128
3072
|
return;
|
|
3129
3073
|
}
|
|
3130
|
-
Look look =
|
|
3074
|
+
Look look = nodeLook(t, style, paint, mask);
|
|
3131
3075
|
bool text = (badgeInfo & 4u) != 0u && height >= ${12 .toFixed(1)};
|
|
3132
3076
|
float font = height * ${badgeFont.toFixed(2)};
|
|
3133
3077
|
float width = text ? max(height, badgeText * font / ${24 .toFixed(1)} + height * 0.6) : height;
|
|
@@ -3239,6 +3183,166 @@ const cornerLabel = new Float32Array([
|
|
|
3239
3183
|
1,
|
|
3240
3184
|
1
|
|
3241
3185
|
]);
|
|
3186
|
+
const primarySize = 12;
|
|
3187
|
+
const lineHeight = 1.25;
|
|
3188
|
+
const labelMin = 8;
|
|
3189
|
+
const cell = 8;
|
|
3190
|
+
const maxLabels = 4e3;
|
|
3191
|
+
const cullMargin = 400;
|
|
3192
|
+
const forcedStates = 6;
|
|
3193
|
+
var GlyphBuffer = class {
|
|
3194
|
+
data = /* @__PURE__ */ new ArrayBuffer(8192);
|
|
3195
|
+
count = 0;
|
|
3196
|
+
#u32 = new Uint32Array(this.data);
|
|
3197
|
+
#f32 = new Float32Array(this.data);
|
|
3198
|
+
#u16 = new Uint16Array(this.data);
|
|
3199
|
+
clear() {
|
|
3200
|
+
this.count = 0;
|
|
3201
|
+
}
|
|
3202
|
+
push(node, kind, line, atlasHeight) {
|
|
3203
|
+
for (const { glyph, x } of line.glyphs) {
|
|
3204
|
+
if ((this.count + 1) * 32 > this.data.byteLength) this.#grow();
|
|
3205
|
+
const at = this.count * 8;
|
|
3206
|
+
this.#u32[at] = node;
|
|
3207
|
+
this.#u32[at + 1] = kind;
|
|
3208
|
+
this.#f32[at + 2] = x;
|
|
3209
|
+
this.#f32[at + 3] = glyph.top;
|
|
3210
|
+
this.#f32[at + 4] = glyph.width;
|
|
3211
|
+
this.#f32[at + 5] = glyph.height;
|
|
3212
|
+
const uv = at * 2 + 12;
|
|
3213
|
+
this.#u16[uv] = Math.round(glyph.x / atlasWidth * 65535);
|
|
3214
|
+
this.#u16[uv + 1] = Math.round(glyph.y / atlasHeight * 65535);
|
|
3215
|
+
this.#u16[uv + 2] = Math.round((glyph.x + glyph.width) / atlasWidth * 65535);
|
|
3216
|
+
this.#u16[uv + 3] = Math.round((glyph.y + glyph.height) / atlasHeight * 65535);
|
|
3217
|
+
this.count++;
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
pushPlate(node, color, width, lines) {
|
|
3221
|
+
if ((this.count + 1) * 32 > this.data.byteLength) this.#grow();
|
|
3222
|
+
const at = this.count * 8;
|
|
3223
|
+
this.#u32[at] = node;
|
|
3224
|
+
this.#u32[at + 1] = 3 | color << 4;
|
|
3225
|
+
this.#f32[at + 2] = width;
|
|
3226
|
+
this.#f32[at + 3] = lines;
|
|
3227
|
+
this.#f32[at + 4] = 0;
|
|
3228
|
+
this.#f32[at + 5] = 0;
|
|
3229
|
+
this.#u32[at + 6] = 0;
|
|
3230
|
+
this.#u32[at + 7] = 0;
|
|
3231
|
+
this.count++;
|
|
3232
|
+
}
|
|
3233
|
+
#grow() {
|
|
3234
|
+
const data = /* @__PURE__ */ new ArrayBuffer(this.data.byteLength * 2);
|
|
3235
|
+
new Uint8Array(data).set(new Uint8Array(this.data));
|
|
3236
|
+
this.data = data;
|
|
3237
|
+
this.#u32 = new Uint32Array(data);
|
|
3238
|
+
this.#f32 = new Float32Array(data);
|
|
3239
|
+
this.#u16 = new Uint16Array(data);
|
|
3240
|
+
}
|
|
3241
|
+
};
|
|
3242
|
+
function labelVisible(mask, flags) {
|
|
3243
|
+
let bits = mask >>> 0;
|
|
3244
|
+
while (bits !== 0) {
|
|
3245
|
+
const bit = 31 - Math.clz32(bits & -bits);
|
|
3246
|
+
bits &= bits - 1;
|
|
3247
|
+
const flag = flags[bit] ?? -1;
|
|
3248
|
+
if (flag >= 0) return flag === 1;
|
|
3249
|
+
}
|
|
3250
|
+
return true;
|
|
3251
|
+
}
|
|
3252
|
+
var LabelLayer = class {
|
|
3253
|
+
main = new GlyphBuffer();
|
|
3254
|
+
highlight = new GlyphBuffer();
|
|
3255
|
+
#occupancy = /* @__PURE__ */ new Uint8Array(0);
|
|
3256
|
+
select(frame, atlas) {
|
|
3257
|
+
this.main.clear();
|
|
3258
|
+
this.highlight.clear();
|
|
3259
|
+
const { nodes, positions, view, width, height } = frame;
|
|
3260
|
+
const cols = Math.ceil(width / cell) + 1;
|
|
3261
|
+
const rows = Math.ceil(height / cell) + 1;
|
|
3262
|
+
if (this.#occupancy.length < cols * rows) this.#occupancy = new Uint8Array(cols * rows);
|
|
3263
|
+
else this.#occupancy.fill(0, 0, cols * rows);
|
|
3264
|
+
const occupancy = this.#occupancy;
|
|
3265
|
+
const highlighted = new Set(frame.highlighted);
|
|
3266
|
+
const worldPrimary = primarySize * Math.min(1, view.zoom);
|
|
3267
|
+
let placed = 0;
|
|
3268
|
+
const forced = (index) => ((frame.nodeMask[index] ?? 0) & forcedStates) !== 0;
|
|
3269
|
+
const place = (index, highlight) => {
|
|
3270
|
+
const force = highlight && forced(index);
|
|
3271
|
+
const label = nodes.label[index];
|
|
3272
|
+
if (!label || nodes.alive[index] !== 1) return;
|
|
3273
|
+
if (!labelVisible(frame.nodeMask[index] ?? 0, frame.labelFlags)) return;
|
|
3274
|
+
const screenUnits = nodes.screenUnits[index] === 1;
|
|
3275
|
+
const primary = screenUnits ? primarySize : worldPrimary;
|
|
3276
|
+
if (primary < labelMin) return;
|
|
3277
|
+
const diameter = screenUnits ? nodes.size[index] ?? 0 : (nodes.size[index] ?? 0) * view.zoom;
|
|
3278
|
+
const radius = Math.max(diameter / 2, 1.25) + (nodes.outlineWidth[index] ?? 0);
|
|
3279
|
+
const x = (positions.x(index) - view.x) * view.zoom + width / 2;
|
|
3280
|
+
const y = (positions.y(index) - view.y) * view.zoom + height / 2;
|
|
3281
|
+
if (x < -400 || x > width + cullMargin) return;
|
|
3282
|
+
if (y + radius > height || y + radius + primary * lineHeight * 3 < -3) return;
|
|
3283
|
+
const line = atlas.line(label, "500");
|
|
3284
|
+
const secondaryText = nodes.secondary[index];
|
|
3285
|
+
const secondary = secondaryText ? atlas.line(secondaryText, "400") : null;
|
|
3286
|
+
const scale = primary / 24;
|
|
3287
|
+
const textUnits = Math.max(line.width, secondary ? secondary.width * 11 / 12 : 0);
|
|
3288
|
+
const background = nodes.labelBackground[index] ?? 4294967295;
|
|
3289
|
+
const plated = background !== noColor;
|
|
3290
|
+
const pad = plated ? primary * platePadX : 0;
|
|
3291
|
+
const lines = secondary ? 2 : 1;
|
|
3292
|
+
const top = y + radius + 3;
|
|
3293
|
+
const bottom = top + (plated ? primary * 2 * (secondary ? plateHalfTwo : plateHalfOne) : primary * lineHeight * lines);
|
|
3294
|
+
const left = x - textUnits * scale / 2 - pad;
|
|
3295
|
+
const right = x + textUnits * scale / 2 + pad;
|
|
3296
|
+
if (right < 0 || left > width || bottom < 0 || top > height) return;
|
|
3297
|
+
const c0 = Math.max(0, Math.floor(left / cell));
|
|
3298
|
+
const c1 = Math.min(cols - 1, Math.floor(right / cell));
|
|
3299
|
+
const r0 = Math.max(0, Math.floor(top / cell));
|
|
3300
|
+
const r1 = Math.min(rows - 1, Math.floor(bottom / cell));
|
|
3301
|
+
if (!force) {
|
|
3302
|
+
for (let row = r0; row <= r1; row++) for (let col = c0; col <= c1; col++) if (occupancy[row * cols + col] === 1) return;
|
|
3303
|
+
}
|
|
3304
|
+
for (let row = r0; row <= r1; row++) occupancy.fill(1, row * cols + c0, row * cols + c1 + 1);
|
|
3305
|
+
const target = highlight ? this.highlight : this.main;
|
|
3306
|
+
const plate = plated ? 4 : 0;
|
|
3307
|
+
if (plated) target.pushPlate(index, background, textUnits, lines);
|
|
3308
|
+
target.push(index, plate, line, atlas.height);
|
|
3309
|
+
if (secondary) target.push(index, 1 | plate, secondary, atlas.height);
|
|
3310
|
+
placed++;
|
|
3311
|
+
};
|
|
3312
|
+
for (const index of highlighted) if (forced(index)) place(index, true);
|
|
3313
|
+
for (const index of highlighted) if (!forced(index)) place(index, true);
|
|
3314
|
+
if (worldPrimary < labelMin && !frame.screenLabels) return;
|
|
3315
|
+
const xy = positions.xy;
|
|
3316
|
+
const order = frame.order;
|
|
3317
|
+
const left = view.x - (width / 2 + cullMargin) / view.zoom;
|
|
3318
|
+
const right = view.x + (width / 2 + cullMargin) / view.zoom;
|
|
3319
|
+
const largest = nodes.size[order[0] ?? 0] ?? 0;
|
|
3320
|
+
const reach = cullMargin + (frame.screenLabels ? largest : largest * view.zoom) / 2;
|
|
3321
|
+
const top = view.y - (height / 2 + reach) / view.zoom;
|
|
3322
|
+
const bottom = view.y + height / 2 / view.zoom;
|
|
3323
|
+
for (let at = 0; at < frame.orderLength && placed < maxLabels; at++) {
|
|
3324
|
+
const index = order[at] ?? 0;
|
|
3325
|
+
const x = xy[index * 2] ?? 0;
|
|
3326
|
+
const y = xy[index * 2 + 1] ?? 0;
|
|
3327
|
+
if (x < left || x > right || y < top || y > bottom) continue;
|
|
3328
|
+
if (!highlighted.has(index)) place(index, false);
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3331
|
+
};
|
|
3332
|
+
function sortBySize(nodes, order) {
|
|
3333
|
+
let length = 0;
|
|
3334
|
+
let screenLabels = false;
|
|
3335
|
+
for (let index = 0; index < nodes.capacity; index++) if (nodes.alive[index] === 1 && nodes.label[index]) {
|
|
3336
|
+
order[length++] = index;
|
|
3337
|
+
if (nodes.screenUnits[index] === 1) screenLabels = true;
|
|
3338
|
+
}
|
|
3339
|
+
const sizes = nodes.size;
|
|
3340
|
+
order.subarray(0, length).sort((a, b) => (sizes[b] ?? 0) - (sizes[a] ?? 0));
|
|
3341
|
+
return {
|
|
3342
|
+
length,
|
|
3343
|
+
screenLabels
|
|
3344
|
+
};
|
|
3345
|
+
}
|
|
3242
3346
|
// src/webgl/renderer.ts
|
|
3243
3347
|
const blocks = {
|
|
3244
3348
|
Frame: 0,
|
|
@@ -3258,7 +3362,7 @@ const units = {
|
|
|
3258
3362
|
edgeState: 7,
|
|
3259
3363
|
atlas: 8,
|
|
3260
3364
|
images: 9,
|
|
3261
|
-
|
|
3365
|
+
nodeDecor: 10
|
|
3262
3366
|
};
|
|
3263
3367
|
function iota(length) {
|
|
3264
3368
|
const values = new Uint32Array(length);
|
|
@@ -3285,7 +3389,7 @@ function createWebglRenderer(canvas, invalidate = () => {}) {
|
|
|
3285
3389
|
const nodeStyle = new DataTexture(gl, format.rgba32f, f32);
|
|
3286
3390
|
const nodePaint = new DataTexture(gl, format.rgba32ui, u32);
|
|
3287
3391
|
const nodeState = new DataTexture(gl, format.r32ui, u32);
|
|
3288
|
-
const
|
|
3392
|
+
const nodeDecor = new DataTexture(gl, format.rgba32ui, u32);
|
|
3289
3393
|
const edgeTopology = new DataTexture(gl, format.rgba32ui, u32);
|
|
3290
3394
|
const edgeStyle = new DataTexture(gl, format.rgba32f, f32);
|
|
3291
3395
|
const edgeState = new DataTexture(gl, format.r32ui, u32);
|
|
@@ -3294,11 +3398,11 @@ function createWebglRenderer(canvas, invalidate = () => {}) {
|
|
|
3294
3398
|
nodeStyle,
|
|
3295
3399
|
nodePaint,
|
|
3296
3400
|
nodeState,
|
|
3297
|
-
|
|
3401
|
+
nodeDecor
|
|
3298
3402
|
];
|
|
3299
3403
|
const images = new ImageAtlas(gl, invalidate);
|
|
3300
|
-
const
|
|
3301
|
-
const
|
|
3404
|
+
const floatBits = /* @__PURE__ */ new Float32Array(1);
|
|
3405
|
+
const floatWord = new Uint32Array(floatBits.buffer);
|
|
3302
3406
|
const edgeTextures = [
|
|
3303
3407
|
edgeTopology,
|
|
3304
3408
|
edgeStyle,
|
|
@@ -3528,6 +3632,7 @@ function createWebglRenderer(canvas, invalidate = () => {}) {
|
|
|
3528
3632
|
nodePaint.data[at] = nodes.fill[index] ?? 0;
|
|
3529
3633
|
nodePaint.data[at + 1] = nodes.stroke[index] ?? 0;
|
|
3530
3634
|
nodePaint.data[at + 2] = nodes.slot[index] ?? 0;
|
|
3635
|
+
nodePaint.data[at + 3] = nodes.outline[index] ?? 4294967295;
|
|
3531
3636
|
const src = nodes.alive[index] === 1 ? nodes.image[index] ?? null : null;
|
|
3532
3637
|
const previous = imageOf[index] ?? null;
|
|
3533
3638
|
if (src !== previous) {
|
|
@@ -3535,10 +3640,12 @@ function createWebglRenderer(canvas, invalidate = () => {}) {
|
|
|
3535
3640
|
if (src) images.acquire(src);
|
|
3536
3641
|
imageOf[index] = src;
|
|
3537
3642
|
}
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3643
|
+
floatBits[0] = nodes.imageScale[index] ?? 1;
|
|
3644
|
+
nodeDecor.data[at] = src ? images.layer(src) + 1 : 0;
|
|
3645
|
+
nodeDecor.data[at + 1] = nodes.imageColor[index] ?? 4294967295;
|
|
3646
|
+
nodeDecor.data[at + 2] = floatWord[0] ?? 0;
|
|
3647
|
+
floatBits[0] = nodes.outlineWidth[index] ?? 0;
|
|
3648
|
+
nodeDecor.data[at + 3] = floatWord[0] ?? 0;
|
|
3542
3649
|
const badges = nodes.alive[index] === 1 ? nodes.badges[index] : null;
|
|
3543
3650
|
if (badges || badged.has(index)) badgesStale = true;
|
|
3544
3651
|
if (badges) badged.add(index);
|
|
@@ -3552,11 +3659,11 @@ function createWebglRenderer(canvas, invalidate = () => {}) {
|
|
|
3552
3659
|
for (let index = 0; index < nodes.capacity; index++) {
|
|
3553
3660
|
const src = imageOf[index];
|
|
3554
3661
|
if (!src || !loaded.has(src)) continue;
|
|
3555
|
-
|
|
3662
|
+
nodeDecor.data[index * 4] = images.layer(src) + 1;
|
|
3556
3663
|
first = Math.min(first, index);
|
|
3557
3664
|
last = Math.max(last, index);
|
|
3558
3665
|
}
|
|
3559
|
-
|
|
3666
|
+
nodeDecor.upload(first, last);
|
|
3560
3667
|
}
|
|
3561
3668
|
function rebuildBadges() {
|
|
3562
3669
|
if (!input) return;
|
|
@@ -3634,7 +3741,7 @@ function createWebglRenderer(canvas, invalidate = () => {}) {
|
|
|
3634
3741
|
}
|
|
3635
3742
|
nodeStyle.upload(first, last);
|
|
3636
3743
|
nodePaint.upload(first, last);
|
|
3637
|
-
|
|
3744
|
+
nodeDecor.upload(first, last);
|
|
3638
3745
|
if (next.positionsChanged || next.full || grown) {
|
|
3639
3746
|
const xy = next.positions.xy;
|
|
3640
3747
|
nodePosition.data.set(xy.subarray(0, Math.min(xy.length, nodePosition.data.length)));
|
|
@@ -3896,7 +4003,7 @@ function createWebglRenderer(canvas, invalidate = () => {}) {
|
|
|
3896
4003
|
[units.edgeStyle, edgeStyle.texture],
|
|
3897
4004
|
[units.edgeState, edgeState.texture],
|
|
3898
4005
|
[units.atlas, atlasTexture],
|
|
3899
|
-
[units.
|
|
4006
|
+
[units.nodeDecor, nodeDecor.texture]
|
|
3900
4007
|
];
|
|
3901
4008
|
for (const [unit, texture] of textures) {
|
|
3902
4009
|
gl.activeTexture(gl.TEXTURE0 + unit);
|
|
@@ -4194,7 +4301,9 @@ function resolveStyle(style, id) {
|
|
|
4194
4301
|
...style.halo !== void 0 ? { halo: style.halo } : {},
|
|
4195
4302
|
...style.label !== void 0 ? { label: style.label } : {},
|
|
4196
4303
|
...style.fill !== void 0 ? { fill: id(style.fill) } : {},
|
|
4197
|
-
...style.stroke !== void 0 ? { stroke: id(style.stroke) } : {}
|
|
4304
|
+
...style.stroke !== void 0 ? { stroke: id(style.stroke) } : {},
|
|
4305
|
+
...style.outline !== void 0 ? { outline: id(style.outline) } : {},
|
|
4306
|
+
...style.outlineWidth !== void 0 || style.outline !== void 0 ? { outlineWidth: style.outlineWidth ?? defaults.nodeOutlineWidth } : {}
|
|
4198
4307
|
};
|
|
4199
4308
|
}
|
|
4200
4309
|
function createGraphHost(container, options, createRenderer) {
|
|
@@ -5142,4 +5251,4 @@ function mountGraph(container, options) {
|
|
|
5142
5251
|
}
|
|
5143
5252
|
export { freeStateNames as n, maxFreeStates as r, mountGraph as t };
|
|
5144
5253
|
|
|
5145
|
-
//# sourceMappingURL=mount-graph-
|
|
5254
|
+
//# sourceMappingURL=mount-graph-mObhwJ3e.js.map
|