Skip to content

Commit 9f900eb

Browse files
History API, icons, various fixes and improvements
1 parent 21b030a commit 9f900eb

16 files changed

+317
-81
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "iknow-entity-browser",
3-
"version": "0.2.6",
3+
"version": "0.3.0",
44
"description": "Visualizer for iKnow entities",
55
"main": "gulpfile.babel.js",
66
"scripts": {
1.17 KB
Binary file not shown.

src/static/fonts/iknowentitybrowsericons.svg

Lines changed: 5 additions & 0 deletions
Loading
1.17 KB
Binary file not shown.
948 Bytes
Binary file not shown.

src/static/index.html

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@
1515
<div id="table">
1616
<i id="tableToggle" class="ui icon-window-list"></i>
1717
<div id="rightTopIcons">
18-
<i id="settingsToggle" class="ui icon-cog"></i>
18+
<i id="settingsToggle" class="ui icon-settings"></i>
19+
</div>
20+
<div id="toolbarIcons">
21+
<i id="dropChildrenButton" class="ui icon-unlink"></i>
22+
<i id="removeButton" class="ui icon-remove"></i>
1923
</div>
2024
<div class="wrapper">
2125
<div class="controls">
22-
<i id="exportCSV" class="ui icon-page-export-csv"></i>
26+
<label>
27+
<i id="exportCSV" class="ui icon-share"></i>
28+
</label>
2329
</div>
2430
<h1>Selected Nodes</h1>
2531
<div class="wrapper">

src/static/js/controls.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* This file describes on-screen controls like UI link/remove buttons, etc.
3+
*/
4+
import { onSelectionUpdate } from "./selection";
5+
6+
let dropChildrenButton = null,
7+
removeButton = null,
8+
selection = [];
9+
10+
onSelectionUpdate((sel) => {
11+
selection = sel;
12+
updateButtons();
13+
});
14+
15+
function updateButtons () {
16+
let display = selection.length ? "block" : "none";
17+
dropChildrenButton.style.display = removeButton.style.display = display;
18+
}
19+
20+
function deleteSelection () {
21+
22+
}
23+
24+
export function init () {
25+
dropChildrenButton = document.getElementById(`dropChildrenButton`);
26+
(removeButton = document.getElementById(`removeButton`)).addEventListener("click",
27+
() => deleteSelection()
28+
);
29+
updateButtons();
30+
}

src/static/js/graph/index.js

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { getGraphData } from "../model";
1+
import { onModelUpdate, unfold } from "../model";
22
import { updateSelection, setLastSelectedNode } from "../selection";
33

44
let shiftKey, ctrlKey,
55
width = window.innerWidth,
6-
height = window.innerHeight;
6+
height = window.innerHeight,
7+
lastGraph = null;
78

89
let svg = null,
910
brush = null,
@@ -20,18 +21,7 @@ let svg = null,
2021
.on("start", dragstarted)
2122
.on("drag", dragged)
2223
.on("end", dragended),
23-
simulation = d3.forceSimulation()
24-
.force("link",
25-
d3.forceLink()
26-
.distance(d => 50 + (d.source.radius + d.target.radius) * 2)
27-
.id(d => d.id)
28-
)
29-
.force("charge",
30-
d3.forceManyBody()
31-
.strength(d => { return -10 * d.radius; })
32-
)
33-
.force("center", d3.forceCenter(width / 2, height / 2))
34-
.on("tick", ticked),
24+
simulation = newSimulation(),
3525
brusher = d3.brush()
3626
.extent([[-9999999, -9999999], [9999999, 9999999]])
3727
.on("start.brush", () => {
@@ -61,6 +51,21 @@ let svg = null,
6151
}),
6252
view = null;
6353

54+
function newSimulation () {
55+
return d3.forceSimulation()
56+
.force("link",
57+
d3.forceLink()
58+
.distance(d => 30 + (d.source.radius + d.target.radius) * 2)
59+
.id(d => d.id)
60+
)
61+
.force("charge",
62+
d3.forceManyBody()
63+
.strength(d => { return -7 * d.radius; })
64+
)
65+
.force("center", d3.forceCenter(width / 2, height / 2))
66+
.on("tick", ticked);
67+
}
68+
6469
function ticked () {
6570
if (!link)
6671
return;
@@ -168,26 +173,24 @@ function flattenEdges (root) {
168173

169174
}
170175

171-
function resetChildrenPosition (parent, children = []) {
172-
if (!children || !children.length)
173-
return;
174-
for (let c of children) {
175-
c.x = parent.x;
176-
c.y = parent.y;
177-
if (c.children)
178-
resetChildrenPosition(c, c.children);
176+
onModelUpdate((graph, force) => update(graph, force));
177+
178+
export function update (g = lastGraph, reset = false) {
179+
180+
if (!reset) {
181+
// g = JSON.parse(JSON.stringify(g));
182+
// g.id = -100;
179183
}
180-
}
181184

182-
export function update (reset = false) {
185+
let fl = flatten(g);
183186

184-
let g = getGraphData().foldedTree,
185-
fl = flatten(g),
186-
graph = {
187+
let graph = {
187188
nodes: fl,
188189
edges: flattenEdges(g)
189190
};
190191

192+
lastGraph = g;
193+
191194
if (reset) {
192195
link = link.data([]);
193196
link.exit().remove();
@@ -206,21 +209,17 @@ export function update (reset = false) {
206209
);
207210
link = linkEnter.merge(link);
208211

209-
node = nodes.selectAll(".node").data(graph.nodes, (d) => d.id);
212+
node = nodes.selectAll(".node").data(graph.nodes, function (d) { return this._id || d.id; });
210213
node.exit().remove();
211214
let nodeEnter = node.enter().append("g")
215+
.each(function (d) { this._id = d.id; })
212216
.attr("class", d => `node${ d.id === 0 ? " root" : "" } ${ d.type || "unknown" }`)
213217
.call(dragger)
214218
.on("dblclick", function (d) {
215219
d3.event.stopPropagation();
216-
if (d.type === "folder" && d._children && d._children.length) {
217-
let next = d._children.splice(0, 20),
218-
left = parseInt(d.label) - 20;
219-
resetChildrenPosition(d, next);
220-
d.children = d.children.concat(next);
221-
d.label = left > 0 ? `${ left } more` : `Others`;
222-
d3.select(this).select("text").text(d.label);
223-
update();
220+
if (unfold(d)) {
221+
d.fx = d.x; d.fy = d.y;
222+
setTimeout(() => d.fx = d.fy = null, 500);
224223
}
225224
})
226225
.on("click", function (d) {
@@ -242,12 +241,15 @@ export function update (reset = false) {
242241
.text(d => d.label);
243242
node = nodeEnter.merge(node);
244243

244+
if (reset)
245+
simulation = newSimulation();
246+
245247
simulation
246248
.nodes(graph.nodes)
247249
.force("link")
248250
.links(graph.edges);
249251

250-
simulation.restart();
252+
simulation.alpha(reset ? 1 : 0.4).restart();
251253

252254
brush.call(brusher)
253255
.on(".brush", null);
@@ -256,6 +258,7 @@ export function update (reset = false) {
256258

257259
if (reset) {
258260
for (let i = 100; i > 0; --i) simulation.tick();
261+
updateSelection();
259262
}
260263

261264
}

src/static/js/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as details from "./details";
44
import * as settings from "./settings";
55
import * as source from "./source";
66
import * as model from "./model";
7+
import * as controls from "./controls";
78

89
window.init = () => {
910

@@ -12,6 +13,8 @@ window.init = () => {
1213
settings.init();
1314
source.init();
1415
graph.init();
16+
controls.init();
17+
model.init();
1518
model.update(() => graph.update(true));
1619

1720
};

src/static/js/model/history.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
let history = [],
2+
redoHistory = [];
3+
4+
export function createState ({ undo, redo } = {}) {
5+
if (typeof undo !== "function" || typeof redo !== "function")
6+
throw new Error("Undo and Redo must be both functions");
7+
redoHistory = [];
8+
history.push({ undo, redo });
9+
}
10+
11+
export function undo () {
12+
let undoed = history.pop();
13+
if (!undoed)
14+
return;
15+
redoHistory.push(undoed);
16+
undoed.undo();
17+
}
18+
19+
export function redo () {
20+
let redoed = redoHistory.pop();
21+
if (!redoed)
22+
return;
23+
history.push(redoed);
24+
redoed.redo();
25+
}
26+
27+
window.undo = undo;
28+
window.redo = redo;

0 commit comments

Comments
 (0)