Browse Source

made labels seperate. Needs cleaning up and comments

flowchartTest
Alex de Mulder 9 years ago
parent
commit
3fda5397c4
9 changed files with 2197 additions and 1974 deletions
  1. +1197
    -1032
      dist/vis.js
  2. +6
    -9
      examples/network/01_basic_usage.html
  3. +4
    -6
      lib/network/modules/CanvasRenderer.js
  4. +14
    -22
      lib/network/modules/NodesHandler.js
  5. +84
    -139
      lib/network/modules/components/edges/EdgeMain.js
  6. +684
    -763
      lib/network/modules/components/nodes/NodeMain.js
  7. +21
    -0
      lib/network/modules/components/nodes/ellipse.js
  8. +187
    -0
      lib/network/modules/components/unified/label.js
  9. +0
    -3
      lib/network/modules/components/unified/labels.js

+ 1197
- 1032
dist/vis.js
File diff suppressed because it is too large
View File


+ 6
- 9
examples/network/01_basic_usage.html View File

@ -23,21 +23,18 @@
// create an array with nodes // create an array with nodes
var nodes = [ var nodes = [
{id: 1, label: 'Node 1'}, {id: 1, label: 'Node 1'},
{id: 2, label: 'Node 2'},
{id: 2, label: 'Node 2', shape:'dot'},
{id: 3, label: 'Node 3'}, {id: 3, label: 'Node 3'},
{id: 4, label: 'Node 4'}, {id: 4, label: 'Node 4'},
{id: 5, label: 'Node 5', shape:'database'}
{id: 5, label: 'Node 5'}
]; ];
// create an array with edges // create an array with edges
var edges = [ var edges = [
// {from: 1, to: 2, label:'bla', font:{size: 15, face: 'arial', color: 'red'}},
{from: 1, to: 3, arrows:{from:false, to:false, middle: true}, label:'bla', dashes:true},
{from: 1, to: 2, arrows:{from:false, to:false, middle: true}, smooth:false, label:'bla'},
{from: 4, to: 4, arrows:{from:false, to:false, middle: true}, smooth:false, label:'bla'},
{from: 5, to: 5, arrows:{from:false, to:false, middle: true}, smooth:false, label:'bla'},
// {from: 2, to: 4},
// {from: 2, to: 5}
{from: 1, to: 3, label:'bla1'},
{from: 1, to: 2, label:'bla2'},
{from: 2, to: 4, label:'bla4'},
{from: 2, to: 5, label:'bla5', font:{align:'top'}}
]; ];
// create a network // create a network

+ 4
- 6
lib/network/modules/CanvasRenderer.js View File

@ -184,7 +184,6 @@ class CanvasRenderer {
// draw unselected nodes; // draw unselected nodes;
for (let i = 0; i < nodeIndices.length; i++) { for (let i = 0; i < nodeIndices.length; i++) {
node = nodes[nodeIndices[i]]; node = nodes[nodeIndices[i]];
node.setScaleAndPos(this.body.view.scale,this.canvasTopLeft,this.canvasBottomRight);
// set selected nodes aside // set selected nodes aside
if (node.isSelected()) { if (node.isSelected()) {
selected.push(nodeIndices[i]); selected.push(nodeIndices[i]);
@ -193,18 +192,17 @@ class CanvasRenderer {
if (alwaysShow === true) { if (alwaysShow === true) {
node.draw(ctx); node.draw(ctx);
} }
else if (node.inArea() === true) {
// todo: replace check
//else if (node.inArea() === true) {
node.draw(ctx); node.draw(ctx);
}
//}
} }
} }
// draw the selected nodes on top // draw the selected nodes on top
for (let i = 0; i < selected.length; i++) { for (let i = 0; i < selected.length; i++) {
node = nodes[selected[i]]; node = nodes[selected[i]];
if (node.inArea() || alwaysShow) {
node.draw(ctx);
}
node.draw(ctx);
} }
} }

