Browse Source

simplified fixed for nodes, removed duplicate datachanged events with support nodes in edges

flowchartTest
Alex de Mulder 10 years ago
parent
commit
cf057e7ecc
16 changed files with 5743 additions and 5695 deletions
  1. +5563
    -5535
      dist/vis.js
  2. +1
    -2
      examples/network/01_basic_usage.html
  3. +2
    -34
      lib/network/Network.js
  4. +8
    -2
      lib/network/modules/Clustering.js
  5. +12
    -2
      lib/network/modules/EdgesHandler.js
  6. +11
    -11
      lib/network/modules/InteractionHandler.js
  7. +3
    -3
      lib/network/modules/LayoutEngine.js
  8. +8
    -1
      lib/network/modules/NodesHandler.js
  9. +12
    -11
      lib/network/modules/PhysicsEngine.js
  10. +24
    -13
      lib/network/modules/components/Edge.js
  11. +26
    -43
      lib/network/modules/components/Node.js
  12. +6
    -13
      lib/network/modules/components/edges/bezierEdgeDynamic.js
  13. +3
    -1
      lib/network/modules/components/edges/bezierEdgeStatic.js
  14. +3
    -3
      lib/network/modules/components/edges/straightEdge.js
  15. +44
    -20
      lib/network/modules/components/unified/label.js
  16. +17
    -1
      lib/util.js

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


+ 1
- 2
examples/network/01_basic_usage.html View File

@ -32,8 +32,7 @@
// create an array with edges
var edges = [
{from: 1, to: 3},
{from: 1, to: 1},
{from: 1, to: 2,smooth:false, arrows:{from:true, middle:true, to: true}},
{from: 1, to: 2},
{from: 2, to: 4},
{from: 2, to: 5}
];

+ 2
- 34
lib/network/Network.js View File

@ -125,7 +125,7 @@ function Network (container, data, options) {
var t0 = new Date().valueOf();
// update shortcut lists
this._updateVisibleIndices();
this.physics._updatePhysicsIndices();
this.physics.updatePhysicsIndices();
// update values
this._updateValueRange(this.body.nodes);
this._updateValueRange(this.body.edges);
@ -287,41 +287,9 @@ Network.prototype.setOptions = function (options) {
//// TODO: work out these options and document them
//if (options.edges) {
// if (options.edges.color !== undefined) {
// if (util.isString(options.edges.color)) {
// this.constants.edges.color = {};
// this.constants.edges.color.color = options.edges.color;
// this.constants.edges.color.highlight = options.edges.color;
// this.constants.edges.color.hover = options.edges.color;
// }
// else {
// if (options.edges.color.color !== undefined) {this.constants.edges.color.color = options.edges.color.color;}
// if (options.edges.color.highlight !== undefined) {this.constants.edges.color.highlight = options.edges.color.highlight;}
// if (options.edges.color.hover !== undefined) {this.constants.edges.color.hover = options.edges.color.hover;}
// }
// this.constants.edges.inheritColor = false;
// }
//
// if (!options.edges.fontColor) {
// if (options.edges.color !== undefined) {
// if (util.isString(options.edges.color)) {this.constants.edges.fontColor = options.edges.color;}
// else if (options.edges.color.color !== undefined) {this.constants.edges.fontColor = options.edges.color.color;}
// }
// }
//}
//
//if (options.nodes) {
// if (options.nodes.color) {
// var newColorObj = util.parseColor(options.nodes.color);
// this.constants.nodes.color.background = newColorObj.background;
// this.constants.nodes.color.border = newColorObj.border;
// this.constants.nodes.color.highlight.background = newColorObj.highlight.background;
// this.constants.nodes.color.highlight.border = newColorObj.highlight.border;
// this.constants.nodes.color.hover.background = newColorObj.hover.background;
// this.constants.nodes.color.hover.border = newColorObj.hover.border;
// }
//}
//
//if (options.groups) {
// for (var groupname in options.groups) {
// if (options.groups.hasOwnProperty(groupname)) {

+ 8
- 2
lib/network/modules/Clustering.js View File

@ -131,8 +131,14 @@ class ClusterEngine {
var node = this.body.nodes[nodeId];
options = this._checkOptions(options, node);
if (options.clusterNodeProperties.x === undefined) {options.clusterNodeProperties.x = node.x; options.clusterNodeProperties.allowedToMoveX = !node.xFixed;}
if (options.clusterNodeProperties.y === undefined) {options.clusterNodeProperties.y = node.y; options.clusterNodeProperties.allowedToMoveY = !node.yFixed;}
if (options.clusterNodeProperties.x === undefined) {options.clusterNodeProperties.x = node.x;}
if (options.clusterNodeProperties.y === undefined) {options.clusterNodeProperties.y = node.y;}
if (options.clusterNodeProperties.fixed === undefined) {
options.clusterNodeProperties.fixed = {};
options.clusterNodeProperties.fixed.x = node.options.fixed.x;
options.clusterNodeProperties.fixed.y = node.options.fixed.y;
}
var childNodesObj = {};
var childEdgesObj = {}

+ 12
- 2
lib/network/modules/EdgesHandler.js View File

@ -99,7 +99,17 @@ class EdgesHandler {
}
setOptions(options) {
if (options) {
if (options.color !== undefined) {
if (util.isString(options.color)) {
util.assignAllKeys(this.options.color, options.color);
}
else {
util.extend(this.options.color, options.color);
}
this.options.color.inherit.enabled = false;
}
}
}
@ -191,7 +201,7 @@ class EdgesHandler {
if (edge === null) {
// update edge
edge.disconnect();
edge.setOptions(data);
dataChanged = edge.setOptions(data) || dataChanged; // if a support node is added, data can be changed.
edge.connect();
}
else {

+ 11
- 11
lib/network/modules/InteractionHandler.js View File

@ -173,8 +173,8 @@ class InteractionHandler {
this.onTouch(event);
}
var node = this.selectionHandler.getNodeAt(this.drag.pointer);
// note: drag.pointer is set in onTouch to get the initial touch location
var node = this.selectionHandler.getNodeAt(this.drag.pointer);
this.drag.dragging = true;
this.drag.selection = [];
@ -203,12 +203,12 @@ class InteractionHandler {
// store original x, y, xFixed and yFixed, make the node temporarily Fixed
x: object.x,
y: object.y,
xFixed: object.xFixed,
yFixed: object.yFixed
xFixed: object.options.fixed.x,
yFixed: object.options.fixed.y
};
object.xFixed = true;
object.yFixed = true;
object.options.fixed.x = true;
object.options.fixed.y = true;
this.drag.selection.push(s);
}
@ -239,12 +239,12 @@ class InteractionHandler {
// update position of all selected nodes
selection.forEach((selection) => {
var node = selection.node;
if (!selection.xFixed) {
// only move the node if it was not fixed initially
if (selection.xFixed === false) {
node.x = this.canvas._XconvertDOMtoCanvas(this.canvas._XconvertCanvasToDOM(selection.x) + deltaX);
}
if (!selection.yFixed) {
// only move the node if it was not fixed initially
if (selection.yFixed === false) {
node.y = this.canvas._YconvertDOMtoCanvas(this.canvas._YconvertCanvasToDOM(selection.y) + deltaY);
}
});
@ -281,8 +281,8 @@ class InteractionHandler {
if (selection && selection.length) {
selection.forEach(function (s) {
// restore original xFixed and yFixed
s.node.xFixed = s.xFixed;
s.node.yFixed = s.yFixed;
s.node.options.fixed.x = s.xFixed;
s.node.options.fixed.y = s.yFixed;
});
this.body.emitter.emit("startSimulation");
}

+ 3
- 3
lib/network/modules/LayoutEngine.js View File

@ -14,11 +14,11 @@ class LayoutEngine {
positionInitially(nodesArray) {
for (var i = 0; i < nodesArray.length; i++) {
let node = nodesArray[i];
if ((node.xFixed == false || node.yFixed == false) && (node.x === null || node.y === null)) {
if ((!node.isFixed()) && (node.x === null || node.y === null)) {
var radius = 10 * 0.1*nodesArray.length + 10;
var angle = 2 * Math.PI * Math.random();
if (node.xFixed == false) {node.x = radius * Math.cos(angle);}
if (node.yFixed == false) {node.y = radius * Math.sin(angle);}
if (node.options.fixed.x == false) {node.x = radius * Math.cos(angle);}
if (node.options.fixed.x == false) {node.y = radius * Math.sin(angle);}
}
}
}

+ 8
- 1
lib/network/modules/NodesHandler.js View File

@ -90,12 +90,19 @@ class NodesHandler {
size: 10,
value: 1
};
util.extend(this.options, this.defaultOptions);
this.setOptions(options);
}
setOptions(options) {
if (options) {
util.selectiveNotDeepExtend(['color'], this.options, options);
if (options.color) {
this.options.color = util.parseColor(options.color);
}
}
}
/**

+ 12
- 11
lib/network/modules/PhysicsEngine.js View File

@ -20,6 +20,7 @@ class PhysicsEngine {
this.simulationInterval = 1000 / 60;
this.requiresTimeout = true;
this.previousStates = {};
this.freezeCache = {};
this.renderTimer == undefined;
this.stabilized = false;
@ -207,7 +208,7 @@ class PhysicsEngine {
*
* @private
*/
_updatePhysicsIndices() {
updatePhysicsIndices() {
this.physicsBody.forces = {};
this.physicsBody.physicsNodeIndices = [];
this.physicsBody.physicsEdgeIndices = [];
@ -307,7 +308,7 @@ class PhysicsEngine {
// store the state so we can revert
this.previousStates[nodeId] = {x:node.x, y:node.y, vx:velocities[nodeId].x, vy:velocities[nodeId].y};
if (!node.xFixed) {
if (node.options.fixed.x === false) {
let dx = this.modelOptions.damping * velocities[nodeId].x; // damping force
let ax = (forces[nodeId].x - dx) / node.options.mass; // acceleration
velocities[nodeId].x += ax * timestep; // velocity
@ -319,7 +320,7 @@ class PhysicsEngine {
velocities[nodeId].x = 0;
}
if (!node.yFixed) {
if (node.options.fixed.y === false) {
let dy = this.modelOptions.damping * velocities[nodeId].y; // damping force
let ay = (forces[nodeId].y - dy) / node.options.mass; // acceleration
velocities[nodeId].y += ay * timestep; // velocity
@ -359,11 +360,10 @@ class PhysicsEngine {
var nodes = this.body.nodes;
for (var id in nodes) {
if (nodes.hasOwnProperty(id)) {
if (nodes[id].x != null && nodes[id].y != null) {
nodes[id].fixedData.x = nodes[id].xFixed;
nodes[id].fixedData.y = nodes[id].yFixed;
nodes[id].xFixed = true;
nodes[id].yFixed = true;
if (nodes[id].x && nodes[id].y) {
this.freezeCache[id] = {x:nodes[id].options.fixed.x,y:nodes[id].options.fixed.y};
nodes[id].options.fixed.x = true;
nodes[id].options.fixed.y = true;
}
}
}
@ -378,12 +378,13 @@ class PhysicsEngine {
var nodes = this.body.nodes;
for (var id in nodes) {
if (nodes.hasOwnProperty(id)) {
if (nodes[id].fixedData.x != null) {
nodes[id].xFixed = nodes[id].fixedData.x;
nodes[id].yFixed = nodes[id].fixedData.y;
if (this.freezeCache[id] !== undefined) {
nodes[id].options.fixed.x = this.freezeCache[id].x;
nodes[id].options.fixed.y = this.freezeCache[id].y;
}
}
}
this.freezeCache = {};
}
/**

+ 24
- 13
lib/network/modules/components/Edge.js View File

@ -25,7 +25,6 @@ class Edge {
if (body === undefined) {
throw "No body provided";
}
this.options = util.bridgeObject(globalOptions);
this.body = body;
@ -49,7 +48,7 @@ class Edge {
this.labelModule = new Label(this.body, this.options);
this.setOptions(options, true);
this.setOptions(options);
this.controlNodesEnabled = false;
this.controlNodes = {from: undefined, to: undefined, positions: {}};
@ -62,7 +61,7 @@ class Edge {
* @param {Object} options an object with options
* @param doNotEmit
*/
setOptions(options, doNotEmit = false) {
setOptions(options) {
if (!options) {
return;
}
@ -138,26 +137,38 @@ class Edge {
this.updateEdgeType();
this.edgeType.setOptions(this.options);
return this.edgeType.setOptions(this.options);
}
updateEdgeType() {
let dataChanged = false;
let changeInType = true;
if (this.edgeType !== undefined) {
this.edgeType.cleanup();
if (this.edgeType instanceof BezierEdgeDynamic && this.options.smooth.enabled == true && this.options.smooth.dynamic == true) {changeInType = false;}
if (this.edgeType instanceof BezierEdgeStatic && this.options.smooth.enabled == true && this.options.smooth.dynamic == false){changeInType = false;}
if (this.edgeType instanceof StraightEdge && this.options.smooth.enabled == false) {changeInType = false;}
if (changeInType == true) {
dataChanged = this.edgeType.cleanup();
}
}
if (this.options.smooth.enabled === true) {
if (this.options.smooth.dynamic === true) {
this.edgeType = new BezierEdgeDynamic(this.options, this.body, this.labelModule);
if (changeInType === true) {
if (this.options.smooth.enabled === true) {
if (this.options.smooth.dynamic === true) {
dataChanged = true;
this.edgeType = new BezierEdgeDynamic(this.options, this.body, this.labelModule);
}
else {
this.edgeType = new BezierEdgeStatic(this.options, this.body, this.labelModule);
}
}
else {
this.edgeType = new BezierEdgeStatic(this.options, this.body, this.labelModule);
this.edgeType = new StraightEdge(this.options, this.body, this.labelModule);
}
}
else {
this.edgeType = new StraightEdge(this.options, this.body, this.labelModule);
}
return dataChanged;
}

+ 26
- 43
lib/network/modules/components/Node.js View File

@ -44,33 +44,25 @@ import TriangleDown from './nodes/shapes/triangleDown'
class Node {
constructor(options, body, imagelist, grouplist, globalOptions) {
this.options = util.bridgeObject(globalOptions);
this.body = body;
this.selected = false;
this.hover = false;
this.edges = []; // all edges connected to this node
// set defaults for the options
this.id = undefined;
this.allowedToMoveX = false;
this.allowedToMoveY = false;
this.xFixed = false;
this.yFixed = false;
this.boundingBox = {top: 0, left: 0, right: 0, bottom: 0};
this.imagelist = imagelist;
this.grouplist = grouplist;
// physics options
// state options
this.x = null;
this.y = null;
this.predefinedPosition = false; // used to check if initial zoomExtent should just take the range or approximate
this.selected = false;
this.hover = false;
this.fixedData = {x: null, y: null};
this.labelModule = new Label(this.body, this.options);
this.setOptions(options);
}
@ -117,29 +109,26 @@ class Node {
}
var fields = [
'id',
'borderWidth',
'borderWidthSelected',
'shape',
'image',
'brokenImage',
'size',
'label',
'customScalingFunction',
'icon',
'value',
'font',
'hidden',
'physics'
'icon',
'id',
'image',
'label',
'physics',
'shape',
'size',
'value'
];
util.selectiveDeepExtend(fields, this.options, options);
// basic options
if (options.id !== undefined) {
this.id = options.id;
}
if (options.title !== undefined) {
this.title = options.title;
}
if (options.x !== undefined) {
this.x = options.x;
this.predefinedPosition = true;
@ -156,10 +145,6 @@ class Node {
this.preassignedLevel = true;
}
if (options.triggerFunction !== undefined) {
this.triggerFunction = options.triggerFunction;
}
if (this.id === undefined) {
throw "Node must have an id";
}
@ -185,21 +170,19 @@ class Node {
}
}
if (options.allowedToMoveX !== undefined) {
this.xFixed = !options.allowedToMoveX;
this.allowedToMoveX = options.allowedToMoveX;
}
else if (options.x !== undefined && this.allowedToMoveX == false) {
this.xFixed = true;
}
if (options.allowedToMoveY !== undefined) {
this.yFixed = !options.allowedToMoveY;
this.allowedToMoveY = options.allowedToMoveY;
}
else if (options.y !== undefined && this.allowedToMoveY == false) {
this.yFixed = true;
if (options.fixed !== undefined) {
if (typeof options.fixed == 'boolean') {
this.options.fixed.x = true;
this.options.fixed.y = true;
}
else {
if (options.fixed.x !== undefined && typeof options.fixed.x == 'boolean') {
this.options.fixed.x = options.fixed.x;
}
if (options.fixed.y !== undefined && typeof options.fixed.y == 'boolean') {
this.options.fixed.y = options.fixed.y;
}
}
}
// choose draw method depending on the shape
@ -249,7 +232,7 @@ class Node {
break;
}
this.labelModule.setOptions(this.options);
this.labelModule.setOptions(this.options, options);
// reset the size of the node, this can be changed
this._reset();

+ 6
- 13
lib/network/modules/components/edges/bezierEdgeDynamic.js View File

@ -6,10 +6,8 @@ import BezierBaseEdge from './util/bezierBaseEdge'
class BezierEdgeDynamic extends BezierBaseEdge {
constructor(options, body, labelModule) {
this.initializing = true;
this.via = undefined;
super(options, body, labelModule);
this.initializing = false;
super(options, body, labelModule); // --> this calls the setOptions below
}
setOptions(options) {
@ -17,27 +15,27 @@ class BezierEdgeDynamic extends BezierBaseEdge {
this.from = this.body.nodes[this.options.from];
this.to = this.body.nodes[this.options.to];
this.id = this.options.id;
this.setupSupportNode(this.initializing);
this.setupSupportNode();
}
cleanup() {
if (this.via !== undefined) {
delete this.body.nodes[this.via.id];
this.via = undefined;
this.body.emitter.emit("_dataChanged");
return true;
}
return false;
}
/**
* Bezier curves require an anchor point to calculate the smooth flow. These points are nodes. These nodes are invisible but
* are used for the force calculation.
*
* The changed data is not called, if needed, it is returned by the main edge constructor.
* @private
*/
setupSupportNode(doNotEmit = false) {
var changedData = false;
setupSupportNode() {
if (this.via === undefined) {
changedData = true;
var nodeId = "edgeId:" + this.id;
var node = this.body.functions.createNode({
id: nodeId,
@ -52,11 +50,6 @@ class BezierEdgeDynamic extends BezierBaseEdge {
this.via.parentEdgeId = this.id;
this.positionBezierNode();
}
// node has been added or deleted
if (changedData === true && doNotEmit === false) {
this.body.emitter.emit("_dataChanged");
}
}
positionBezierNode() {

+ 3
- 1
lib/network/modules/components/edges/bezierEdgeStatic.js View File

@ -9,7 +9,9 @@ class BezierEdgeStatic extends BezierBaseEdge {
super(options, body, labelModule);
}
cleanup() {}
cleanup() {
return false;
}
/**
* Draw a line between two nodes
* @param {CanvasRenderingContext2D} ctx

+ 3
- 3
lib/network/modules/components/edges/straightEdge.js View File

@ -9,7 +9,9 @@ class StraightEdge extends BaseEdge {
super(options, body, labelModule);
}
cleanup() {}
cleanup() {
return false;
}
/**
* Draw a line between two nodes
* @param {CanvasRenderingContext2D} ctx
@ -47,8 +49,6 @@ class StraightEdge extends BaseEdge {
node2 = this.to;
}
let angle = Math.atan2((node1.y - node2.y), (node1.x - node2.x));
let dx = (node1.x - node2.x);
let dy = (node1.y - node2.y);

+ 44
- 20
lib/network/modules/components/unified/label.js View File

@ -7,8 +7,20 @@ let util = require('../../../../util');
class Label {
constructor(body,options) {
this.body = body;
this.setOptions(options);
this.fontOptions = {};
this.defaultOptions = {
color: '#343434',
size: 14, // px
face: 'arial',
background: 'none',
stroke: 0, // px
strokeColor: 'white',
align:'horizontal'
}
util.extend(this.fontOptions, this.defaultOptions);
this.setOptions(options);
this.size = {top: 0, left: 0, width: 0, height: 0, yLine: 0}; // could be cached
}
@ -17,6 +29,18 @@ class Label {
if (options.label !== undefined) {
this.labelDirty = true;
}
if (options.font) {
if (typeof options.font === 'string') {
let optionsArray = options.font.split(" ");
this.fontOptions.size = optionsArray[0].replace("px",'');
this.fontOptions.face = optionsArray[1];
this.fontOptions.color = optionsArray[2];
}
else if (typeof options.font == 'object') {
util.extend(this.fontOptions, options.font);
}
this.fontOptions.size = Number(this.fontOptions.size);
}
}
@ -34,7 +58,7 @@ class Label {
return;
// check if we have to render the label
let viewFontSize = Number(this.options.font.size) * this.body.view.scale;
let viewFontSize = this.fontOptions.size * this.body.view.scale;
if (this.options.label && viewFontSize < this.options.scaling.label.drawThreshold - 1)
return;
@ -53,12 +77,12 @@ class Label {
* @private
*/
_drawBackground(ctx) {
if (this.options.font.background !== undefined && this.options.font.background !== "none") {
ctx.fillStyle = this.options.font.background;
if (this.fontOptions.background !== undefined && this.fontOptions.background !== "none") {
ctx.fillStyle = this.fontOptions.background;
let lineMargin = 2;
switch (this.options.font.align) {
switch (this.fontOptions.align) {
case 'middle':
ctx.fillRect(-this.size.width * 0.5, -this.size.height * 0.5, this.size.width, this.size.height);
break;
@ -84,7 +108,7 @@ class Label {
* @private
*/
_drawText(ctx, selected, x, y, baseline = 'middle') {
let fontSize = Number(this.options.font.size);
let fontSize = this.fontOptions.size;
let viewFontSize = fontSize * this.body.view.scale;
// this ensures that there will not be HUGE letters on screen by setting an upper limit on the visible text size (regardless of zoomLevel)
if (viewFontSize >= this.options.scaling.label.maxVisible) {
@ -96,20 +120,20 @@ class Label {
[x, yLine] = this._setAlignment(ctx, x, yLine, baseline);
// configure context for drawing the text
ctx.font = (selected ? 'bold ' : '') + fontSize + "px " + this.options.font.face;
ctx.font = (selected ? 'bold ' : '') + fontSize + "px " + this.fontOptions.face;
ctx.fillStyle = fontColor;
ctx.textAlign = 'center';
// set the strokeWidth
if (this.options.font.stroke > 0) {
ctx.lineWidth = this.options.font.stroke;
if (this.fontOptions.stroke > 0) {
ctx.lineWidth = this.fontOptions.stroke;
ctx.strokeStyle = strokeColor;
ctx.lineJoin = 'round';
}
// draw the text
for (let i = 0; i < this.lineCount; i++) {
if (this.options.font.stroke > 0) {
if (this.fontOptions.stroke > 0) {
ctx.strokeText(this.lines[i], x, yLine);
}
ctx.fillText(this.lines[i], x, yLine);
@ -120,16 +144,16 @@ class Label {
_setAlignment(ctx, x, yLine, baseline) {
// check for label alignment (for edges)
// TODO: make alignment for nodes
if (this.options.font.align !== 'horizontal') {
if (this.fontOptions.align !== 'horizontal') {
x = 0;
yLine = 0;
let lineMargin = 2;
if (this.options.font.align === 'top') {
if (this.fontOptions.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') {
else if (this.fontOptions.align === 'bottom') {
ctx.textBaseline = 'hanging';
yLine += 2 * lineMargin;// distance from edge, required because we use hanging. Hanging has less difference between browsers
}
@ -153,8 +177,8 @@ class Label {
* @private
*/
_getColor(viewFontSize) {
let fontColor = this.options.font.color || '#000000';
let strokeColor = this.options.font.strokeColor || '#ffffff';
let fontColor = this.fontOptions.color || '#000000';
let strokeColor = this.fontOptions.strokeColor || '#ffffff';
if (viewFontSize <= this.options.scaling.label.drawThreshold) {
let opacity = Math.max(0, Math.min(1, 1 - (this.options.scaling.label.drawThreshold - viewFontSize)));
fontColor = util.overrideOpacity(fontColor, opacity);
@ -173,7 +197,7 @@ class Label {
getTextSize(ctx, selected = false) {
let size = {
width: this._processLabel(ctx,selected),
height: this.options.font.size * this.lineCount
height: this.fontOptions.size * this.lineCount
};
return size;
}
@ -191,12 +215,12 @@ class Label {
if (this.labelDirty === true) {
this.size.width = this._processLabel(ctx,selected);
}
this.size.height = this.options.font.size * this.lineCount;
this.size.height = this.fontOptions.size * this.lineCount;
this.size.left = x - this.size.width * 0.5;
this.size.top = y - this.size.height * 0.5;
this.size.yLine = y + (1 - this.lineCount) * 0.5 * this.options.font.size;
this.size.yLine = y + (1 - this.lineCount) * 0.5 * this.fontOptions.size;
if (baseline == "hanging") {
this.size.top += 0.5 * this.options.font.size;
this.size.top += 0.5 * this.fontOptions.size;
this.size.top += 4; // distance from node, required because we use hanging. Hanging has less difference between browsers
this.size.yLine += 4; // distance from node
}
@ -219,7 +243,7 @@ class Label {
if (this.options.label !== undefined) {
lines = String(this.options.label).split('\n');
lineCount = lines.length;
ctx.font = (selected ? 'bold ' : '') + this.options.font.size + "px " + this.options.font.face;
ctx.font = (selected ? 'bold ' : '') + this.fontOptions.size + "px " + this.fontOptions.face;
width = ctx.measureText(lines[0]).width;
for (let i = 1; i < lineCount; i++) {
let lineWidth = ctx.measureText(lines[i]).width;

+ 17
- 1
lib/util.js View File

@ -105,6 +105,22 @@ exports.randomUUID = function() {
);
};
/**
* assign all keys of an object that are not nested objects to a certain value (used for color objects).
* @param obj
* @param value
*/
exports.assignAllKeys = function (obj, value) {
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
if (typeof obj[prop] !== 'object') {
obj[prop] = value;
}
}
}
}
/**
* Extend object a with the properties of object b or a series of objects
* Only properties with defined values are copied
@ -113,7 +129,7 @@ exports.randomUUID = function() {
* @return {Object} a
*/
exports.extend = function (a, b) {
for (var i = 1, len = arguments.length; i < len; i++) {
for (var i = 1; i < arguments.length; i++) {
var other = arguments[i];
for (var prop in other) {
if (other.hasOwnProperty(prop)) {

Loading…
Cancel
Save