vault backup: 2025-04-10 14:07:13
This commit is contained in:
417
.obsidian/plugins/obsidian-webpage-export-master/assets/graph-render-worker.txt.js
vendored
Normal file
417
.obsidian/plugins/obsidian-webpage-export-master/assets/graph-render-worker.txt.js
vendored
Normal file
@ -0,0 +1,417 @@
|
||||
// Import Pixi.js library
|
||||
if( 'function' === typeof importScripts)
|
||||
{
|
||||
importScripts('https://d157l7jdn8e5sf.cloudfront.net/v7.2.0/webworker.js', './tinycolor.js');
|
||||
|
||||
addEventListener('message', onMessage);
|
||||
|
||||
let app;
|
||||
let container;
|
||||
let graphics;
|
||||
|
||||
isDrawing = false;
|
||||
|
||||
let linkCount = 0;
|
||||
let linkSources = [];
|
||||
let linkTargets = [];
|
||||
let nodeCount = 0;
|
||||
let radii = [];
|
||||
let labels = [];
|
||||
let labelFade = [];
|
||||
let labelWidths = [];
|
||||
let pixiLabels = [];
|
||||
let cameraOffset = {x: 0, y: 0};
|
||||
let positions = new Float32Array(0);
|
||||
let linkLength = 0;
|
||||
let edgePruning = 0;
|
||||
let colors =
|
||||
{
|
||||
background: 0x232323,
|
||||
link: 0xAAAAAA,
|
||||
node: 0xCCCCCC,
|
||||
outline: 0xAAAAAA,
|
||||
text: 0xFFFFFF,
|
||||
accent: 0x4023AA
|
||||
}
|
||||
|
||||
let hoveredNode = -1;
|
||||
let lastHoveredNode = -1;
|
||||
let grabbedNode = -1;
|
||||
let updateAttached = false;
|
||||
let attachedToGrabbed = [];
|
||||
let activeNode = -1;
|
||||
let attachedToActive = [];
|
||||
|
||||
let cameraScale = 1;
|
||||
let cameraScaleRoot = 1;
|
||||
|
||||
function toScreenSpace(x, y, floor = true)
|
||||
{
|
||||
if (floor)
|
||||
{
|
||||
return {x: Math.floor((x * cameraScale) + cameraOffset.x), y: Math.floor((y * cameraScale) + cameraOffset.y)};
|
||||
}
|
||||
else
|
||||
{
|
||||
return {x: (x * cameraScale) + cameraOffset.x, y: (y * cameraScale) + cameraOffset.y};
|
||||
}
|
||||
}
|
||||
|
||||
function vecToScreenSpace({x, y}, floor = true)
|
||||
{
|
||||
return toScreenSpace(x, y, floor);
|
||||
}
|
||||
|
||||
function toWorldspace(x, y)
|
||||
{
|
||||
return {x: (x - cameraOffset.x) / cameraScale, y: (y - cameraOffset.y) / cameraScale};
|
||||
}
|
||||
|
||||
function vecToWorldspace({x, y})
|
||||
{
|
||||
return toWorldspace(x, y);
|
||||
}
|
||||
|
||||
function setCameraCenterWorldspace({x, y})
|
||||
{
|
||||
cameraOffset.x = (canvas.width / 2) - (x * cameraScale);
|
||||
cameraOffset.y = (canvas.height / 2) - (y * cameraScale);
|
||||
}
|
||||
|
||||
function getCameraCenterWorldspace()
|
||||
{
|
||||
return toWorldspace(canvas.width / 2, canvas.height / 2);
|
||||
}
|
||||
|
||||
function getNodeScreenRadius(radius)
|
||||
{
|
||||
return radius * cameraScaleRoot;
|
||||
}
|
||||
|
||||
function getNodeWorldspaceRadius(radius)
|
||||
{
|
||||
return radius / cameraScaleRoot;
|
||||
}
|
||||
|
||||
function getPosition(index)
|
||||
{
|
||||
return {x: positions[index * 2], y: positions[index * 2 + 1]};
|
||||
}
|
||||
|
||||
function mixColors(hexStart, hexEnd, factor)
|
||||
{
|
||||
return tinycolor.mix(tinycolor(hexStart.toString(16)), tinycolor(hexEnd.toString(16)), factor).toHexNumber()
|
||||
}
|
||||
|
||||
function darkenColor(hexColor, factor)
|
||||
{
|
||||
return tinycolor(hexColor.toString(16)).darken(factor).toHexNumber();
|
||||
}
|
||||
|
||||
function lightenColor(hexColor, factor)
|
||||
{
|
||||
return tinycolor(hexColor.toString(16)).lighten(factor).toHexNumber();
|
||||
}
|
||||
|
||||
function invertColor(hex, bw)
|
||||
{
|
||||
hex = hex.toString(16); // force conversion
|
||||
// fill extra space up to 6 characters with 0
|
||||
while (hex.length < 6) hex = "0" + hex;
|
||||
|
||||
if (hex.indexOf('#') === 0) {
|
||||
hex = hex.slice(1);
|
||||
}
|
||||
// convert 3-digit hex to 6-digits.
|
||||
if (hex.length === 3) {
|
||||
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
|
||||
}
|
||||
if (hex.length !== 6) {
|
||||
throw new Error('Invalid HEX color:' + hex);
|
||||
}
|
||||
var r = parseInt(hex.slice(0, 2), 16),
|
||||
g = parseInt(hex.slice(2, 4), 16),
|
||||
b = parseInt(hex.slice(4, 6), 16);
|
||||
if (bw) {
|
||||
// https://stackoverflow.com/a/3943023/112731
|
||||
return (r * 0.299 + g * 0.587 + b * 0.114) > 186
|
||||
? '#000000'
|
||||
: '#FFFFFF';
|
||||
}
|
||||
// invert color components
|
||||
r = (255 - r).toString(16);
|
||||
g = (255 - g).toString(16);
|
||||
b = (255 - b).toString(16);
|
||||
// pad each with zeros and return
|
||||
return "#" + padZero(r) + padZero(g) + padZero(b);
|
||||
}
|
||||
|
||||
function clamp(value, min, max)
|
||||
{
|
||||
return Math.min(Math.max(value, min), max);
|
||||
}
|
||||
|
||||
function lerp(a, b, t)
|
||||
{
|
||||
return a + (b - a) * t;
|
||||
}
|
||||
|
||||
let hoverFade = 0;
|
||||
let hoverFadeSpeed = 0.2;
|
||||
let hoverFontSize = 15;
|
||||
let normalFontSize = 12;
|
||||
let fontRatio = hoverFontSize / normalFontSize;
|
||||
|
||||
function showLabel(index, fade, hovered = false)
|
||||
{
|
||||
let label = pixiLabels[index];
|
||||
if (!label) return;
|
||||
labelFade[index] = fade;
|
||||
|
||||
if(fade > 0.01) label.visible = true;
|
||||
else
|
||||
{
|
||||
hideLabel(index);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hovered) label.style.fontSize = hoverFontSize;
|
||||
else label.style.fontSize = normalFontSize;
|
||||
|
||||
|
||||
let nodePos = vecToScreenSpace(getPosition(index));
|
||||
let width = (labelWidths[index] * (hovered ? fontRatio : 1)) / 2;
|
||||
label.x = nodePos.x - width;
|
||||
label.y = nodePos.y + getNodeScreenRadius(radii[index]) + 9;
|
||||
label.alpha = fade;
|
||||
}
|
||||
|
||||
function hideLabel(index)
|
||||
{
|
||||
let label = pixiLabels[index];
|
||||
label.visible = false;
|
||||
}
|
||||
|
||||
function draw()
|
||||
{
|
||||
graphics.clear();
|
||||
|
||||
let topLines = [];
|
||||
if (updateAttached)
|
||||
{
|
||||
attachedToGrabbed = [];
|
||||
// hoverFade = 0;
|
||||
}
|
||||
|
||||
if (hoveredNode != -1 || grabbedNode != -1)
|
||||
{
|
||||
hoverFade = Math.min(1, hoverFade + hoverFadeSpeed);
|
||||
}
|
||||
else
|
||||
{
|
||||
hoverFade = Math.max(0, hoverFade - hoverFadeSpeed);
|
||||
}
|
||||
|
||||
graphics.lineStyle(1, mixColors(colors.link, colors.background, hoverFade * 50), 0.7);
|
||||
|
||||
for (let i = 0; i < linkCount; i++)
|
||||
{
|
||||
let target = linkTargets[i];
|
||||
let source = linkSources[i];
|
||||
|
||||
if (hoveredNode == source || hoveredNode == target || ((lastHoveredNode == source || lastHoveredNode == target) && hoverFade != 0))
|
||||
{
|
||||
if (updateAttached && hoveredNode == source)
|
||||
attachedToGrabbed.push(target);
|
||||
|
||||
else if (updateAttached && hoveredNode == target)
|
||||
attachedToGrabbed.push(source);
|
||||
|
||||
topLines.push(i);
|
||||
}
|
||||
|
||||
let startWorld = getPosition(source);
|
||||
let endWorld = getPosition(target);
|
||||
|
||||
let start = vecToScreenSpace(startWorld);
|
||||
let end = vecToScreenSpace(endWorld);
|
||||
|
||||
let dist = Math.sqrt(Math.pow(startWorld.x - endWorld.x, 2) + Math.pow(startWorld.y - endWorld.y, 2));
|
||||
|
||||
if (dist < (radii[source] + radii[target]) * edgePruning)
|
||||
{
|
||||
graphics.moveTo(start.x, start.y);
|
||||
graphics.lineTo(end.x, end.y);
|
||||
}
|
||||
}
|
||||
|
||||
let opacity = 1 - (hoverFade * 0.5);
|
||||
graphics.beginFill(mixColors(colors.node, colors.background, hoverFade * 50), opacity);
|
||||
graphics.lineStyle(0, 0xffffff);
|
||||
for (let i = 0; i < nodeCount; i++)
|
||||
{
|
||||
let screenRadius = getNodeScreenRadius(radii[i]);
|
||||
|
||||
if (hoveredNode != i)
|
||||
{
|
||||
if (screenRadius > 2)
|
||||
{
|
||||
|
||||
let labelFade = lerp(0, (screenRadius - 4) / 8 - (1/cameraScaleRoot)/6 * 0.9, Math.max(1 - hoverFade, 0.2));
|
||||
showLabel(i, labelFade);
|
||||
}
|
||||
else
|
||||
{
|
||||
hideLabel(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (hoveredNode == i || (lastHoveredNode == i && hoverFade != 0) || (hoveredNode != -1 && attachedToGrabbed.includes(i))) continue;
|
||||
|
||||
let pos = vecToScreenSpace(getPosition(i));
|
||||
graphics.drawCircle(pos.x, pos.y, screenRadius);
|
||||
}
|
||||
|
||||
graphics.endFill();
|
||||
|
||||
|
||||
opacity = hoverFade * 0.7;
|
||||
graphics.lineStyle(1, mixColors(mixColors(colors.link, colors.accent, hoverFade * 100), colors.background, 20), opacity);
|
||||
|
||||
for (let i = 0; i < topLines.length; i++)
|
||||
{
|
||||
let target = linkTargets[topLines[i]];
|
||||
let source = linkSources[topLines[i]];
|
||||
|
||||
// draw lines on top when hovered
|
||||
let start = vecToScreenSpace(getPosition(source));
|
||||
let end = vecToScreenSpace(getPosition(target));
|
||||
|
||||
|
||||
graphics.moveTo(start.x, start.y);
|
||||
graphics.lineTo(end.x, end.y);
|
||||
}
|
||||
|
||||
if(hoveredNode != -1 || (lastHoveredNode != -1 && hoverFade != 0))
|
||||
{
|
||||
graphics.beginFill(mixColors(colors.node, colors.accent, hoverFade * 20), 0.9);
|
||||
graphics.lineStyle(0, 0xffffff);
|
||||
for (let i = 0; i < attachedToGrabbed.length; i++)
|
||||
{
|
||||
let point = attachedToGrabbed[i];
|
||||
|
||||
let pos = vecToScreenSpace(getPosition(point));
|
||||
|
||||
graphics.drawCircle(pos.x, pos.y, getNodeScreenRadius(radii[point]));
|
||||
showLabel(point, Math.max(hoverFade * 0.6, labelFade[point]));
|
||||
}
|
||||
graphics.endFill();
|
||||
|
||||
let index = hoveredNode != -1 ? hoveredNode : lastHoveredNode;
|
||||
|
||||
let pos = vecToScreenSpace(getPosition(index));
|
||||
graphics.beginFill(mixColors(colors.node, colors.accent, hoverFade * 100), 1);
|
||||
graphics.lineStyle(hoverFade, mixColors(invertColor(colors.background, true), colors.accent, 50));
|
||||
graphics.drawCircle(pos.x, pos.y, getNodeScreenRadius(radii[index]));
|
||||
graphics.endFill();
|
||||
|
||||
showLabel(index, Math.max(hoverFade, labelFade[index]), true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
updateAttached = false;
|
||||
|
||||
graphics.lineStyle(2, colors.accent);
|
||||
// draw the active node
|
||||
if (activeNode != -1)
|
||||
{
|
||||
let pos = vecToScreenSpace(getPosition(activeNode));
|
||||
graphics.drawCircle(pos.x, pos.y, getNodeScreenRadius(radii[activeNode]) + 4);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function onMessage(event)
|
||||
{
|
||||
if(event.data.type == "draw")
|
||||
{
|
||||
positions = new Float32Array(event.data.positions);
|
||||
draw();
|
||||
}
|
||||
else if(event.data.type == "update_camera")
|
||||
{
|
||||
cameraOffset = event.data.cameraOffset;
|
||||
cameraScale = event.data.cameraScale;
|
||||
cameraScaleRoot = Math.sqrt(cameraScale);
|
||||
}
|
||||
else if(event.data.type == "update_interaction")
|
||||
{
|
||||
if(hoveredNode != event.data.hoveredNode && event.data.hoveredNode != -1) updateAttached = true;
|
||||
if(grabbedNode != event.data.grabbedNode && event.data.hoveredNode != -1) updateAttached = true;
|
||||
|
||||
if(event.data.hoveredNode == -1) lastHoveredNode = hoveredNode;
|
||||
else lastHoveredNode = -1;
|
||||
|
||||
hoveredNode = event.data.hoveredNode;
|
||||
grabbedNode = event.data.grabbedNode;
|
||||
}
|
||||
else if(event.data.type == "resize")
|
||||
{
|
||||
app.renderer.resize(event.data.width, event.data.height);
|
||||
}
|
||||
else if(event.data.type == "set_active")
|
||||
{
|
||||
activeNode = event.data.active;
|
||||
}
|
||||
else if(event.data.type == "update_colors")
|
||||
{
|
||||
colors = event.data.colors;
|
||||
|
||||
for (let label of pixiLabels)
|
||||
{
|
||||
label.style.fill = invertColor(colors.background, true);
|
||||
}
|
||||
}
|
||||
else if(event.data.type == "init")
|
||||
{
|
||||
// Extract data from message
|
||||
linkCount = event.data.linkCount;
|
||||
linkSources = event.data.linkSources;
|
||||
linkTargets = event.data.linkTargets;
|
||||
nodeCount = event.data.nodeCount;
|
||||
radii = event.data.radii;
|
||||
labels = event.data.labels;
|
||||
linkLength = event.data.linkLength;
|
||||
edgePruning = event.data.edgePruning;
|
||||
|
||||
app = new PIXI.Application({... event.data.options, antialias: true, resolution: 2, backgroundAlpha: 0, transparent: true});
|
||||
container = new PIXI.Container();
|
||||
graphics = new PIXI.Graphics();
|
||||
app.stage.addChild(container);
|
||||
container.addChild(graphics);
|
||||
|
||||
pixiLabels = [];
|
||||
for (let i = 0; i < nodeCount; i++)
|
||||
{
|
||||
let label = new PIXI.Text(labels[i], {fontFamily : 'Arial', fontSize: 12, fontWeight: "normal", fill : invertColor(colors.background, true), align : 'center', anchor: 0.5});
|
||||
pixiLabels.push(label);
|
||||
labelWidths.push(label.width);
|
||||
labelFade.push(0);
|
||||
app.stage.addChild(label);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log("Unknown message type sent to graph worker: " + event.data.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user