+ 14
- 22
lib/network/modules/NodesHandler.js View File

@ -5,8 +5,8 @@
var util = require("../../util"); var util = require("../../util");
var DataSet = require('../../DataSet'); var DataSet = require('../../DataSet');
var DataView = require('../../DataView'); var DataView = require('../../DataView');
var Node = require("./components/nodes/NodeMain");
import Node from "./components/nodes/NodeMain";
class NodesHandler { class NodesHandler {
constructor(body, images, groups, layoutEngine) { constructor(body, images, groups, layoutEngine) {
@ -28,9 +28,7 @@ class NodesHandler {
this.options = {}; this.options = {};
this.defaultOptions = { this.defaultOptions = {
mass: 1, mass: 1,
//radiusMin: 10,
//radiusMax: 30,
radius: 10,
size: 10,
scaling: { scaling: {
min: 10, min: 10,
max: 40, max: 40,
@ -53,21 +51,15 @@ class NodesHandler {
}, },
shape: 'ellipse', shape: 'ellipse',
image: undefined, // --> URL image: undefined, // --> URL
//widthMin: 16, // px
//widthMax: 64, // px
label: undefined, label: undefined,
labelStyle: {
fontColor: 'black',
fontSize: 14, // px
fontFace: 'verdana',
fontFill: undefined,
fontStrokeWidth: 0, // px
fontStrokeColor: '#ffffff',
//scaleFontWithValue: false,
//fontSizeMin: 14,
//fontSizeMax: 30,
//fontSizeMaxVisible: 30,
//fontDrawThreshold: 3
font: {
color: '#343434',
size: 14, // px
face: 'arial',
background: 'none',
stroke: 0, // px
strokeColor: 'white',
align:'horizontal'
}, },
value: 1, value: 1,
color: { color: {
@ -159,8 +151,8 @@ class NodesHandler {
var newNodes = []; var newNodes = [];
for (var i = 0; i < ids.length; i++) { for (var i = 0; i < ids.length; i++) {
id = ids[i]; id = ids[i];
var data = this.body.data.nodes.get(id);
var node = new Node(data, this.images, this.groups, this.options);
var properties = this.body.data.nodes.get(id);
var node = this.create(properties);;
newNodes.push(node); newNodes.push(node);
this.body.nodes[id] = node; // note: this may replace an existing node this.body.nodes[id] = node; // note: this may replace an existing node
} }
@ -189,7 +181,7 @@ class NodesHandler {
else { else {
dataChanged = true; dataChanged = true;
// create node // create node
node = new Node(properties, this.images, this.groups, this.constants);
node = this.create(properties);
nodes[id] = node; nodes[id] = node;
} }
} }
@ -221,7 +213,7 @@ class NodesHandler {
create(properties) { create(properties) {
return new Node(properties, this.images, this.groups, this.options)
return new Node(properties, this.body, this.images, this.groups, this.options)
} }

+ 84
- 139
lib/network/modules/components/edges/EdgeMain.js View File

@ -1,5 +1,7 @@
var util = require('../../../../util'); var util = require('../../../../util');
import Label from '../unified/label.js'
/** /**
* @class Edge * @class Edge
* *
@ -33,7 +35,6 @@ class Edge {
this.value = undefined; this.value = undefined;
this.selected = false; this.selected = false;
this.hover = false; this.hover = false;
this.labelDimensions = {top: 0, left: 0, width: 0, height: 0, yLine: 0}; // could be cached
this.labelDirty = true; this.labelDirty = true;
this.colorDirty = true; this.colorDirty = true;
@ -51,6 +52,8 @@ class Edge {
this.connected = false; this.connected = false;
this.labelModule = new Label(this.body, this.options);
this.setOptions(options, true); this.setOptions(options, true);
this.controlNodesEnabled = false; this.controlNodesEnabled = false;
@ -101,12 +104,6 @@ class Edge {
if (options.id !== undefined) {this.id = options.id;} if (options.id !== undefined) {this.id = options.id;}
if (options.from !== undefined) {this.fromId = options.from;} if (options.from !== undefined) {this.fromId = options.from;}
if (options.to !== undefined) {this.toId = options.to;} if (options.to !== undefined) {this.toId = options.to;}
if (options.label !== undefined) {
this.label = options.label;
this.labelDirty = true;
}
if (options.title !== undefined) {this.title = options.title;} if (options.title !== undefined) {this.title = options.title;}
if (options.value !== undefined) {this.value = options.value;} if (options.value !== undefined) {this.value = options.value;}
@ -142,6 +139,8 @@ class Edge {
this.widthSelected = this.options.width * this.options.widthSelectionMultiplier; this.widthSelected = this.options.width * this.options.widthSelectionMultiplier;
this.setupSmoothEdges(doNotEmit); this.setupSmoothEdges(doNotEmit);
this.labelModule.setOptions(this.options);
} }
@ -265,11 +264,14 @@ class Edge {
* @param total * @param total
*/ */
setValueRange(min, max, total) { setValueRange(min, max, total) {
if (!this.widthFixed && this.value !== undefined) {
var scale = this.options.customScalingFunction(min, max, total, this.value);
var widthDiff = this.options.widthMax - this.options.widthMin;
this.options.width = this.options.widthMin + scale * widthDiff;
this.widthSelected = this.options.width * this.options.widthSelectionMultiplier;
if (this.value !== undefined) {
var scale = this.options.scaling.customScalingFunction(min, max, total, this.value);
var widthDiff = this.options.scaling.max - this.options.scaling.min;
if (this.options.scaling.label.enabled == true) {
var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
}
this.options.width = this.options.scaling.min + scale * widthDiff;
} }
} }
@ -304,13 +306,25 @@ class Edge {
} }
drawLabel(ctx, viaNode) { drawLabel(ctx, viaNode) {
if (this.label !== undefined) {
if (this.options.label !== undefined) {
// set style // set style
var node1 = this.from; var node1 = this.from;
var node2 = this.to; var node2 = this.to;
var selected = (this.from.selected || this.to.selected || this.selected);
if (node1.id != node2.id) { if (node1.id != node2.id) {
var point = this._pointOnEdge(0.5, viaNode); var point = this._pointOnEdge(0.5, viaNode);
this._label(ctx, this.label, point.x, point.y);
ctx.save();
// if the label has to be rotated:
if (this.options.font.align != "horizontal") {
this.labelModule.calculateLabelSize(ctx,selected,point.x,point.y);
ctx.translate(point.x, this.labelModule.size.yLine);
this._rotateForLabelAlignment(ctx);
}
// draw the label
this.labelModule.draw(ctx, point.x, point.y, selected);
ctx.restore();
} }
else { else {
var x, y; var x, y;
@ -324,7 +338,8 @@ class Edge {
y = node1.y - node1.height * 0.5; y = node1.y - node1.height * 0.5;
} }
point = this._pointOnCircle(x, y, radius, 0.125); point = this._pointOnCircle(x, y, radius, 0.125);
this._label(ctx, this.label, point.x, point.y);
this.labelModule.draw(ctx, point.x, point.y, selected);
} }
} }
} }
@ -378,7 +393,7 @@ class Edge {
grd.addColorStop(0, fromColor); grd.addColorStop(0, fromColor);
grd.addColorStop(1, toColor); grd.addColorStop(1, toColor);
// -------------------- this returns the function -------------------- //
// -------------------- this returns -------------------- //
return grd; return grd;
} }
@ -726,49 +741,7 @@ class Edge {
* @param {Number} y * @param {Number} y
* @private * @private
*/ */
_label(ctx, text, x, y) {
if (text) {
ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") +
this.options.font.size + "px " + this.options.font.face;
var yLine;
if (this.labelDirty == true) {
var lines = String(text).split('\n');
var lineCount = lines.length;
var fontSize = Number(this.options.font.size);
yLine = y + (1 - lineCount) * 0.5 * fontSize;
var width = ctx.measureText(lines[0]).width;
for (var i = 1; i < lineCount; i++) {
var lineWidth = ctx.measureText(lines[i]).width;
width = lineWidth > width ? lineWidth : width;
}
var height = this.options.font.size * lineCount;
var left = x - width * 0.5;
var top = y - height * 0.5;
// cache
this.labelDimensions = {top: top, left: left, width: width, height: height, yLine: yLine};
}
var yLine = this.labelDimensions.yLine;
ctx.save();
if (this.options.font.align != "horizontal") {
ctx.translate(x, yLine);
this._rotateForLabelAlignment(ctx);
x = 0;
yLine = 0;
}
this._drawLabelRect(ctx);
this._drawLabelText(ctx, x, yLine, lines, lineCount, fontSize);
ctx.restore();
}
}
/** /**
@ -790,83 +763,6 @@ class Edge {
} }
/**
* Draws the label rectangle
* @param {CanvasRenderingContext2D} ctx
* @private
*/
_drawLabelRect(ctx) {
if (this.options.font.background !== undefined && this.options.font.background !== "none") {
ctx.fillStyle = this.options.font.background;
var lineMargin = 2;
if (this.options.font.align == 'middle') {
ctx.fillRect(-this.labelDimensions.width * 0.5, -this.labelDimensions.height * 0.5, this.labelDimensions.width, this.labelDimensions.height);
}
else if (this.options.font.align == 'top') {
ctx.fillRect(-this.labelDimensions.width * 0.5, -(this.labelDimensions.height + lineMargin), this.labelDimensions.width, this.labelDimensions.height);
}
else if (this.options.font.align == 'bottom') {
ctx.fillRect(-this.labelDimensions.width * 0.5, lineMargin, this.labelDimensions.width, this.labelDimensions.height);
}
else {
ctx.fillRect(this.labelDimensions.left, this.labelDimensions.top, this.labelDimensions.width, this.labelDimensions.height);
}
}
}
/**
* Draws the label text
* @param {CanvasRenderingContext2D} ctx
* @param {Number} x
* @param {Number} yLine
* @param {Array} lines
* @param {Number} lineCount
* @param {Number} fontSize
* @private
*/
_drawLabelText(ctx, x, yLine, lines, lineCount, fontSize) {
// draw text
ctx.fillStyle = this.options.font.color || "black";
ctx.textAlign = "center";
// check for label alignment
if (this.options.font.align != 'horizontal') {
var lineMargin = 2;
if (this.options.font.align == 'top') {
ctx.textBaseline = "alphabetic";
yLine -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers
}
else if (this.options.font.align == 'bottom') {
ctx.textBaseline = "hanging";
yLine += 2 * lineMargin;// distance from edge, required because we use hanging. Hanging has less difference between browsers
}
else {
ctx.textBaseline = "middle";
}
}
else {
ctx.textBaseline = "middle";
}
// check for strokeWidth
if (this.options.font.stroke > 0) {
ctx.lineWidth = this.options.font.stroke;
ctx.strokeStyle = this.options.font.strokeColor;
ctx.lineJoin = 'round';
}
for (var i = 0; i < lineCount; i++) {
if (this.options.font.stroke > 0) {
ctx.strokeText(lines[i], x, yLine);
}
ctx.fillText(lines[i], x, yLine);
yLine += fontSize;
}
}
/** /**
* Redraw a edge as a dashes line * Redraw a edge as a dashes line
* Draw this edge in the given canvas * Draw this edge in the given canvas
@ -1266,10 +1162,10 @@ class Edge {
returnValue = Math.abs(Math.sqrt(dx * dx + dy * dy) - radius); returnValue = Math.abs(Math.sqrt(dx * dx + dy * dy) - radius);
} }
if (this.labelDimensions.left < x3 &&
this.labelDimensions.left + this.labelDimensions.width > x3 &&
this.labelDimensions.top < y3 &&
this.labelDimensions.top + this.labelDimensions.height > y3) {
if (this.labelModule.size.left < x3 &&
this.labelModule.size.left + this.labelModule.size.width > x3 &&
this.labelModule.size.top < y3 &&
this.labelModule.size.top + this.labelModule.size.height > y3) {
return 0; return 0;
} }
else { else {
@ -1337,6 +1233,55 @@ class Edge {
} }
//*************************************************************************************************//
//*************************************************************************************************//
//*************************************************************************************************//
//*************************************************************************************************//
//*********************** MOVE THESE FUNCTIONS TO THE MANIPULATION SYSTEM ************************//
//*************************************************************************************************//
//*************************************************************************************************//
//*************************************************************************************************//
//*************************************************************************************************//
/** /**
* This function draws the control nodes for the manipulator. * This function draws the control nodes for the manipulator.
* In order to enable this, only set the this.controlNodesEnabled to true. * In order to enable this, only set the this.controlNodesEnabled to true.

+ 684
- 763
lib/network/modules/components/nodes/NodeMain.js
File diff suppressed because it is too large
View File


+ 21
- 0
lib/network/modules/components/nodes/ellipse.js View File

@ -0,0 +1,21 @@
/**
* Created by Alex on 3/18/2015.
*/
class Ellipse {
constructor () {
}
resize(ctx) {
}
draw(ctx) {
}
distanceToBorder() {
}
}

+ 187
- 0
lib/network/modules/components/unified/label.js View File

@ -0,0 +1,187 @@
let util = require('../../../../util');
/**
* Created by Alex on 3/17/2015.
*/
class Label {
constructor(body,options) {
this.body = body;
this.setOptions(options);
this.size = {top: 0, left: 0, width: 0, height: 0, yLine: 0}; // could be cached
}
setOptions(options) {
this.options = options;
if (options.label !== undefined) {
this.labelDirty = true;
}
}
draw(ctx, x, y, selected, baseline = 'middle') {
if (this.options.label !== undefined) {
// check if we have to render the label
let relativeFontSize = Number(this.options.font.size) * this.body.view.scale;
if (this.options.label && relativeFontSize >= this.options.scaling.label.drawThreshold - 1) {
// this ensures that there will not be HUGE letters on screen by setting an upper limit on the visible text size (regardless of zoomLevel)
let fontSize = Number(this.options.font.size);
if (relativeFontSize >= this.options.scaling.label.maxVisible) {
fontSize = Number(this.options.scaling.label.maxVisible) / this.body.view.scale;
}
// notify the canvas of the fontsize and thickness
ctx.font = (selected ? "bold " : "") + fontSize + "px " + this.options.font.face;
// update the size cache if required
if (this.labelDirty == true) {
this.calculateLabelSize(ctx, selected, x, y, baseline);
}
// create some of the local variables
let yLine = this.size.yLine;
let lines = String(this.options.label).split('\n');
let lineCount = lines.length;
// create the fontfill background
this._drawLabelRect(ctx);
// draw text
this._drawLabelText(ctx, x, yLine, lines, lineCount, fontSize, baseline, relativeFontSize);
}
}
}
getTextSize(ctx, selected) {
if (this.options.label !== undefined) {
this._calculateLabelSize(ctx,selected);
}
else {
this.size = {top: 0, left: 0, width: 0, height: 0, yLine: 0};
}
return this.size;
}
_calculateLabelSize(ctx,selected,x,y,baseline) {
ctx.font = (selected ? "bold " : "") + this.options.font.size + "px " + this.options.font.face;
let lines = String(this.options.label).split('\n');
let lineCount = lines.length;
let yLine = y + (1 - lineCount) * 0.5 * this.options.font.size;
let width = ctx.measureText(lines[0]).width;
for (let i = 1; i < lineCount; i++) {
let lineWidth = ctx.measureText(lines[i]).width;
width = lineWidth > width ? lineWidth : width;
}
let height = this.options.font.size * lineCount;
let left = x - width * 0.5;
let top = y - height * 0.5;
if (baseline == "hanging") {
top += 0.5 * this.options.font.size;
top += 4; // distance from node, required because we use hanging. Hanging has less difference between browsers
yLine += 4; // distance from node
}
// cache
this.size = {top: top, left: left, width: width, height: height, yLine: yLine};
}
calculateLabelSize(ctx,selected,x=0,y=0,baseline='middle') {
if (this.labelDirty == true) {
this._calculateLabelSize(ctx, selected, x, y, baseline);
}
}
/**
* Draws the label rectangle
* @param {CanvasRenderingContext2D} ctx
* @private
*/
_drawLabelRect(ctx) {
if (this.options.font.background !== undefined && this.options.font.background !== "none") {
ctx.fillStyle = this.options.font.background;
let lineMargin = 2;
switch (this.options.font.align) {
case 'middle':
ctx.fillRect(-this.size.width * 0.5, -this.size.height * 0.5, this.size.width, this.size.height);
break;
case 'top':
ctx.fillRect(-this.size.width * 0.5, -(this.size.height + lineMargin), this.size.width, this.size.height);
break;
case 'bottom':
ctx.fillRect(-this.size.width * 0.5, lineMargin, this.size.width, this.size.height);
break
default:
ctx.fillRect(this.size.left, this.size.top, this.size.width, this.size.height);
break;
}
}
}
/**
* Draws the label text
* @param {CanvasRenderingContext2D} ctx
* @param {Number} x
* @param {Number} yLine
* @param {Array} lines
* @param {Number} lineCount
* @param {Number} fontSize
* @private
*/
_drawLabelText(ctx, x, yLine, lines, lineCount, fontSize, baseline = 'middle', relativeFontSize = this.options.font.size) {
// fade in when relative scale is between threshold and threshold - 1
let fontColor = this.options.font.color || "#000000";
let strokeColor = this.options.font.strokeColor;
if (relativeFontSize <= this.options.scaling.label.drawThreshold) {
let opacity = Math.max(0, Math.min(1, 1 - (this.options.scaling.label.drawThreshold - relativeFontSize)));
fontColor = util.overrideOpacity(fontColor, opacity);
strokeColor = util.overrideOpacity(strokeColor, opacity);
}
// draw text
ctx.fillStyle = fontColor;
ctx.textAlign = 'center';
// check for label alignment (for edges)
// TODO: make alignment for nodes
if (this.options.font.align !== 'horizontal') {
x = 0;
yLine = 0;
let lineMargin = 2;
if (this.options.font.align === 'top') {
ctx.textBaseline = 'alphabetic';
yLine -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers
}
else if (this.options.font.align === 'bottom') {
ctx.textBaseline = 'hanging';
yLine += 2 * lineMargin;// distance from edge, required because we use hanging. Hanging has less difference between browsers
}
else {
ctx.textBaseline = 'middle';
}
}
else {
ctx.textBaseline = baseline;
}
// check for strokeWidth
if (this.options.font.stroke > 0) {
ctx.lineWidth = this.options.font.stroke;
ctx.strokeStyle = strokeColor;
ctx.lineJoin = 'round';
}
for (let i = 0; i < lineCount; i++) {
if (this.options.font.stroke > 0) {
ctx.strokeText(lines[i], x, yLine);
}
ctx.fillText(lines[i], x, yLine);
yLine += fontSize;
}
}
}
export default Label;

+ 0
- 3
lib/network/modules/components/unified/labels.js View File

@ -1,3 +0,0 @@
/**
* Created by Alex on 3/17/2015.
*/

Loading…
Cancel
Save