Skip to content

Commit

Permalink
support node background image loading
Browse files Browse the repository at this point in the history
  • Loading branch information
mikekucera committed Oct 22, 2024
1 parent 65ca1ea commit 5c722e1
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 28 deletions.
64 changes: 64 additions & 0 deletions debug/webgl/network-images.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"elements": {
"nodes": [
{ "data": { "id": "n1", "weight": 1 }, "position": { "x": -29, "y": 26 } },
{ "data": { "id": "n2", "weight": 2 }, "position": { "x": 77, "y": -15 } },
{ "data": { "id": "n3", "weight": 3 }, "position": { "x": 178, "y": 36 } },
{ "data": { "id": "n4", "weight": 4 }, "position": { "x": -17, "y": 146 } },
{ "data": { "id": "n5", "weight": 5 }, "position": { "x": 134, "y": 157 } }
],
"edges": [
{ "data": { "id":"n1-n2", "source": "n1", "target": "n2", "directed": "false" } },
{ "data": { "id":"n1-n3", "source": "n1", "target": "n3", "directed": "false" } },
{ "data": { "id":"n1-n4", "source": "n1", "target": "n4", "directed": "false" } },
{ "data": { "id":"n1-n5", "source": "n1", "target": "n5", "directed": "false" } },
{ "data": { "id":"n2-n3", "source": "n2", "target": "n3", "directed": "false" } },
{ "data": { "id":"n2-n4", "source": "n2", "target": "n4", "directed": "false" } },
{ "data": { "id":"n2-n5", "source": "n2", "target": "n5", "directed": "false" } },
{ "data": { "id":"n3-n4", "source": "n3", "target": "n4", "directed": "false" } },
{ "data": { "id":"n3-n5", "source": "n3", "target": "n5", "directed": "false" } },
{ "data": { "id":"n4-n5", "source": "n4", "target": "n5", "directed": "false" } }
]
},
"style": [
{
"selector": "node",
"style": {
"label": "data(id)",
"text-valign": "top",
"color": "#000000",
"background-color": "#3a7ecf",
"font-family": "Helvetica",
"background-fit": "cover",
"font-size": "8px",
"border-color": "darkblue",
"border-width": 2
}
}, {
"selector": "#n1",
"style": {
"background-image": "https://picsum.photos/601"
}
}, {
"selector": "#n2",
"style": {
"background-image": "https://picsum.photos/602"
}
}, {
"selector": "#n3",
"style": {
"background-image": "https://picsum.photos/603"
}
}, {
"selector": "#n4",
"style": {
"background-image": "https://picsum.photos/604"
}
}, {
"selector": "#n5",
"style": {
"background-image": "https://picsum.photos/605"
}
}
]
}
17 changes: 11 additions & 6 deletions debug/webgl/network-tiny.json → debug/webgl/network-styles.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"elements": {
"nodes": [
{ "data": { "id": "n1", "weight": 1 } },
{ "data": { "id": "n2", "weight": 2 } },
{ "data": { "id": "n3", "weight": 3 } },
{ "data": { "id": "n4", "weight": 4 } },
{ "data": { "id": "n5", "weight": 5 } }
{ "data": { "id": "n1", "weight": 1 }, "position": { "x": -29, "y": 26 } },
{ "data": { "id": "n2", "weight": 2 }, "position": { "x": 77, "y": -15 } },
{ "data": { "id": "n3", "weight": 3 }, "position": { "x": 178, "y": 36 } },
{ "data": { "id": "n4", "weight": 4 }, "position": { "x": -17, "y": 146 } },
{ "data": { "id": "n5", "weight": 5 }, "position": { "x": 134, "y": 157 } }
],
"edges": [
{ "data": { "id":"n1-n2", "source": "n1", "target": "n2", "directed": "false" } },
Expand Down Expand Up @@ -45,7 +45,12 @@
"selector": "#n2",
"style": {
"border-color": "black",
"border-width": 2
"border-width": 2,
"background-image": "https://picsum.photos/600",
"background-fit": "cover",
"text-valign": "top",
"label": "n2 (random image)",
"font-size": "8px"
}
},
{
Expand Down
11 changes: 9 additions & 2 deletions debug/webgl/networks.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ var networks = {
desc: 'Style Test',
nodes: 5,
edges: 10,
url: 'network-tiny.json',
layout: { name: 'cose' }
url: 'network-styles.json',
layout: { name: 'preset' }
},
'compound': {
desc: 'Compound nodes',
Expand All @@ -16,6 +16,13 @@ var networks = {
url: 'network-compound-nodes.json',
layout: { name: 'preset' }
},
'images': {
desc: 'Image Load Test',
nodes: 5,
edges: 10,
url: 'network-images.json',
layout: { name: 'preset' }
},
'em-web': {
desc: 'EM web',
nodes: 569,
Expand Down
53 changes: 38 additions & 15 deletions src/extensions/renderer/canvas/webgl/atlas.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ export class AtlasCollection {

this.atlases = [];
this.styleKeyToAtlas = new Map();
this.styleKeyNeedsRedraw = new Set();

this.forceGC = false;
}

getKeys() {
Expand Down Expand Up @@ -263,9 +266,21 @@ export class AtlasCollection {
}

draw(id, key, bb, doDrawing) {
if(this.styleKeyNeedsRedraw.delete(key)) {
this.deleteKey(id, key);
// We need to mark the atlas as needing GC because the key will be mapped to
// this atlas or a new atlas, so the key itself won't be marked for GC.
const atlas = this.styleKeyToAtlas.get(key);
if(atlas) {
atlas.forceGC = true;
}
this.styleKeyToAtlas.delete(key);
}

let atlas = this.styleKeyToAtlas.get(key);
if(!atlas) {
// this is an overly simplistic way of finding an atlas, needs to be rewritten
// This is a simplistic way of finding an atlas.
// May waste space at the end of the atalas if the element doesn't fit.
atlas = this.atlases[this.atlases.length - 1];
if(!atlas || !atlas.canFit(bb)) {
atlas = this._createAtlas();
Expand All @@ -289,14 +304,17 @@ export class AtlasCollection {
return this.styleKeyToAtlas.has(key);
}

deleteKey(id, key) {
this.idToKey.delete(id);
this.getIdsFor(key).delete(id);
}

checkKey(id, newKey) {
if(!this.idToKey.has(id))
return;

const oldKey = this.idToKey.get(id);
if(oldKey != newKey) {
this.idToKey.delete(id);
this.getIdsFor(oldKey).delete(id);
this.deleteKey(id, oldKey);
}
}

Expand All @@ -314,8 +332,10 @@ export class AtlasCollection {
* TODO dispose of the old atlas and texture
*/
gc() {
const forceGC = this.atlases.some(atlas => atlas.forceGC);
const markedKeys = this._getKeysToCollect();
if(markedKeys.size === 0) {

if(markedKeys.size === 0 && !forceGC) {
console.log("nothing to garbage collect");
return;
}
Expand All @@ -330,7 +350,7 @@ export class AtlasCollection {

const keysToCollect = intersection(markedKeys, keys);

if(keysToCollect.size === 0) {
if(keysToCollect.size === 0 && !atlas.forceGC) {
newAtlases.push(atlas);
keys.forEach(k => newStyleKeyToAtlas.set(k, atlas));
continue;
Expand All @@ -352,13 +372,10 @@ export class AtlasCollection {
newStyleKeyToAtlas.set(key, newAtlas);
}
}

}

this.atlases = newAtlases;
this.styleKeyToAtlas = newStyleKeyToAtlas;
// TODO, I might not clean up every key
this.markedKeys = new Set();
}


Expand Down Expand Up @@ -453,14 +470,20 @@ export class AtlasManager {
}

/** Marks textues associated with the element for garbage collection. */
invalidate(eles, testEle) {
const renderTypes = this.getRenderTypes();
invalidate(eles, { testEle, testType, forceRedraw } = {}) {
for(const ele of eles) {
if(testEle(ele)) {
if(!testEle || testEle(ele)) {
const id = ele.id();
for(const opts of renderTypes) {
const styleKey = opts.getKey(ele);
opts.atlasCollection.checkKey(id, styleKey);
for(const opts of this.getRenderTypes()) {
if(!testType || testType(opts.type)) {
const styleKey = opts.getKey(ele);
if(forceRedraw) {
opts.atlasCollection.deleteKey(id, styleKey);
opts.atlasCollection.styleKeyNeedsRedraw.add(styleKey);
} else {
opts.atlasCollection.checkKey(id, styleKey);
}
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/extensions/renderer/canvas/webgl/drawing-edges-webgl.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ export class EdgeDrawing {
}

invalidate(eles) {
this.atlasManager.invalidate(eles, ele => ele.isNode());
this.atlasManager.invalidate(eles, { testEle: ele => ele.isEdge() });
}

gc() {
this.atlasCollection.gc();
this.atlasManager.gc();
}

createShaderProgram(renderTarget) {
Expand Down
7 changes: 5 additions & 2 deletions src/extensions/renderer/canvas/webgl/drawing-nodes-webgl.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@ export class NodeDrawing {
this.atlasManager.addRenderType(type, opts);
}

invalidate(eles) {
this.atlasManager.invalidate(eles, ele => ele.isNode());
invalidate(eles, { type } = {}) {
const testEle = ele => ele.isNode();
const testType = type ? t => t === type : null;
const forceRedraw = type ? true : false;
this.atlasManager.invalidate(eles, { testEle, testType, forceRedraw });
}

gc() {
Expand Down
7 changes: 6 additions & 1 deletion src/extensions/renderer/canvas/webgl/drawing-redraw-webgl.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,10 @@ CRp.initWebgl = function(opts, fns) {

// TODO not called when deleting elements
r.onUpdateEleCalcs((willDraw, eles) => {
r.nodeDrawing.invalidate(eles);
if(eles && eles.length > 0) {
r.nodeDrawing.invalidate(eles);
r.edgeDrawing.invalidate(eles);
}
});

// "Override" certain functions in canvas and base renderer
Expand Down Expand Up @@ -176,6 +179,8 @@ function overrideCanvasRendererFunctions(r) {
baseFunc.call(r, eventName, eles);
if(eventName === 'viewport' || eventName === 'bounds') {
r.pickingFrameBuffer.needsDraw = true;
} else if(eventName === 'background') { // background image finished loading, need to redraw
r.nodeDrawing.invalidate(eles, { type: 'node-body' });
}
};
}
Expand Down

0 comments on commit 5c722e1

Please sign in to comment.