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:
commit
7466c269c6
6 changed files with 88 additions and 54 deletions
122
dist/workers/graph.js
vendored
122
dist/workers/graph.js
vendored
|
@ -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) => {
|
||||
|
|
4
dist/workers/lib/util.js
vendored
4
dist/workers/lib/util.js
vendored
|
@ -78,4 +78,8 @@ class Util {
|
|||
this.ctx.restore();
|
||||
};
|
||||
|
||||
arrayUnique (a) {
|
||||
return [ ...new Set(a) ];
|
||||
};
|
||||
|
||||
};
|
|
@ -1173,6 +1173,7 @@
|
|||
"menuGraphSettingsLinks": "Links",
|
||||
"menuGraphSettingsRelations": "Relations",
|
||||
"menuGraphSettingsUnlinkedObjects": "Unlinked Objects",
|
||||
"menuGraphSettingsLocal": "Local graph",
|
||||
|
||||
"menuHelpWhatsNew": "What's New",
|
||||
"menuHelpShortcut": "Keyboard Shortcuts",
|
||||
|
|
|
@ -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') },
|
||||
]
|
||||
}
|
||||
];
|
||||
|
|
|
@ -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[]) {
|
||||
|
|
|
@ -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: '',
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue