disabling link map animation, closes #684

This commit is contained in:
zadam 2019-11-05 20:59:20 +01:00
parent 9c9ef1c7b4
commit a2c78e2c5c
5 changed files with 73 additions and 141 deletions

View File

@ -191,7 +191,7 @@
this.addNodes.apply(this, json['nodes']); this.addNodes.apply(this, json['nodes']);
this.addEdges.apply(this, json['edges']); this.addEdges.apply(this, json['edges']);
} }
} };
// find the edges from node1 to node2 // find the edges from node1 to node2
@ -479,51 +479,35 @@
return energy; return energy;
}; };
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; // stolen from coffeescript, thanks jashkenas! ;-)
Springy.requestAnimationFrame = __bind(this.requestAnimationFrame ||
this.webkitRequestAnimationFrame ||
this.mozRequestAnimationFrame ||
this.oRequestAnimationFrame ||
this.msRequestAnimationFrame ||
(function(callback, element) {
this.setTimeout(callback, 10);
}), this);
/** /**
* Start simulation if it's not running already. * Start simulation if it's not running already.
* In case it's running then the call is ignored, and none of the callbacks passed is ever executed. * In case it's running then the call is ignored, and none of the callbacks passed is ever executed.
*/ */
Layout.ForceDirected.prototype.start = function(render, onRenderStop, onRenderStart) { Layout.ForceDirected.prototype.start = function(onRenderStop) {
var t = this; var t = this;
if (this._started) return; if (this._started) return;
this._started = true; this._started = true;
this._stop = false; this._stop = false;
if (onRenderStart !== undefined) { onRenderStart(); } function step() {
Springy.requestAnimationFrame(function step() {
t.tick(0.03); t.tick(0.03);
if (!t._stop && render !== undefined) {
render();
}
// stop simulation when energy of the system goes below a threshold // stop simulation when energy of the system goes below a threshold
if (t._stop || t.totalEnergy() < t.minEnergyThreshold) { if (t._stop || t.totalEnergy() < t.minEnergyThreshold) {
t._started = false; t._started = false;
if (onRenderStop !== undefined) { onRenderStop(); } onRenderStop();
} else { } else {
Springy.requestAnimationFrame(step); setImmediate(step);
} }
}); }
step();
}; };
Layout.ForceDirected.prototype.stop = function() { Layout.ForceDirected.prototype.stop = function() {
this._stop = true; this._stop = true;
} };
Layout.ForceDirected.prototype.tick = function(timestep) { Layout.ForceDirected.prototype.tick = function(timestep) {
this.applyCoulombsLaw(); this.applyCoulombsLaw();
@ -644,85 +628,35 @@
/** /**
* Renderer handles the layout rendering loop * Renderer handles the layout rendering loop
* @param onRenderStop optional callback function that gets executed whenever rendering stops.
* @param onRenderStart optional callback function that gets executed whenever rendering starts.
* @param onRenderFrame optional callback function that gets executed after each frame is rendered.
*/ */
var Renderer = Springy.Renderer = function(layout, clear, drawEdge, drawNode, onRenderStop, onRenderStart, onRenderFrame) { var Renderer = Springy.Renderer = function(layout, onRenderStop) {
this.layout = layout; this.layout = layout;
this.clear = clear;
this.drawEdge = drawEdge;
this.drawNode = drawNode;
this.onRenderStop = onRenderStop; this.onRenderStop = onRenderStop;
this.onRenderStart = onRenderStart;
this.onRenderFrame = onRenderFrame;
this.layout.graph.addGraphListener(this); this.layout.graph.addGraphListener(this);
} };
Renderer.prototype.graphChanged = function(e) { Renderer.prototype.graphChanged = function() {
this.start(); this.start();
}; };
/** /**
* Starts the simulation of the layout in use. * Starts the simulation of the layout in use.
*
* Note that in case the algorithm is still or already running then the layout that's in use
* might silently ignore the call, and your optional <code>done</code> callback is never executed.
* At least the built-in ForceDirected layout behaves in this way.
*
* @param done An optional callback function that gets executed when the springy algorithm stops,
* either because it ended or because stop() was called.
*/ */
Renderer.prototype.start = function(done) { Renderer.prototype.start = function(maxTime) {
var t = this; if (maxTime) {
this.layout.start(function render() { setTimeout(() => this.stop(), maxTime);
t.clear(); }
t.layout.eachEdge(function(edge, spring) { return new Promise((res, rej) => {
t.drawEdge(edge, spring.point1.p, spring.point2.p); this.layout.start(res);
}); });
t.layout.eachNode(function(node, point) {
t.drawNode(node, point.p);
});
if (t.onRenderFrame !== undefined) { t.onRenderFrame(); }
}, this.onRenderStop, this.onRenderStart);
}; };
Renderer.prototype.stop = function() { Renderer.prototype.stop = function() {
this.layout.stop(); this.layout.stop();
}; };
// Array.forEach implementation for IE support..
//https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach
if ( !Array.prototype.forEach ) {
Array.prototype.forEach = function( callback, thisArg ) {
var T, k;
if ( this == null ) {
throw new TypeError( " this is null or not defined" );
}
var O = Object(this);
var len = O.length >>> 0; // Hack to convert O.length to a UInt32
if ( {}.toString.call(callback) != "[object Function]" ) {
throw new TypeError( callback + " is not a function" );
}
if ( thisArg ) {
T = thisArg;
}
k = 0;
while( k < len ) {
var kValue;
if ( k in O ) {
kValue = O[ k ];
callback.call( T, kValue, k, O );
}
k++;
}
};
}
var isEmpty = function(obj) { var isEmpty = function(obj) {
for (var k in obj) { for (var k in obj) {
if (obj.hasOwnProperty(k)) { if (obj.hasOwnProperty(k)) {

View File

@ -23,19 +23,18 @@ export async function showDialog() {
// set default settings // set default settings
$maxNotesInput.val(20); $maxNotesInput.val(20);
const note = noteDetailService.getActiveTabNote();
if (!note) {
return;
}
$linkMapContainer.css("height", $("body").height() - 150); $linkMapContainer.css("height", $("body").height() - 150);
linkMapService = new LinkMapService(note, $linkMapContainer, getOptions()); $linkMapContainer.empty();
linkMapService.render();
$dialog.modal(); $dialog.modal();
} }
$dialog.on('shown.bs.modal', () => {
const note = noteDetailService.getActiveTabNote();
linkMapService = new LinkMapService(note, $linkMapContainer, getOptions());
linkMapService.render();
});
$maxNotesInput.on("input", () => linkMapService.loadNotesAndRelations(getOptions())); $maxNotesInput.on("input", () => linkMapService.loadNotesAndRelations(getOptions()));

View File

@ -119,14 +119,27 @@ export default class LinkMap {
stop: params => {} stop: params => {}
}); });
return $noteBox; return $noteBox;
}; };
this.renderer = new Springy.Renderer( this.renderer = new Springy.Renderer(layout);
layout, await this.renderer.start(500);
() => {},
(edge, p1, p2) => { layout.eachNode((node, point) => {
const $noteBox = getNoteBox(node.id);
const middleW = this.$linkMapContainer.width() / 2;
const middleH = this.$linkMapContainer.height() / 2;
$noteBox
.css("left", (middleW + point.p.x * 100) + "px")
.css("top", (middleH + point.p.y * 100) + "px");
if ($noteBox.hasClass("link-map-active-note")) {
this.moveToCenterOfElement($noteBox[0]);
}
});
layout.eachEdge(edge => {
const connectionId = this.linkMapContainerId + '-' + edge.source.id + '-' + edge.target.id; const connectionId = this.linkMapContainerId + '-' + edge.source.id + '-' + edge.target.id;
if ($("#" + connectionId).length > 0) { if ($("#" + connectionId).length > 0) {
@ -151,29 +164,10 @@ export default class LinkMap {
else { else {
console.log(`connection not created for`, edge); console.log(`connection not created for`, edge);
} }
}, });
(node, p) => {
const $noteBox = getNoteBox(node.id);
const middleW = this.$linkMapContainer.width() / 2;
const middleH = this.$linkMapContainer.height() / 2;
$noteBox
.css("left", (middleW + p.x * 100) + "px")
.css("top", (middleH + p.y * 100) + "px");
if ($noteBox.hasClass("link-map-active-note")) {
this.moveToCenterOfElement($noteBox[0]);
}
},
() => {},
() => {},
() => {
this.jsPlumbInstance.repaintEverything(); this.jsPlumbInstance.repaintEverything();
} }
);
this.renderer.start();
}
moveToCenterOfElement(element) { moveToCenterOfElement(element) {
const elemBounds = element.getBoundingClientRect(); const elemBounds = element.getBoundingClientRect();

View File

@ -29,6 +29,7 @@ class LinkMapWidget extends StandardWidget {
} }
async doRenderBody() { async doRenderBody() {
this.$body.css('opacity', 0);
this.$body.html(TPL); this.$body.html(TPL);
const $linkMapContainer = this.$body.find('.link-map-container'); const $linkMapContainer = this.$body.find('.link-map-container');
@ -43,6 +44,8 @@ class LinkMapWidget extends StandardWidget {
}); });
await this.linkMapService.render(); await this.linkMapService.render();
this.$body.animate({opacity: 1}, 300);
} }
cleanup() { cleanup() {

View File

@ -64,7 +64,9 @@ async function update(name, value) {
return false; return false;
} }
if (name !== 'openTabs') {
log.info(`Updating option ${name} to ${value}`); log.info(`Updating option ${name} to ${value}`);
}
await optionService.setOption(name, value); await optionService.setOption(name, value);