vis.js is a dynamic, browser-based visualization library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

246 lines
7.0 KiB

/**
* Created by Alex on 26-Feb-15.
*/
if (typeof window !== 'undefined') {
window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
}
class CanvasRenderer {
constructor(body) {
this.body = body;
this.redrawRequested = false;
this.renderTimer = false;
this.requiresTimeout = true;
this.continueRendering = true;
this.renderRequests = 0;
this.translation = {x: 0, y: 0};
this.scale = 1.0;
this.canvasTopLeft = {x: 0, y: 0};
this.canvasBottomRight = {x: 0, y: 0};
this.body.emitter.on("_setScale", (scale) => this.scale = scale);
this.body.emitter.on("_setTranslation", (translation) => {this.translation.x = translation.x; this.translation.y = translation.y;});
this.body.emitter.on("_redraw", this._redraw.bind(this));
this.body.emitter.on("_redrawHidden", this._redraw.bind(this, true));
this.body.emitter.on("_requestRedraw", this._requestRedraw.bind(this));
this.body.emitter.on("_startRendering", () => {this.renderRequests += 1; this.continueRendering = true; this.startRendering();});
this.body.emitter.on("_stopRendering", () => {this.renderRequests -= 1; this.continueRendering = this.renderRequests > 0;});
this._determineBrowserMethod();
}
startRendering() {
if (this.continueRendering === true) {
if (!this.renderTimer) {
if (this.requiresTimeout == true) {
this.renderTimer = window.setTimeout(this.renderStep.bind(this), this.simulationInterval); // wait this.renderTimeStep milliseconds and perform the animation step function
}
else {
this.renderTimer = window.requestAnimationFrame(this.renderStep.bind(this)); // wait this.renderTimeStep milliseconds and perform the animation step function
}
}
}
else {
}
}
renderStep() {
// reset the renderTimer so a new scheduled animation step can be set
this.renderTimer = undefined;
if (this.requiresTimeout == true) {
// this schedules a new simulation step
this.startRendering();
}
this._redraw();
if (this.requiresTimeout == false) {
// this schedules a new simulation step
this.startRendering();
}
}
setCanvas(canvas) {
this.canvas = canvas;
}
/**
* Redraw the network with the current data
* chart will be resized too.
*/
redraw() {
this.setSize(this.constants.width, this.constants.height);
this._redraw();
}
/**
* Redraw the network with the current data
* @param hidden | used to get the first estimate of the node sizes. only the nodes are drawn after which they are quickly drawn over.
* @private
*/
_requestRedraw(hidden) {
if (this.redrawRequested !== true) {
this.redrawRequested = true;
if (this.requiresTimeout === true) {
window.setTimeout(this._redraw.bind(this, hidden),0);
}
else {
window.requestAnimationFrame(this._redraw.bind(this, hidden, true));
}
}
}
_redraw(hidden = false) {
this.body.emitter.emit("_beforeRender");
this.redrawRequested = false;
var ctx = this.canvas.frame.canvas.getContext('2d');
ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
// clear the canvas
var w = this.canvas.frame.canvas.clientWidth;
var h = this.canvas.frame.canvas.clientHeight;
ctx.clearRect(0, 0, w, h);
// set scaling and translation
ctx.save();
ctx.translate(this.translation.x, this.translation.y);
ctx.scale(this.scale, this.scale);
this.canvasTopLeft = this.canvas.DOMtoCanvas({x:0,y:0});
this.canvasBottomRight = this.canvas.DOMtoCanvas({x:this.canvas.frame.canvas.clientWidth,y:this.canvas.frame.canvas.clientHeight});
if (hidden === false) {
// todo: solve this
//if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideEdgesOnDrag == false) {
this._drawEdges(ctx);
//}
}
// todo: solve this
//if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideNodesOnDrag == false) {
this._drawNodes(ctx, this.body.nodes, hidden);
//}
if (hidden === false) {
if (this.controlNodesActive == true) {
this._drawControlNodes(ctx);
}
}
//this._drawNodes(ctx,this.body.supportNodes,true);
// this.physics.nodesSolver._debug(ctx,"#F00F0F");
// restore original scaling and translation
ctx.restore();
if (hidden === true) {
ctx.clearRect(0, 0, w, h);
}
}
/**
* Redraw all nodes
* The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d');
* @param {CanvasRenderingContext2D} ctx
* @param {Boolean} [alwaysShow]
* @private
*/
_drawNodes(ctx,nodes,alwaysShow = false) {
// first draw the unselected nodes
var selected = [];
for (var id in nodes) {
if (nodes.hasOwnProperty(id)) {
nodes[id].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight);
if (nodes[id].isSelected()) {
selected.push(id);
}
else {
if (alwaysShow === true) {
nodes[id].draw(ctx);
}
else if (nodes[id].inArea() === true) {
nodes[id].draw(ctx);
}
}
}
}
// draw the selected nodes on top
for (var s = 0, sMax = selected.length; s < sMax; s++) {
if (nodes[selected[s]].inArea() || alwaysShow) {
nodes[selected[s]].draw(ctx);
}
}
}
/**
* Redraw all edges
* The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d');
* @param {CanvasRenderingContext2D} ctx
* @private
*/
_drawEdges(ctx) {
var edges = this.body.edges;
for (var id in edges) {
if (edges.hasOwnProperty(id)) {
var edge = edges[id];
edge.setScale(this.scale);
if (edge.connected === true) {
edges[id].draw(ctx);
}
}
}
}
/**
* Redraw all edges
* The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d');
* @param {CanvasRenderingContext2D} ctx
* @private
*/
_drawControlNodes(ctx) {
var edges = this.body.edges;
for (var id in edges) {
if (edges.hasOwnProperty(id)) {
edges[id]._drawControlNodes(ctx);
}
}
}
/**
* Determine if the browser requires a setTimeout or a requestAnimationFrame. This was required because
* some implementations (safari and IE9) did not support requestAnimationFrame
* @private
*/
_determineBrowserMethod() {
if (typeof window !== 'undefined') {
var browserType = navigator.userAgent.toLowerCase();
this.requiresTimeout = false;
if (browserType.indexOf('msie 9.0') != -1) { // IE 9
this.requiresTimeout = true;
}
else if (browserType.indexOf('safari') != -1) { // safari
if (browserType.indexOf('chrome') <= -1) {
this.requiresTimeout = true;
}
}
}
else {
this.requiresTimeout = true;
}
}
}
export {CanvasRenderer};