Problem: the hexagonal refactor churns the backend tree for nine more phases; the UI delivery stack (web/ SPA, cmd/desktop Wails wrapper, compose/web image) must move to its own repo first so doc/layout rewrites land once on a backend-only tree. Change: - New repo git.hubris.network/dtoro/oikos-web (v0.33.0): web/, desktop/ (updateURL repointed to oikos-web releases), compose/, own CI (web + desktop jobs), own deploy script (CI-green gate, TOCTOU guard, version-tagged images, prune-to-3), own webhook receiver on :9798 + launchd unit, own compose project publishing the same 8091:80. - Cutover executed on mac-mini in order: oikos stack's web service stopped+removed, oikos-web project brought up on 8091; outer Caddy untouched (targets the published port) — serving + Authentik flow + /wails 404 quirk verified post-cutover. - Stripped from oikos: web/, cmd/desktop/, compose/web/, desktop CI workflow, ci.yml web job, Makefile ui/desktop/desktop-package/install targets, the compose web service, oikos-web from deploy.sh's fallback prune list; wails + go-keyring dropped from go.mod, vendor synced. - README / CONTRIBUTING / AGENTS.md / .agents dev+operations docs now point at the new repo; mbse + mascot design docs carry a path note. Risk: production SPA serving depends on the new pipeline now; rollback is versioned-image re-up of the old web service from a pre-split checkout (port 8091). Desktop builds installed before the split still check dtoro/oikos releases — one manual reinstall, noted in the oikos-web release notes. Verification: go vet, make test (race), make generate-check, golangci (no new findings; baseline down 400→365); post-cutover curls — localhost:8091 200, /wails/runtime.js 404, outer Caddy 302 Authentik.
361 lines
11 KiB
JavaScript
361 lines
11 KiB
JavaScript
import isGraph from 'graphology-utils/is-graph';
|
|
import { _ as _slicedToArray } from './colors-beb06eb2.esm.js';
|
|
|
|
var linear = function linear(k) {
|
|
return k;
|
|
};
|
|
var quadraticIn = function quadraticIn(k) {
|
|
return k * k;
|
|
};
|
|
var quadraticOut = function quadraticOut(k) {
|
|
return k * (2 - k);
|
|
};
|
|
var quadraticInOut = function quadraticInOut(k) {
|
|
if ((k *= 2) < 1) return 0.5 * k * k;
|
|
return -0.5 * (--k * (k - 2) - 1);
|
|
};
|
|
var cubicIn = function cubicIn(k) {
|
|
return k * k * k;
|
|
};
|
|
var cubicOut = function cubicOut(k) {
|
|
return --k * k * k + 1;
|
|
};
|
|
var cubicInOut = function cubicInOut(k) {
|
|
if ((k *= 2) < 1) return 0.5 * k * k * k;
|
|
return 0.5 * ((k -= 2) * k * k + 2);
|
|
};
|
|
var easings = {
|
|
linear: linear,
|
|
quadraticIn: quadraticIn,
|
|
quadraticOut: quadraticOut,
|
|
quadraticInOut: quadraticInOut,
|
|
cubicIn: cubicIn,
|
|
cubicOut: cubicOut,
|
|
cubicInOut: cubicInOut
|
|
};
|
|
|
|
/**
|
|
* Defaults.
|
|
*/
|
|
|
|
var ANIMATE_DEFAULTS = {
|
|
easing: "quadraticInOut",
|
|
duration: 150
|
|
};
|
|
|
|
/**
|
|
* Function used to animate the nodes.
|
|
*/
|
|
function animateNodes(graph, targets, opts, callback) {
|
|
var options = Object.assign({}, ANIMATE_DEFAULTS, opts);
|
|
var easing = typeof options.easing === "function" ? options.easing : easings[options.easing];
|
|
var start = Date.now();
|
|
var startPositions = {};
|
|
for (var node in targets) {
|
|
var attrs = targets[node];
|
|
startPositions[node] = {};
|
|
for (var _k in attrs) startPositions[node][_k] = graph.getNodeAttribute(node, _k);
|
|
}
|
|
var frame = null;
|
|
var _step = function step() {
|
|
frame = null;
|
|
var p = (Date.now() - start) / options.duration;
|
|
if (p >= 1) {
|
|
// Animation is done
|
|
for (var _node in targets) {
|
|
var _attrs = targets[_node];
|
|
|
|
// We use given values to avoid precision issues and for convenience
|
|
for (var _k2 in _attrs) graph.setNodeAttribute(_node, _k2, _attrs[_k2]);
|
|
}
|
|
if (typeof callback === "function") callback();
|
|
return;
|
|
}
|
|
p = easing(p);
|
|
for (var _node2 in targets) {
|
|
var _attrs2 = targets[_node2];
|
|
var s = startPositions[_node2];
|
|
for (var _k3 in _attrs2) graph.setNodeAttribute(_node2, _k3, _attrs2[_k3] * p + s[_k3] * (1 - p));
|
|
}
|
|
frame = requestAnimationFrame(_step);
|
|
};
|
|
_step();
|
|
return function () {
|
|
if (frame) cancelAnimationFrame(frame);
|
|
};
|
|
}
|
|
|
|
function identity() {
|
|
return Float32Array.of(1, 0, 0, 0, 1, 0, 0, 0, 1);
|
|
}
|
|
|
|
// TODO: optimize
|
|
function scale(m, x, y) {
|
|
m[0] = x;
|
|
m[4] = typeof y === "number" ? y : x;
|
|
return m;
|
|
}
|
|
function rotate(m, r) {
|
|
var s = Math.sin(r),
|
|
c = Math.cos(r);
|
|
m[0] = c;
|
|
m[1] = s;
|
|
m[3] = -s;
|
|
m[4] = c;
|
|
return m;
|
|
}
|
|
function translate(m, x, y) {
|
|
m[6] = x;
|
|
m[7] = y;
|
|
return m;
|
|
}
|
|
function multiply(a, b) {
|
|
var a00 = a[0],
|
|
a01 = a[1],
|
|
a02 = a[2];
|
|
var a10 = a[3],
|
|
a11 = a[4],
|
|
a12 = a[5];
|
|
var a20 = a[6],
|
|
a21 = a[7],
|
|
a22 = a[8];
|
|
var b00 = b[0],
|
|
b01 = b[1],
|
|
b02 = b[2];
|
|
var b10 = b[3],
|
|
b11 = b[4],
|
|
b12 = b[5];
|
|
var b20 = b[6],
|
|
b21 = b[7],
|
|
b22 = b[8];
|
|
a[0] = b00 * a00 + b01 * a10 + b02 * a20;
|
|
a[1] = b00 * a01 + b01 * a11 + b02 * a21;
|
|
a[2] = b00 * a02 + b01 * a12 + b02 * a22;
|
|
a[3] = b10 * a00 + b11 * a10 + b12 * a20;
|
|
a[4] = b10 * a01 + b11 * a11 + b12 * a21;
|
|
a[5] = b10 * a02 + b11 * a12 + b12 * a22;
|
|
a[6] = b20 * a00 + b21 * a10 + b22 * a20;
|
|
a[7] = b20 * a01 + b21 * a11 + b22 * a21;
|
|
a[8] = b20 * a02 + b21 * a12 + b22 * a22;
|
|
return a;
|
|
}
|
|
function multiplyVec2(a, b) {
|
|
var z = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
|
|
var a00 = a[0];
|
|
var a01 = a[1];
|
|
var a10 = a[3];
|
|
var a11 = a[4];
|
|
var a20 = a[6];
|
|
var a21 = a[7];
|
|
var b0 = b.x;
|
|
var b1 = b.y;
|
|
return {
|
|
x: b0 * a00 + b1 * a10 + a20 * z,
|
|
y: b0 * a01 + b1 * a11 + a21 * z
|
|
};
|
|
}
|
|
|
|
/**
|
|
* In sigma, the graph is normalized into a [0, 1], [0, 1] square, before being given to the various renderers. This
|
|
* helps to deal with quadtree in particular.
|
|
* But at some point, we need to rescale it so that it takes the best place in the screen, i.e. we always want to see two
|
|
* nodes "touching" opposite sides of the graph, with the camera being at its default state.
|
|
*
|
|
* This function determines this ratio.
|
|
*/
|
|
function getCorrectionRatio(viewportDimensions, graphDimensions) {
|
|
var viewportRatio = viewportDimensions.height / viewportDimensions.width;
|
|
var graphRatio = graphDimensions.height / graphDimensions.width;
|
|
|
|
// If the stage and the graphs are in different directions (such as the graph being wider that tall while the stage
|
|
// is taller than wide), we can stop here to have indeed nodes touching opposite sides:
|
|
if (viewportRatio < 1 && graphRatio > 1 || viewportRatio > 1 && graphRatio < 1) {
|
|
return 1;
|
|
}
|
|
|
|
// Else, we need to fit the graph inside the stage:
|
|
// 1. If the graph is "squarer" (i.e. with a ratio closer to 1), we need to make the largest sides touch;
|
|
// 2. If the stage is "squarer", we need to make the smallest sides touch.
|
|
return Math.min(Math.max(graphRatio, 1 / graphRatio), Math.max(1 / viewportRatio, viewportRatio));
|
|
}
|
|
|
|
/**
|
|
* Function returning a matrix from the current state of the camera.
|
|
*/
|
|
function matrixFromCamera(state, viewportDimensions, graphDimensions, padding, inverse) {
|
|
// TODO: it's possible to optimize this drastically!
|
|
var angle = state.angle,
|
|
ratio = state.ratio,
|
|
x = state.x,
|
|
y = state.y;
|
|
var width = viewportDimensions.width,
|
|
height = viewportDimensions.height;
|
|
var matrix = identity();
|
|
var smallestDimension = Math.min(width, height) - 2 * padding;
|
|
var correctionRatio = getCorrectionRatio(viewportDimensions, graphDimensions);
|
|
if (!inverse) {
|
|
multiply(matrix, scale(identity(), 2 * (smallestDimension / width) * correctionRatio, 2 * (smallestDimension / height) * correctionRatio));
|
|
multiply(matrix, rotate(identity(), -angle));
|
|
multiply(matrix, scale(identity(), 1 / ratio));
|
|
multiply(matrix, translate(identity(), -x, -y));
|
|
} else {
|
|
multiply(matrix, translate(identity(), x, y));
|
|
multiply(matrix, scale(identity(), ratio));
|
|
multiply(matrix, rotate(identity(), angle));
|
|
multiply(matrix, scale(identity(), width / smallestDimension / 2 / correctionRatio, height / smallestDimension / 2 / correctionRatio));
|
|
}
|
|
return matrix;
|
|
}
|
|
|
|
/**
|
|
* All these transformations we apply on the matrix to get it rescale the graph
|
|
* as we want make it very hard to get pixel-perfect distances in WebGL. This
|
|
* function returns a factor that properly cancels the matrix effect on lengths.
|
|
*
|
|
* [jacomyal]
|
|
* To be fully honest, I can't really explain happens here... I notice that the
|
|
* following ratio works (i.e. it correctly compensates the matrix impact on all
|
|
* camera states I could try):
|
|
* > `R = size(V) / size(M * V) / W`
|
|
* as long as `M * V` is in the direction of W (ie. parallel to (Ox)). It works
|
|
* as well with H and a vector that transforms into something parallel to (Oy).
|
|
*
|
|
* Also, note that we use `angle` and not `-angle` (that would seem logical,
|
|
* since we want to anticipate the rotation), because the image is vertically
|
|
* swapped in WebGL.
|
|
*/
|
|
function getMatrixImpact(matrix, cameraState, viewportDimensions) {
|
|
var _multiplyVec = multiplyVec2(matrix, {
|
|
x: Math.cos(cameraState.angle),
|
|
y: Math.sin(cameraState.angle)
|
|
}, 0),
|
|
x = _multiplyVec.x,
|
|
y = _multiplyVec.y;
|
|
return 1 / Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) / viewportDimensions.width;
|
|
}
|
|
|
|
/**
|
|
* Function returning the graph's node extent in x & y.
|
|
*/
|
|
function graphExtent(graph) {
|
|
if (!graph.order) return {
|
|
x: [0, 1],
|
|
y: [0, 1]
|
|
};
|
|
var xMin = Infinity;
|
|
var xMax = -Infinity;
|
|
var yMin = Infinity;
|
|
var yMax = -Infinity;
|
|
graph.forEachNode(function (_, attr) {
|
|
var x = attr.x,
|
|
y = attr.y;
|
|
if (x < xMin) xMin = x;
|
|
if (x > xMax) xMax = x;
|
|
if (y < yMin) yMin = y;
|
|
if (y > yMax) yMax = y;
|
|
});
|
|
return {
|
|
x: [xMin, xMax],
|
|
y: [yMin, yMax]
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Check if the graph variable is a valid graph, and if sigma can render it.
|
|
*/
|
|
function validateGraph(graph) {
|
|
// check if it's a valid graphology instance
|
|
if (!isGraph(graph)) throw new Error("Sigma: invalid graph instance.");
|
|
|
|
// check if nodes have x/y attributes
|
|
graph.forEachNode(function (key, attributes) {
|
|
if (!Number.isFinite(attributes.x) || !Number.isFinite(attributes.y)) {
|
|
throw new Error("Sigma: Coordinates of node ".concat(key, " are invalid. A node must have a numeric 'x' and 'y' attribute."));
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Function used to create DOM elements easily.
|
|
*/
|
|
function createElement(tag, style, attributes) {
|
|
var element = document.createElement(tag);
|
|
if (style) {
|
|
for (var k in style) {
|
|
element.style[k] = style[k];
|
|
}
|
|
}
|
|
if (attributes) {
|
|
for (var _k in attributes) {
|
|
element.setAttribute(_k, attributes[_k]);
|
|
}
|
|
}
|
|
return element;
|
|
}
|
|
|
|
/**
|
|
* Function returning the browser's pixel ratio.
|
|
*/
|
|
function getPixelRatio() {
|
|
if (typeof window.devicePixelRatio !== "undefined") return window.devicePixelRatio;
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Function ordering the given elements in reverse z-order so they drawn
|
|
* the correct way.
|
|
*/
|
|
function zIndexOrdering(_extent, getter, elements) {
|
|
// If k is > n, we'll use a standard sort
|
|
return elements.sort(function (a, b) {
|
|
var zA = getter(a) || 0,
|
|
zB = getter(b) || 0;
|
|
if (zA < zB) return -1;
|
|
if (zA > zB) return 1;
|
|
return 0;
|
|
});
|
|
|
|
// TODO: counting sort optimization
|
|
}
|
|
|
|
/**
|
|
* Factory returning a function normalizing the given node's position & size.
|
|
*/
|
|
|
|
function createNormalizationFunction(extent) {
|
|
var _extent$x = _slicedToArray(extent.x, 2),
|
|
minX = _extent$x[0],
|
|
maxX = _extent$x[1],
|
|
_extent$y = _slicedToArray(extent.y, 2),
|
|
minY = _extent$y[0],
|
|
maxY = _extent$y[1];
|
|
var ratio = Math.max(maxX - minX, maxY - minY),
|
|
dX = (maxX + minX) / 2,
|
|
dY = (maxY + minY) / 2;
|
|
if (ratio === 0 || Math.abs(ratio) === Infinity || isNaN(ratio)) ratio = 1;
|
|
if (isNaN(dX)) dX = 0;
|
|
if (isNaN(dY)) dY = 0;
|
|
var fn = function fn(data) {
|
|
return {
|
|
x: 0.5 + (data.x - dX) / ratio,
|
|
y: 0.5 + (data.y - dY) / ratio
|
|
};
|
|
};
|
|
|
|
// TODO: possibility to apply this in batch over array of indices
|
|
fn.applyTo = function (data) {
|
|
data.x = 0.5 + (data.x - dX) / ratio;
|
|
data.y = 0.5 + (data.y - dY) / ratio;
|
|
};
|
|
fn.inverse = function (data) {
|
|
return {
|
|
x: dX + ratio * (data.x - 0.5),
|
|
y: dY + ratio * (data.y - 0.5)
|
|
};
|
|
};
|
|
fn.ratio = ratio;
|
|
return fn;
|
|
}
|
|
|
|
export { ANIMATE_DEFAULTS as A, getMatrixImpact as a, createElement as b, createNormalizationFunction as c, getPixelRatio as d, easings as e, multiplyVec2 as f, graphExtent as g, animateNodes as h, identity as i, getCorrectionRatio as j, quadraticOut as k, linear as l, matrixFromCamera as m, quadraticInOut as n, cubicIn as o, cubicOut as p, quadraticIn as q, cubicInOut as r, scale as s, rotate as t, translate as u, validateGraph as v, multiply as w, zIndexOrdering as z };
|