1
0
Fork 0
mirror of https://github.com/anyproto/anytype-ts.git synced 2025-06-10 01:51:10 +09:00

Merge pull request #336 from anyproto/feature/JS-3184-local-graph

Feature/JS-3184: Local graph
This commit is contained in:
Razor 2023-11-14 12:08:58 +01:00 committed by GitHub
commit 7466c269c6
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 88 additions and 54 deletions

122
dist/workers/graph.js vendored
View file

@ -15,6 +15,7 @@ const util = new Util();
// CONSTANTS
const transformThreshold = 1.5;
const delayFocus = 1000;
const ObjectLayout = {
Human: 1,
@ -70,7 +71,9 @@ let edgeMap = new Map();
let hoverAlpha = 0.2;
let fontFamily = 'Helvetica, san-serif';
let timeoutHover = 0;
let rootId = '';
let root = null;
let paused = false;
addEventListener('message', ({ data }) => {
if (this[data.id]) {
@ -82,7 +85,7 @@ init = (param) => {
data = param;
canvas = data.canvas;
settings = data.settings;
rootId = data.rootId;
ctx = canvas.getContext('2d');
util.ctx = ctx;
@ -99,25 +102,10 @@ init = (param) => {
initForces();
simulation.on('tick', () => { redraw(); });
simulation.on('tick', () => redraw());
simulation.tick(100);
// Center initially on root node
setTimeout(() => {
root = getNodeById(data.rootId);
let x = width / 2;
let y = height / 2;
if (root) {
x = root.x;
y = root.y;
};
transform = Object.assign(transform, getCenter(x, y));
send('onTransform', { ...transform });
redraw();
}, 100);
setTimeout(() => this.setRootId({ rootId }), 100);
};
initTheme = (theme) => {
@ -202,7 +190,7 @@ initForces = () => {
};
updateForces = () => {
let old = getNodeMap();
const old = getNodeMap();
edges = util.objectCopy(data.edges);
nodes = util.objectCopy(data.nodes);
@ -217,6 +205,14 @@ updateForces = () => {
edges = edges.filter(d => d.type != EdgeType.Relation);
};
// Filte local only edges
if (settings.local) {
edges = edges.filter(d => (d.source == rootId) || (d.target == rootId));
const nodeIds = util.arrayUnique([ rootId ].concat(edges.map(d => d.source)).concat(edges.map(d => d.target)));
nodes = nodes.filter(d => nodeIds.includes(d.id));
};
let map = getNodeMap();
edges = edges.filter(d => map.get(d.source) && map.get(d.target));
@ -237,7 +233,9 @@ updateForces = () => {
edges = edges.filter(d => map.get(d.source) && map.get(d.target));
// Shallow copy to disable mutations
nodes = nodes.map(d => Object.assign(old.get(d.id) || {}, d));
nodes = nodes.map(d => {
return Object.assign(old.get(d.id) || { x: width / 2, y: width / 2 }, d);
});
edges = edges.map(d => Object.assign({}, d));
simulation.nodes(nodes);
@ -258,16 +256,28 @@ updateForces = () => {
};
updateSettings = (param) => {
const needUpdate = (param.link != settings.link) ||
(param.relation != settings.relation) ||
(param.orphan != settings.orphan);
const updateKeys = [ 'link', 'relation', 'orphan', 'local' ];
let needUpdate = false;
let needFocus = false;
for (let key of updateKeys) {
if (param[key] != settings[key]) {
needUpdate = true;
if (key == 'local') {
needFocus = true;
};
break;
};
};
settings = Object.assign(settings, param);
needUpdate ? updateForces() : redraw();
if (needUpdate) {
updateForces();
} else {
redraw();
if (needFocus) {
setTimeout(() => this.setRootId({ rootId }), delayFocus);
};
};
@ -289,7 +299,7 @@ draw = (t) => {
ctx.font = getFont();
edges.forEach(d => {
drawLine(d, radius, radius * 1.3, settings.marker && d.isDouble, settings.marker);
drawEdge(d, radius, radius * 1.3, settings.marker && d.isDouble, settings.marker);
});
nodes.forEach(d => {
@ -303,10 +313,12 @@ draw = (t) => {
redraw = () => {
cancelAnimationFrame(frame);
frame = requestAnimationFrame(draw);
if (!paused) {
frame = requestAnimationFrame(draw);
};
};
drawLine = (d, arrowWidth, arrowHeight, arrowStart, arrowEnd) => {
drawEdge = (d, arrowWidth, arrowHeight, arrowStart, arrowEnd) => {
const x1 = d.source.x;
const y1 = d.source.y;
const r1 = getRadius(d.source);
@ -577,6 +589,22 @@ onSelect = ({ x, y, selectRelated }) => {
};
};
onSetRootId = ({ x, y }) => {
const d = getNodeByCoords(x, y);
if (d) {
this.setRootId({ rootId: d.id });
};
};
onSetEdges = (param) => {
data.edges = param.edges;
updateForces();
};
onSetSelected = ({ ids }) => {
selected = ids;
};
onMouseMove = ({ x, y }) => {
const active = nodes.find(d => d.isOver);
const d = getNodeByCoords(x, y);
@ -618,12 +646,11 @@ onContextMenu = ({ x, y }) => {
const d = getNodeByCoords(x, y);
if (!d) {
send('onContextSpaceClick', { x, y });
return;
} else {
send('onContextMenu', { node: d, x, y });
d.isOver = true;
redraw();
};
d.isOver = true;
send('onContextMenu', { node: d, x, y });
redraw();
};
onAddNode = ({ target, sourceId }) => {
@ -667,21 +694,12 @@ onRemoveNode = ({ ids }) => {
data.edges = data.edges.filter(d => !ids.includes(d.source.id) && !ids.includes(d.target.id));
updateForces();
redraw();
};
onSetEdges = (param) => {
data.edges = param.edges;
setRootId = (param) => {
rootId = param.rootId;
root = getNodeById(rootId);
updateForces();
};
onSetSelected = ({ ids }) => {
selected = ids;
};
onSetRootId = ({ rootId }) => {
root = nodes.find(d => d.id == rootId);
if (!root) {
return;
};
@ -696,12 +714,14 @@ onSetRootId = ({ rootId }) => {
transform = Object.assign(transform, coords);
redraw();
})
.onComplete(() => {
send('onTransform', { ...transform });
})
.onComplete(() => send('onTransform', { ...transform }))
.start();
redraw();
if (settings.local) {
updateForces();
} else {
redraw();
};
};
restart = (alpha) => {

View file

@ -78,4 +78,8 @@ class Util {
this.ctx.restore();
};
arrayUnique (a) {
return [ ...new Set(a) ];
};
};

View file

@ -1173,6 +1173,7 @@
"menuGraphSettingsLinks": "Links",
"menuGraphSettingsRelations": "Relations",
"menuGraphSettingsUnlinkedObjects": "Unlinked Objects",
"menuGraphSettingsLocal": "Local graph",
"menuHelpWhatsNew": "What's New",
"menuHelpShortcut": "Keyboard Shortcuts",

View file

@ -99,6 +99,7 @@ const MenuGraphSettings = observer(class MenuGraphSettings extends React.Compone
{ id: 'link', name: translate('menuGraphSettingsLinks') },
{ id: 'relation', name: translate('menuGraphSettingsRelations') },
{ id: 'orphan', name: translate('menuGraphSettingsUnlinkedObjects') },
{ id: 'local', name: translate('menuGraphSettingsLocal') },
]
}
];

View file

@ -83,7 +83,7 @@ const Graph = observer(class Graph extends React.Component<Props> {
this.unbind();
win.on('updateGraphSettings.graph', () => { this.updateSettings(); });
win.on('updateGraphRoot.graph', (e: any, data: any) => { this.setRootId(data.id); });
win.on('updateGraphRoot.graph', (e: any, data: any) => this.setRootId(data.id));
win.on('updateTheme.graph', () => { this.send('updateTheme', { theme: commonStore.getThemeClass() }); });
};
@ -138,8 +138,14 @@ const Graph = observer(class Graph extends React.Component<Props> {
.call(this.zoom)
.call(this.zoom.transform, d3.zoomIdentity.translate(0, 0).scale(1.5))
.on('click', (e: any) => {
const { local } = commonStore.graph;
const [ x, y ] = d3.pointer(e);
this.send(e.shiftKey ? 'onSelect' : 'onClick', { x, y });
if (local) {
this.send('onSetRootId', { x, y });
} else {
this.send(e.shiftKey ? 'onSelect' : 'onClick', { x, y });
};
})
.on('dblclick', (e: any) => {
if (e.shiftKey) {
@ -464,7 +470,7 @@ const Graph = observer(class Graph extends React.Component<Props> {
};
setRootId (id: string) {
this.send('onSetRootId', { rootId: id });
this.send('setRootId', { rootId: id });
};
send (id: string, param: any, transfer?: any[]) {

View file

@ -16,6 +16,7 @@ interface Graph {
label: boolean;
relation: boolean;
link: boolean;
local: boolean;
filter: string;
};
@ -64,6 +65,7 @@ class CommonStore {
label: true,
relation: true,
link: true,
local: false,
filter: '',
};