@ -0,0 +1,386 @@ | |||||
var util = require('../../../util'); | |||||
import Label from './unified/label' | |||||
import Box from './nodes/box' | |||||
import Circle from './nodes/circle' | |||||
import CircularImage from './nodes/circularImage' | |||||
import Database from './nodes/database' | |||||
import Dot from './nodes/dot' | |||||
import Ellipse from './nodes/ellipse' | |||||
import Icon from './nodes/icon' | |||||
import Image from './nodes/image' | |||||
import Square from './nodes/square' | |||||
import Star from './nodes/star' | |||||
import Text from './nodes/text' | |||||
import Triangle from './nodes/triangle' | |||||
import TriangleDown from './nodes/triangleDown' | |||||
/** | |||||
* @class Node | |||||
* A node. A node can be connected to other nodes via one or multiple edges. | |||||
* @param {object} options An object containing options for the node. All | |||||
* options are optional, except for the id. | |||||
* {number} id Id of the node. Required | |||||
* {string} label Text label for the node | |||||
* {number} x Horizontal position of the node | |||||
* {number} y Vertical position of the node | |||||
* {string} shape Node shape, available: | |||||
* "database", "circle", "ellipse", | |||||
* "box", "image", "text", "dot", | |||||
* "star", "triangle", "triangleDown", | |||||
* "square", "icon" | |||||
* {string} image An image url | |||||
* {string} title An title text, can be HTML | |||||
* {anytype} group A group name or number | |||||
* @param {Network.Images} imagelist A list with images. Only needed | |||||
* when the node has an image | |||||
* @param {Network.Groups} grouplist A list with groups. Needed for | |||||
* retrieving group options | |||||
* @param {Object} constants An object with default values for | |||||
* example for the color | |||||
* | |||||
*/ | |||||
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 | |||||
this.x = null; | |||||
this.y = null; | |||||
this.predefinedPosition = false; // used to check if initial zoomExtent should just take the range or approximate | |||||
this.fixedData = {x: null, y: null}; | |||||
this.labelModule = new Label(this.body, this.options); | |||||
this.setOptions(options); | |||||
} | |||||
/** | |||||
* Attach a edge to the node | |||||
* @param {Edge} edge | |||||
*/ | |||||
attachEdge(edge) { | |||||
if (this.edges.indexOf(edge) == -1) { | |||||
this.edges.push(edge); | |||||
} | |||||
} | |||||
/** | |||||
* Detach a edge from the node | |||||
* @param {Edge} edge | |||||
*/ | |||||
detachEdge(edge) { | |||||
var index = this.edges.indexOf(edge); | |||||
if (index != -1) { | |||||
this.edges.splice(index, 1); | |||||
} | |||||
} | |||||
/** | |||||
* Set or overwrite options for the node | |||||
* @param {Object} options an object with options | |||||
* @param {Object} constants and object with default, global options | |||||
*/ | |||||
setOptions(options) { | |||||
if (!options) { | |||||
return; | |||||
} | |||||
var fields = [ | |||||
'id', | |||||
'borderWidth', | |||||
'borderWidthSelected', | |||||
'shape', | |||||
'image', | |||||
'brokenImage', | |||||
'size', | |||||
'label', | |||||
'customScalingFunction', | |||||
'icon', | |||||
'value', | |||||
'hidden', | |||||
'physics' | |||||
]; | |||||
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; | |||||
} | |||||
if (options.y !== undefined) { | |||||
this.y = options.y; | |||||
this.predefinedPosition = true; | |||||
} | |||||
if (options.value !== undefined) { | |||||
this.value = options.value; | |||||
} | |||||
if (options.level !== undefined) { | |||||
this.level = options.level; | |||||
this.preassignedLevel = true; | |||||
} | |||||
if (options.triggerFunction !== undefined) { | |||||
this.triggerFunction = options.triggerFunction; | |||||
} | |||||
if (this.id === undefined) { | |||||
throw "Node must have an id"; | |||||
} | |||||
// copy group options | |||||
if (typeof options.group === 'number' || (typeof options.group === 'string' && options.group != '')) { | |||||
var groupObj = this.grouplist.get(options.group); | |||||
util.deepExtend(this.options, groupObj); | |||||
// the color object needs to be completely defined. Since groups can partially overwrite the colors, we parse it again, just in case. | |||||
this.options.color = util.parseColor(this.options.color); | |||||
} | |||||
// individual shape options | |||||
if (options.color !== undefined) { | |||||
this.options.color = util.parseColor(options.color); | |||||
} | |||||
if (this.options.image !== undefined && this.options.image != "") { | |||||
if (this.imagelist) { | |||||
this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage); | |||||
} | |||||
else { | |||||
throw "No imagelist provided"; | |||||
} | |||||
} | |||||
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; | |||||
} | |||||
// choose draw method depending on the shape | |||||
switch (this.options.shape) { | |||||
case 'database': | |||||
this.shape = new Database(this.options, this.body, this.labelModule); | |||||
break; | |||||
case 'box': | |||||
this.shape = new Box(this.options, this.body, this.labelModule); | |||||
break; | |||||
case 'circle': | |||||
this.shape = new Circle(this.options, this.body, this.labelModule); | |||||
break; | |||||
case 'ellipse': | |||||
this.shape = new Ellipse(this.options, this.body, this.labelModule); | |||||
break; | |||||
// TODO: add diamond shape | |||||
case 'image': | |||||
this.shape = new Image(this.options, this.body, this.labelModule, this.imageObj); | |||||
break; | |||||
case 'circularImage': | |||||
this.shape = new CircularImage(this.options, this.body, this.labelModule, this.imageObj); | |||||
break; | |||||
case 'text': | |||||
this.shape = new Text(this.options, this.body, this.labelModule); | |||||
break; | |||||
case 'dot': | |||||
this.shape = new Dot(this.options, this.body, this.labelModule); | |||||
break; | |||||
case 'square': | |||||
this.shape = new Square(this.options, this.body, this.labelModule); | |||||
break; | |||||
case 'triangle': | |||||
this.shape = new Triangle(this.options, this.body, this.labelModule); | |||||
break; | |||||
case 'triangleDown': | |||||
this.shape = new TriangleDown(this.options, this.body, this.labelModule); | |||||
break; | |||||
case 'star': | |||||
this.shape = new Star(this.options, this.body, this.labelModule); | |||||
break; | |||||
case 'icon': | |||||
this.shape = new Icon(this.options, this.body, this.labelModule); | |||||
break; | |||||
default: | |||||
this.shape = new Ellipse(this.options, this.body, this.labelModule); | |||||
break; | |||||
} | |||||
this.labelModule.setOptions(this.options); | |||||
// reset the size of the node, this can be changed | |||||
this._reset(); | |||||
} | |||||
/** | |||||
* select this node | |||||
*/ | |||||
select() { | |||||
this.selected = true; | |||||
this._reset(); | |||||
} | |||||
/** | |||||
* unselect this node | |||||
*/ | |||||
unselect() { | |||||
this.selected = false; | |||||
this._reset(); | |||||
} | |||||
/** | |||||
* Reset the calculated size of the node, forces it to recalculate its size | |||||
* @private | |||||
*/ | |||||
_reset() { | |||||
this.width = undefined; | |||||
this.height = undefined; | |||||
} | |||||
/** | |||||
* get the title of this node. | |||||
* @return {string} title The title of the node, or undefined when no title | |||||
* has been set. | |||||
*/ | |||||
getTitle() { | |||||
return typeof this.title === "function" ? this.title() : this.title; | |||||
} | |||||
/** | |||||
* Calculate the distance to the border of the Node | |||||
* @param {CanvasRenderingContext2D} ctx | |||||
* @param {Number} angle Angle in radians | |||||
* @returns {number} distance Distance to the border in pixels | |||||
*/ | |||||
distanceToBorder(ctx, angle) { | |||||
this.shape.distanceToBorder(ctx,angle); | |||||
} | |||||
/** | |||||
* Check if this node has a fixed x and y position | |||||
* @return {boolean} true if fixed, false if not | |||||
*/ | |||||
isFixed() { | |||||
return (this.xFixed && this.yFixed); | |||||
} | |||||
/** | |||||
* check if this node is selecte | |||||
* @return {boolean} selected True if node is selected, else false | |||||
*/ | |||||
isSelected() { | |||||
return this.selected; | |||||
} | |||||
/** | |||||
* Retrieve the value of the node. Can be undefined | |||||
* @return {Number} value | |||||
*/ | |||||
getValue() { | |||||
return this.value; | |||||
} | |||||
/** | |||||
* Adjust the value range of the node. The node will adjust it's size | |||||
* based on its value. | |||||
* @param {Number} min | |||||
* @param {Number} max | |||||
*/ | |||||
setValueRange(min, max, total) { | |||||
if (this.value !== undefined) { | |||||
var scale = this.options.scaling.customScalingFunction(min, max, total, this.value); | |||||
var sizeDiff = 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.size = this.options.scaling.min + scale * sizeDiff; | |||||
} | |||||
} | |||||
/** | |||||
* Draw this node in the given canvas | |||||
* The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); | |||||
* @param {CanvasRenderingContext2D} ctx | |||||
*/ | |||||
draw(ctx) { | |||||
this.shape.draw(ctx, this.x, this.y, this.selected, this.hover); | |||||
} | |||||
/** | |||||
* Recalculate the size of this node in the given canvas | |||||
* The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); | |||||
* @param {CanvasRenderingContext2D} ctx | |||||
*/ | |||||
resize(ctx) { | |||||
this.shape.resize(ctx); | |||||
} | |||||
/** | |||||
* Check if this object is overlapping with the provided object | |||||
* @param {Object} obj an object with parameters left, top, right, bottom | |||||
* @return {boolean} True if location is located on node | |||||
*/ | |||||
isOverlappingWith(obj) { | |||||
return ( | |||||
this.shape.left < obj.right && | |||||
this.shape.left + this.shape.width > obj.left && | |||||
this.shape.top < obj.bottom && | |||||
this.shape.top + this.shape.height > obj.top | |||||
); | |||||
} | |||||
} | |||||
export default Node; |
@ -1,881 +0,0 @@ | |||||
var util = require('../../../../util'); | |||||
import Label from '../unified/label.js' | |||||
/** | |||||
* @class Node | |||||
* A node. A node can be connected to other nodes via one or multiple edges. | |||||
* @param {object} options An object containing options for the node. All | |||||
* options are optional, except for the id. | |||||
* {number} id Id of the node. Required | |||||
* {string} label Text label for the node | |||||
* {number} x Horizontal position of the node | |||||
* {number} y Vertical position of the node | |||||
* {string} shape Node shape, available: | |||||
* "database", "circle", "ellipse", | |||||
* "box", "image", "text", "dot", | |||||
* "star", "triangle", "triangleDown", | |||||
* "square", "icon" | |||||
* {string} image An image url | |||||
* {string} title An title text, can be HTML | |||||
* {anytype} group A group name or number | |||||
* @param {Network.Images} imagelist A list with images. Only needed | |||||
* when the node has an image | |||||
* @param {Network.Groups} grouplist A list with groups. Needed for | |||||
* retrieving group options | |||||
* @param {Object} constants An object with default values for | |||||
* example for the color | |||||
* | |||||
*/ | |||||
class Node { | |||||
constructor(options, body, imagelist, grouplist, globalOptions) { | |||||
this.options = util.bridgeObject(globalOptions); | |||||
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 | |||||
this.x = null; | |||||
this.y = null; | |||||
this.predefinedPosition = false; // used to check if initial zoomExtent should just take the range or approximate | |||||
this.fixedData = {x: null, y: null}; | |||||
this.labelModule = new Label(body, this.options); | |||||
this.setOptions(options); | |||||
} | |||||
/** | |||||
* Attach a edge to the node | |||||
* @param {Edge} edge | |||||
*/ | |||||
attachEdge(edge) { | |||||
if (this.edges.indexOf(edge) == -1) { | |||||
this.edges.push(edge); | |||||
} | |||||
} | |||||
/** | |||||
* Detach a edge from the node | |||||
* @param {Edge} edge | |||||
*/ | |||||
detachEdge(edge) { | |||||
var index = this.edges.indexOf(edge); | |||||
if (index != -1) { | |||||
this.edges.splice(index, 1); | |||||
} | |||||
} | |||||
/** | |||||
* Set or overwrite options for the node | |||||
* @param {Object} options an object with options | |||||
* @param {Object} constants and object with default, global options | |||||
*/ | |||||
setOptions(options) { | |||||
if (!options) { | |||||
return; | |||||
} | |||||
var fields = [ | |||||
'borderWidth', | |||||
'borderWidthSelected', | |||||
'shape', | |||||
'image', | |||||
'brokenImage', | |||||
'size', | |||||
'label', | |||||
'customScalingFunction', | |||||
'icon', | |||||
'value', | |||||
'hidden', | |||||
'physics' | |||||
]; | |||||
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; | |||||
} | |||||
if (options.y !== undefined) { | |||||
this.y = options.y; | |||||
this.predefinedPosition = true; | |||||
} | |||||
if (options.value !== undefined) { | |||||
this.value = options.value; | |||||
} | |||||
if (options.level !== undefined) { | |||||
this.level = options.level; | |||||
this.preassignedLevel = true; | |||||
} | |||||
if (options.triggerFunction !== undefined) { | |||||
this.triggerFunction = options.triggerFunction; | |||||
} | |||||
if (this.id === undefined) { | |||||
throw "Node must have an id"; | |||||
} | |||||
// copy group options | |||||
if (typeof options.group === 'number' || (typeof options.group === 'string' && options.group != '')) { | |||||
var groupObj = this.grouplist.get(options.group); | |||||
util.deepExtend(this.options, groupObj); | |||||
// the color object needs to be completely defined. Since groups can partially overwrite the colors, we parse it again, just in case. | |||||
this.options.color = util.parseColor(this.options.color); | |||||
} | |||||
// individual shape options | |||||
if (options.color !== undefined) { | |||||
this.options.color = util.parseColor(options.color); | |||||
} | |||||
if (this.options.image !== undefined && this.options.image != "") { | |||||
if (this.imagelist) { | |||||
this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage); | |||||
} | |||||
else { | |||||
throw "No imagelist provided"; | |||||
} | |||||
} | |||||
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; | |||||
} | |||||
// choose draw method depending on the shape | |||||
switch (this.options.shape) { | |||||
case 'database': | |||||
this.draw = this._drawDatabase; | |||||
this.resize = this._resizeDatabase; | |||||
break; | |||||
case 'box': | |||||
this.draw = this._drawBox; | |||||
this.resize = this._resizeBox; | |||||
break; | |||||
case 'circle': | |||||
this.draw = this._drawCircle; | |||||
this.resize = this._resizeCircle; | |||||
break; | |||||
case 'ellipse': | |||||
this.draw = this._drawEllipse; | |||||
this.resize = this._resizeEllipse; | |||||
break; | |||||
// TODO: add diamond shape | |||||
case 'image': | |||||
this.draw = this._drawImage; | |||||
this.resize = this._resizeImage; | |||||
break; | |||||
case 'circularImage': | |||||
this.draw = this._drawCircularImage; | |||||
this.resize = this._resizeCircularImage; | |||||
break; | |||||
case 'text': | |||||
this.draw = this._drawText; | |||||
this.resize = this._resizeText; | |||||
break; | |||||
case 'dot': | |||||
this.draw = this._drawDot; | |||||
this.resize = this._resizeShape; | |||||
break; | |||||
case 'square': | |||||
this.draw = this._drawSquare; | |||||
this.resize = this._resizeShape; | |||||
break; | |||||
case 'triangle': | |||||
this.draw = this._drawTriangle; | |||||
this.resize = this._resizeShape; | |||||
break; | |||||
case 'triangleDown': | |||||
this.draw = this._drawTriangleDown; | |||||
this.resize = this._resizeShape; | |||||
break; | |||||
case 'star': | |||||
this.draw = this._drawStar; | |||||
this.resize = this._resizeShape; | |||||
break; | |||||
case 'icon': | |||||
this.draw = this._drawIcon; | |||||
this.resize = this._resizeIcon; | |||||
break; | |||||
default: | |||||
this.draw = this._drawEllipse; | |||||
this.resize = this._resizeEllipse; | |||||
break; | |||||
} | |||||
this.labelModule.setOptions(this.options); | |||||
// reset the size of the node, this can be changed | |||||
this._reset(); | |||||
} | |||||
/** | |||||
* select this node | |||||
*/ | |||||
select() { | |||||
this.selected = true; | |||||
this._reset(); | |||||
} | |||||
/** | |||||
* unselect this node | |||||
*/ | |||||
unselect() { | |||||
this.selected = false; | |||||
this._reset(); | |||||
} | |||||
/** | |||||
* Reset the calculated size of the node, forces it to recalculate its size | |||||
* @private | |||||
*/ | |||||
_reset() { | |||||
this.width = undefined; | |||||
this.height = undefined; | |||||
} | |||||
/** | |||||
* get the title of this node. | |||||
* @return {string} title The title of the node, or undefined when no title | |||||
* has been set. | |||||
*/ | |||||
getTitle() { | |||||
return typeof this.title === "function" ? this.title() : this.title; | |||||
} | |||||
/** | |||||
* Calculate the distance to the border of the Node | |||||
* @param {CanvasRenderingContext2D} ctx | |||||
* @param {Number} angle Angle in radians | |||||
* @returns {number} distance Distance to the border in pixels | |||||
*/ | |||||
distanceToBorder(ctx, angle) { | |||||
var borderWidth = 1; | |||||
if (!this.width) { | |||||
this.resize(ctx); | |||||
} | |||||
switch (this.options.shape) { | |||||
case 'circle': | |||||
case 'dot': | |||||
return this.options.size + borderWidth; | |||||
case 'ellipse': | |||||
var a = this.width / 2; | |||||
var b = this.height / 2; | |||||
var w = (Math.sin(angle) * a); | |||||
var h = (Math.cos(angle) * b); | |||||
return a * b / Math.sqrt(w * w + h * h); | |||||
// TODO: implement distanceToBorder for database | |||||
// TODO: implement distanceToBorder for triangle | |||||
// TODO: implement distanceToBorder for triangleDown | |||||
case 'box': | |||||
case 'image': | |||||
case 'text': | |||||
default: | |||||
if (this.width) { | |||||
return Math.min( | |||||
Math.abs(this.width / 2 / Math.cos(angle)), | |||||
Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth; | |||||
// TODO: reckon with border size too in case of box | |||||
} | |||||
else { | |||||
return 0; | |||||
} | |||||
} | |||||
// TODO: implement calculation of distance to border for all shapes | |||||
} | |||||
/** | |||||
* Check if this node has a fixed x and y position | |||||
* @return {boolean} true if fixed, false if not | |||||
*/ | |||||
isFixed() { | |||||
return (this.xFixed && this.yFixed); | |||||
} | |||||
/** | |||||
* check if this node is selecte | |||||
* @return {boolean} selected True if node is selected, else false | |||||
*/ | |||||
isSelected() { | |||||
return this.selected; | |||||
} | |||||
/** | |||||
* Retrieve the value of the node. Can be undefined | |||||
* @return {Number} value | |||||
*/ | |||||
getValue() { | |||||
return this.value; | |||||
} | |||||
/** | |||||
* Adjust the value range of the node. The node will adjust it's size | |||||
* based on its value. | |||||
* @param {Number} min | |||||
* @param {Number} max | |||||
*/ | |||||
setValueRange(min, max, total) { | |||||
if (this.value !== undefined) { | |||||
var scale = this.options.scaling.customScalingFunction(min, max, total, this.value); | |||||
var sizeDiff = 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.size = this.options.scaling.min + scale * sizeDiff; | |||||
} | |||||
} | |||||
/** | |||||
* Draw this node in the given canvas | |||||
* The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); | |||||
* @param {CanvasRenderingContext2D} ctx | |||||
*/ | |||||
draw(ctx) { | |||||
throw "Draw method not initialized for node"; | |||||
} | |||||
/** | |||||
* Recalculate the size of this node in the given canvas | |||||
* The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); | |||||
* @param {CanvasRenderingContext2D} ctx | |||||
*/ | |||||
resize(ctx) { | |||||
throw "Resize method not initialized for node"; | |||||
} | |||||
/** | |||||
* Check if this object is overlapping with the provided object | |||||
* @param {Object} obj an object with parameters left, top, right, bottom | |||||
* @return {boolean} True if location is located on node | |||||
*/ | |||||
isOverlappingWith(obj) { | |||||
return (this.left < obj.right && | |||||
this.left + this.width > obj.left && | |||||
this.top < obj.bottom && | |||||
this.top + this.height > obj.top); | |||||
} | |||||
_resizeImage(ctx) { | |||||
// TODO: pre calculate the image size | |||||
if (!this.width || !this.height) { // undefined or 0 | |||||
var width, height; | |||||
if (this.value) { | |||||
var scale = this.imageObj.height / this.imageObj.width; | |||||
if (scale !== undefined) { | |||||
width = this.options.size || this.imageObj.width; | |||||
height = this.options.size * scale || this.imageObj.height; | |||||
} | |||||
else { | |||||
width = 0; | |||||
height = 0; | |||||
} | |||||
} | |||||
else { | |||||
width = this.imageObj.width; | |||||
height = this.imageObj.height; | |||||
} | |||||
this.width = width; | |||||
this.height = height; | |||||
} | |||||
} | |||||
_drawImageAtPosition(ctx) { | |||||
if (this.imageObj.width != 0) { | |||||
// draw the image | |||||
ctx.globalAlpha = 1.0; | |||||
ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height); | |||||
} | |||||
} | |||||
_drawImageLabel(ctx) { | |||||
var yLabel; | |||||
var offset = 0; | |||||
if (this.height) { | |||||
offset = this.height / 2; | |||||
var labelDimensions = this.labelModule.labelDimensions; | |||||
if (labelDimensions.lineCount >= 1) { | |||||
offset += labelDimensions.height / 2; | |||||
offset += 3; | |||||
} | |||||
} | |||||
yLabel = this.y + offset; | |||||
this.labelModule.draw(ctx, this.x, yLabel); | |||||
} | |||||
_drawImage(ctx) { | |||||
this._resizeImage(ctx); | |||||
this.left = this.x - this.width / 2; | |||||
this.top = this.y - this.height / 2; | |||||
this._drawImageAtPosition(ctx); | |||||
this.boundingBox.top = this.top; | |||||
this.boundingBox.left = this.left; | |||||
this.boundingBox.right = this.left + this.width; | |||||
this.boundingBox.bottom = this.top + this.height; | |||||
this._drawImageLabel(ctx); | |||||
this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left); | |||||
this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width); | |||||
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height); | |||||
} | |||||
_resizeCircularImage(ctx) { | |||||
if (!this.imageObj.src || !this.imageObj.width || !this.imageObj.height) { | |||||
if (!this.width) { | |||||
var diameter = this.options.size * 2; | |||||
this.width = diameter; | |||||
this.height = diameter; | |||||
this._swapToImageResizeWhenImageLoaded = true; | |||||
} | |||||
} | |||||
else { | |||||
if (this._swapToImageResizeWhenImageLoaded) { | |||||
this.width = 0; | |||||
this.height = 0; | |||||
delete this._swapToImageResizeWhenImageLoaded; | |||||
} | |||||
this._resizeImage(ctx); | |||||
} | |||||
} | |||||
_drawCircularImage(ctx) { | |||||
this._resizeCircularImage(ctx); | |||||
this.left = this.x - this.width / 2; | |||||
this.top = this.y - this.height / 2; | |||||
var centerX = this.left + (this.width / 2); | |||||
var centerY = this.top + (this.height / 2); | |||||
var size = Math.abs(this.height / 2); | |||||
this._drawRawCircle(ctx, size); | |||||
ctx.save(); | |||||
ctx.circle(this.x, this.y, size); | |||||
ctx.stroke(); | |||||
ctx.clip(); | |||||
this._drawImageAtPosition(ctx); | |||||
ctx.restore(); | |||||
this.boundingBox.top = this.y - this.options.size; | |||||
this.boundingBox.left = this.x - this.options.size; | |||||
this.boundingBox.right = this.x + this.options.size; | |||||
this.boundingBox.bottom = this.y + this.options.size; | |||||
this._drawImageLabel(ctx); | |||||
this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left); | |||||
this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width); | |||||
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height); | |||||
} | |||||
_resizeBox(ctx) { | |||||
if (!this.width) { | |||||
var margin = 5; | |||||
var textSize = this.labelModule.getTextSize(ctx,this.selected); | |||||
this.width = textSize.width + 2 * margin; | |||||
this.height = textSize.height + 2 * margin; | |||||
} | |||||
} | |||||
_drawBox(ctx) { | |||||
this._resizeBox(ctx); | |||||
this.left = this.x - this.width / 2; | |||||
this.top = this.y - this.height / 2; | |||||
var borderWidth = this.options.borderWidth; | |||||
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; | |||||
ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; | |||||
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth); | |||||
ctx.lineWidth *= this.networkScaleInv; | |||||
ctx.lineWidth = Math.min(this.width, ctx.lineWidth); | |||||
ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; | |||||
ctx.roundRect(this.left, this.top, this.width, this.height, this.options.size); | |||||
ctx.fill(); | |||||
ctx.stroke(); | |||||
this.boundingBox.top = this.top; | |||||
this.boundingBox.left = this.left; | |||||
this.boundingBox.right = this.left + this.width; | |||||
this.boundingBox.bottom = this.top + this.height; | |||||
this.labelModule.draw(ctx, this.x, this.y); | |||||
} | |||||
_resizeDatabase(ctx) { | |||||
if (!this.width) { | |||||
var margin = 5; | |||||
var textSize = this.labelModule.getTextSize(ctx,this.selected); | |||||
var size = textSize.width + 2 * margin; | |||||
this.width = size; | |||||
this.height = size; | |||||
} | |||||
} | |||||
_drawDatabase(ctx) { | |||||
this._resizeDatabase(ctx); | |||||
this.left = this.x - this.width / 2; | |||||
this.top = this.y - this.height / 2; | |||||
var borderWidth = this.options.borderWidth; | |||||
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; | |||||
ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; | |||||
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth); | |||||
ctx.lineWidth *= this.networkScaleInv; | |||||
ctx.lineWidth = Math.min(this.width, ctx.lineWidth); | |||||
ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; | |||||
ctx.database(this.x - this.width / 2, this.y - this.height * 0.5, this.width, this.height); | |||||
ctx.fill(); | |||||
ctx.stroke(); | |||||
this.boundingBox.top = this.top; | |||||
this.boundingBox.left = this.left; | |||||
this.boundingBox.right = this.left + this.width; | |||||
this.boundingBox.bottom = this.top + this.height; | |||||
this.labelModule.draw(ctx, this.x, this.y); | |||||
} | |||||
_resizeCircle(ctx) { | |||||
if (!this.width) { | |||||
var margin = 5; | |||||
var textSize = this.labelModule.getTextSize(ctx,this.selected); | |||||
var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; | |||||
this.options.size = diameter / 2; | |||||
this.width = diameter; | |||||
this.height = diameter; | |||||
} | |||||
} | |||||
_drawRawCircle(ctx, size) { | |||||
var borderWidth = this.options.borderWidth; | |||||
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; | |||||
ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; | |||||
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth); | |||||
ctx.lineWidth *= this.networkScaleInv; | |||||
ctx.lineWidth = Math.min(this.width, ctx.lineWidth); | |||||
ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; | |||||
ctx.circle(this.x, this.y, size); | |||||
ctx.fill(); | |||||
ctx.stroke(); | |||||
} | |||||
_drawCircle(ctx) { | |||||
this._resizeCircle(ctx); | |||||
this.left = this.x - this.width / 2; | |||||
this.top = this.y - this.height / 2; | |||||
this._drawRawCircle(ctx, this.options.size); | |||||
this.boundingBox.top = this.y - this.options.size; | |||||
this.boundingBox.left = this.x - this.options.size; | |||||
this.boundingBox.right = this.x + this.options.size; | |||||
this.boundingBox.bottom = this.y + this.options.size; | |||||
this.labelModule.draw(ctx, this.x, this.y); | |||||
} | |||||
_resizeEllipse(ctx) { | |||||
if (this.width === undefined) { | |||||
var textSize = this.labelModule.getTextSize(ctx,this.selected); | |||||
this.width = textSize.width * 1.5; | |||||
this.height = textSize.height * 2; | |||||
if (this.width < this.height) { | |||||
this.width = this.height; | |||||
} | |||||
} | |||||
} | |||||
_drawEllipse(ctx) { | |||||
this._resizeEllipse(ctx); | |||||
this.left = this.x - this.width / 2; | |||||
this.top = this.y - this.height / 2; | |||||
var borderWidth = this.options.borderWidth; | |||||
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; | |||||
ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; | |||||
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth); | |||||
ctx.lineWidth *= this.networkScaleInv; | |||||
ctx.lineWidth = Math.min(this.width, ctx.lineWidth); | |||||
ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; | |||||
ctx.ellipse(this.left, this.top, this.width, this.height); | |||||
ctx.fill(); | |||||
ctx.stroke(); | |||||
this.boundingBox.top = this.top; | |||||
this.boundingBox.left = this.left; | |||||
this.boundingBox.right = this.left + this.width; | |||||
this.boundingBox.bottom = this.top + this.height; | |||||
this.labelModule.draw(ctx, this.x, this.y, this.selected); | |||||
} | |||||
_drawDot(ctx) { | |||||
this._drawShape(ctx, 'circle'); | |||||
} | |||||
_drawTriangle(ctx) { | |||||
this._drawShape(ctx, 'triangle'); | |||||
} | |||||
_drawTriangleDown(ctx) { | |||||
this._drawShape(ctx, 'triangleDown'); | |||||
} | |||||
_drawSquare(ctx) { | |||||
this._drawShape(ctx, 'square'); | |||||
} | |||||
_drawStar(ctx) { | |||||
this._drawShape(ctx, 'star'); | |||||
} | |||||
_resizeShape(ctx) { | |||||
if (!this.width) { | |||||
var size = 2 * this.options.size; | |||||
this.width = size; | |||||
this.height = size; | |||||
} | |||||
} | |||||
_drawShape(ctx, shape) { | |||||
this._resizeShape(ctx); | |||||
this.left = this.x - this.width / 2; | |||||
this.top = this.y - this.height / 2; | |||||
var borderWidth = this.options.borderWidth; | |||||
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; | |||||
var sizeMultiplier = 2; | |||||
// choose draw method depending on the shape | |||||
switch (shape) { | |||||
case 'dot': | |||||
sizeMultiplier = 2; | |||||
break; | |||||
case 'square': | |||||
sizeMultiplier = 2; | |||||
break; | |||||
case 'triangle': | |||||
sizeMultiplier = 3; | |||||
break; | |||||
case 'triangleDown': | |||||
sizeMultiplier = 3; | |||||
break; | |||||
case 'star': | |||||
sizeMultiplier = 4; | |||||
break; | |||||
} | |||||
ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; | |||||
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth); | |||||
ctx.lineWidth *= this.networkScaleInv; | |||||
ctx.lineWidth = Math.min(this.width, ctx.lineWidth); | |||||
ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; | |||||
ctx[shape](this.x, this.y, this.options.size); | |||||
ctx.fill(); | |||||
ctx.stroke(); | |||||
this.boundingBox.top = this.y - this.options.size; | |||||
this.boundingBox.left = this.x - this.options.size; | |||||
this.boundingBox.right = this.x + this.options.size; | |||||
this.boundingBox.bottom = this.y + this.options.size; | |||||
if (this.options.label!== undefined) { | |||||
this.labelModule.draw(ctx, this.x, this.y + (this.height + this.labelModule.size.height)*0.5, this.selected, 'hanging'); | |||||
this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left); | |||||
this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width); | |||||
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height); | |||||
} | |||||
} | |||||
_resizeText(ctx) { | |||||
if (!this.width) { | |||||
var margin = 5; | |||||
var textSize = this.labelModule.getTextSize(ctx,this.selected); | |||||
this.width = textSize.width + 2 * margin; | |||||
this.height = textSize.height + 2 * margin; | |||||
} | |||||
} | |||||
_drawText(ctx) { | |||||
this._resizeText(ctx); | |||||
this.left = this.x - this.width / 2; | |||||
this.top = this.y - this.height / 2; | |||||
this.labelModule.draw(ctx, this.x, this.y); | |||||
this.boundingBox.top = this.top; | |||||
this.boundingBox.left = this.left; | |||||
this.boundingBox.right = this.left + this.width; | |||||
this.boundingBox.bottom = this.top + this.height; | |||||
} | |||||
_resizeIcon(ctx) { | |||||
if (!this.width) { | |||||
var margin = 5; | |||||
var iconSize = | |||||
{ | |||||
width: Number(this.options.icon.iconSize), | |||||
height: Number(this.options.icon.iconSize) | |||||
}; | |||||
this.width = iconSize.width + 2 * margin; | |||||
this.height = iconSize.height + 2 * margin; | |||||
} | |||||
} | |||||
_drawIcon(ctx) { | |||||
this._resizeIcon(ctx); | |||||
this.options.icon.iconSize = this.options.icon.iconSize || 50; | |||||
this.left = this.x - this.width / 2; | |||||
this.top = this.y - this.height / 2; | |||||
this._icon(ctx); | |||||
this.boundingBox.top = this.y - this.options.icon.iconSize / 2; | |||||
this.boundingBox.left = this.x - this.options.icon.iconSize / 2; | |||||
this.boundingBox.right = this.x + this.options.icon.iconSize / 2; | |||||
this.boundingBox.bottom = this.y + this.options.icon.iconSize / 2; | |||||
if (this.options.label!== unde) { | |||||
var iconTextSpacing = 5; | |||||
this.labelModule.draw(ctx, this.x, this.y + this.height / 2 + iconTextSpacing); | |||||
this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left); | |||||
this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width); | |||||
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height); | |||||
} | |||||
} | |||||
_icon(ctx) { | |||||
var relativeIconSize = Number(this.options.icon.iconSize) * this.networkScale; | |||||
if (this.options.icon.code && relativeIconSize > this.options.scaling.label.drawThreshold - 1) { | |||||
var iconSize = Number(this.options.icon.iconSize); | |||||
ctx.font = (this.selected ? "bold " : "") + iconSize + "px " + this.options.icon.iconFontFace; | |||||
// draw icon | |||||
ctx.fillStyle = this.options.icon.iconColor || "black"; | |||||
ctx.textAlign = "center"; | |||||
ctx.textBaseline = "middle"; | |||||
ctx.fillText(this.options.icon.code, this.x, this.y); | |||||
} | |||||
} | |||||
} | |||||
export default Node; |
@ -0,0 +1,68 @@ | |||||
/** | |||||
* Created by Alex on 3/18/2015. | |||||
*/ | |||||
'use strict'; | |||||
class Box { | |||||
constructor (options, body, labelModule) { | |||||
this.body = body; | |||||
this.labelModule = labelModule; | |||||
this.setOptions(options); | |||||
this.top = undefined; | |||||
this.left = undefined; | |||||
this.height = undefined; | |||||
this.height = undefined; | |||||
this.boundingBox = {top: 0, left: 0, right: 0, bottom: 0}; | |||||
} | |||||
setOptions(options) { | |||||
this.options = options; | |||||
} | |||||
resize(ctx) { | |||||
if (this.width === undefined) { | |||||
var margin = 5; | |||||
var textSize = this.labelModule.getTextSize(ctx,this.selected); | |||||
this.width = textSize.width + 2 * margin; | |||||
this.height = textSize.height + 2 * margin; | |||||
} | |||||
} | |||||
draw(ctx, x, y, selected, hover) { | |||||
this.resize(ctx); | |||||
this.left = x - this.width / 2; | |||||
this.top = y - this.height / 2; | |||||
var borderWidth = this.options.borderWidth; | |||||
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; | |||||
console.log(this) | |||||
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border; | |||||
ctx.lineWidth = (selected ? selectionLineWidth : borderWidth); | |||||
ctx.lineWidth /= this.body.view.scale; | |||||
ctx.lineWidth = Math.min(this.width, ctx.lineWidth); | |||||
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background; | |||||
ctx.roundRect(this.left, this.top, this.width, this.height, this.options.size); | |||||
ctx.fill(); | |||||
ctx.stroke(); | |||||
this.boundingBox.top = this.top; | |||||
this.boundingBox.left = this.left; | |||||
this.boundingBox.right = this.left + this.width; | |||||
this.boundingBox.bottom = this.top + this.height; | |||||
this.labelModule.draw(ctx, x, y, selected); | |||||
} | |||||
distanceToBorder(ctx, angle) { | |||||
this.resize(ctx); | |||||
var a = this.width / 2; | |||||
var b = this.height / 2; | |||||
var w = (Math.sin(angle) * a); | |||||
var h = (Math.cos(angle) * b); | |||||
return a * b / Math.sqrt(w * w + h * h); | |||||
} | |||||
} | |||||
export default Box; |
@ -0,0 +1,60 @@ | |||||
/** | |||||
* Created by Alex on 3/18/2015. | |||||
*/ | |||||
'use strict'; | |||||
import NodeUtil from './nodeUtil' | |||||
class Circle extends NodeUtil { | |||||
constructor (options, labelModule) { | |||||
this.labelModule = labelModule; | |||||
this.setOptions(options); | |||||
this.top = undefined; | |||||
this.left = undefined; | |||||
this.height = undefined; | |||||
this.height = undefined; | |||||
this.boundingBox = {top: 0, left: 0, right: 0, bottom: 0}; | |||||
} | |||||
setOptions(options) { | |||||
this.options = options; | |||||
} | |||||
resize(ctx) { | |||||
if (this.width === undefined) { | |||||
var margin = 5; | |||||
var textSize = this.labelModule.getTextSize(ctx,this.selected); | |||||
var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; | |||||
this.options.size = diameter / 2; | |||||
this.width = diameter; | |||||
this.height = diameter; | |||||
} | |||||
} | |||||
draw(ctx, x, y, selected, hover) { | |||||
this.resize(ctx); | |||||
this.left = x - this.width / 2; | |||||
this.top = y - this.height / 2; | |||||
this._drawRawCircle(ctx, x, y, selected, hover, this.options.size); | |||||
this.boundingBox.top = y - this.options.size; | |||||
this.boundingBox.left = x - this.options.size; | |||||
this.boundingBox.right = x + this.options.size; | |||||
this.boundingBox.bottom = y + this.options.size; | |||||
this.labelModule.draw(ctx, x, y, selected); | |||||
} | |||||
distanceToBorder(ctx, angle) { | |||||
this.resize(ctx); | |||||
var a = this.width / 2; | |||||
var b = this.height / 2; | |||||
var w = (Math.sin(angle) * a); | |||||
var h = (Math.cos(angle) * b); | |||||
return a * b / Math.sqrt(w * w + h * h); | |||||
} | |||||
} | |||||
export default Circle; |
@ -0,0 +1,78 @@ | |||||
/** | |||||
* Created by Alex on 3/18/2015. | |||||
*/ | |||||
'use strict'; | |||||
import NodeUtil from './nodeUtil' | |||||
class CircularImage extends NodeUtil { | |||||
constructor (options, body, labelModule, imageObj) { | |||||
super(options, body, labelModule); | |||||
this.imageObj = imageObj; | |||||
} | |||||
setOptions(options) { | |||||
this.options = options; | |||||
} | |||||
resize(ctx) { | |||||
if (this.imageObj.src !== undefined || this.imageObj.width !== undefined || this.imageObj.height !== undefined ) { | |||||
if (!this.width) { | |||||
var diameter = this.options.size * 2; | |||||
this.width = diameter; | |||||
this.height = diameter; | |||||
this._swapToImageResizeWhenImageLoaded = true; | |||||
} | |||||
} | |||||
else { | |||||
if (this._swapToImageResizeWhenImageLoaded) { | |||||
this.width = 0; | |||||
this.height = 0; | |||||
delete this._swapToImageResizeWhenImageLoaded; | |||||
} | |||||
this._resizeImage(ctx); | |||||
} | |||||
} | |||||
draw(ctx, x, y, selected, hover) { | |||||
this.resize(ctx); | |||||
this.left = x - this.width / 2; | |||||
this.top = y - this.height / 2; | |||||
var centerX = this.left + (this.width / 2); | |||||
var centerY = this.top + (this.height / 2); | |||||
var size = Math.abs(this.height / 2); | |||||
this._drawRawCircle(ctx, x, y, selected, hover, size); | |||||
ctx.save(); | |||||
ctx.circle(x, y, size); | |||||
ctx.stroke(); | |||||
ctx.clip(); | |||||
this._drawImageAtPosition(ctx); | |||||
ctx.restore(); | |||||
this.boundingBox.top = y - this.options.size; | |||||
this.boundingBox.left = x - this.options.size; | |||||
this.boundingBox.right = x + this.options.size; | |||||
this.boundingBox.bottom = y + this.options.size; | |||||
this._drawImageLabel(ctx); | |||||
this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left); | |||||
this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width); | |||||
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height); | |||||
} | |||||
distanceToBorder(ctx, angle) { | |||||
this.resize(ctx); | |||||
return this._distanceToBorder(angle); | |||||
} | |||||
} | |||||
export default CircularImage; |
@ -0,0 +1,68 @@ | |||||
/** | |||||
* Created by Alex on 3/18/2015. | |||||
*/ | |||||
'use strict'; | |||||
class Database { | |||||
constructor (options, body, labelModule) { | |||||
this.body = body; | |||||
this.labelModule = labelModule; | |||||
this.setOptions(options); | |||||
this.top = undefined; | |||||
this.left = undefined; | |||||
this.height = undefined; | |||||
this.height = undefined; | |||||
this.boundingBox = {top: 0, left: 0, right: 0, bottom: 0}; | |||||
} | |||||
setOptions(options) { | |||||
this.options = options; | |||||
} | |||||
resize(ctx, selected) { | |||||
if (this.width === undefined) { | |||||
var margin = 5; | |||||
var textSize = this.labelModule.getTextSize(ctx, selected); | |||||
var size = textSize.width + 2 * margin; | |||||
this.width = size; | |||||
this.height = size; | |||||
} | |||||
} | |||||
draw(ctx, x, y, selected, hover) { | |||||
this.resize(ctx, selected); | |||||
this.left = x - this.width / 2; | |||||
this.top = y - this.height / 2; | |||||
var borderWidth = this.options.borderWidth; | |||||
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; | |||||
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border; | |||||
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth); | |||||
ctx.lineWidth *= this.networkScaleInv; | |||||
ctx.lineWidth = Math.min(this.width, ctx.lineWidth); | |||||
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background; | |||||
ctx.database(x - this.width / 2, y - this.height * 0.5, this.width, this.height); | |||||
ctx.fill(); | |||||
ctx.stroke(); | |||||
this.boundingBox.top = this.top; | |||||
this.boundingBox.left = this.left; | |||||
this.boundingBox.right = this.left + this.width; | |||||
this.boundingBox.bottom = this.top + this.height; | |||||
this.labelModule.draw(ctx, x, y, selected); | |||||
} | |||||
distanceToBorder(ctx, angle) { | |||||
this.resize(ctx); | |||||
var a = this.width / 2; | |||||
var b = this.height / 2; | |||||
var w = (Math.sin(angle) * a); | |||||
var h = (Math.cos(angle) * b); | |||||
return a * b / Math.sqrt(w * w + h * h); | |||||
} | |||||
} | |||||
export default Database; |
@ -0,0 +1,30 @@ | |||||
/** | |||||
* Created by Alex on 3/18/2015. | |||||
*/ | |||||
'use strict'; | |||||
import NodeUtil from './nodeUtil' | |||||
class Dot extends NodeUtil { | |||||
constructor (options, body, labelModule) { | |||||
super(options, body, labelModule) | |||||
} | |||||
setOptions(options) { | |||||
this.options = options; | |||||
} | |||||
resize(ctx) { | |||||
this._resizeShape(); | |||||
} | |||||
draw(ctx, x, y, selected, hover) { | |||||
this._drawShape(ctx, 'circle', 2, x, y, selected, hover); | |||||
} | |||||
distanceToBorder(ctx, angle) { | |||||
return this.options.size + this.options.borderWidth; | |||||
} | |||||
} | |||||
export default Dot; |
@ -1,21 +1,72 @@ | |||||
/** | /** | ||||
* Created by Alex on 3/18/2015. | * Created by Alex on 3/18/2015. | ||||
*/ | */ | ||||
'use strict'; | |||||
class Ellipse { | class Ellipse { | ||||
constructor () { | |||||
constructor(options, body, labelModule) { | |||||
this.body = body; | |||||
this.labelModule = labelModule; | |||||
this.setOptions(options); | |||||
this.top = undefined; | |||||
this.left = undefined; | |||||
this.height = undefined; | |||||
this.height = undefined; | |||||
this.boundingBox = {top: 0, left: 0, right: 0, bottom: 0}; | |||||
} | |||||
setOptions(options) { | |||||
this.options = options; | |||||
} | } | ||||
resize(ctx) { | |||||
resize(ctx, selected) { | |||||
if (this.width === undefined) { | |||||
var textSize = this.labelModule.getTextSize(ctx, selected); | |||||
this.width = textSize.width * 1.5; | |||||
this.height = textSize.height * 2; | |||||
if (this.width < this.height) { | |||||
this.width = this.height; | |||||
} | |||||
} | |||||
} | } | ||||
draw(ctx) { | |||||
draw(ctx, x, y, selected, hover) { | |||||
this.resize(ctx, selected); | |||||
this.left = x - this.width / 2; | |||||
this.top = y - this.height / 2; | |||||
} | |||||
var borderWidth = this.options.borderWidth; | |||||
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; | |||||
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border; | |||||
ctx.lineWidth = (selected ? selectionLineWidth : borderWidth); | |||||
ctx.lineWidth /= this.body.view.scale; | |||||
ctx.lineWidth = Math.min(this.width, ctx.lineWidth); | |||||
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background; | |||||
ctx.ellipse(this.left, this.top, this.width, this.height); | |||||
ctx.fill(); | |||||
ctx.stroke(); | |||||
distanceToBorder() { | |||||
this.boundingBox.left = this.left; | |||||
this.boundingBox.top = this.top; | |||||
this.boundingBox.bottom = this.top + this.height; | |||||
this.boundingBox.right = this.left + this.width; | |||||
this.labelModule.draw(ctx, x, y, selected); | |||||
} | |||||
distanceToBorder(ctx, angle) { | |||||
this.resize(ctx); | |||||
var a = this.width / 2; | |||||
var b = this.height / 2; | |||||
var w = (Math.sin(angle) * a); | |||||
var h = (Math.cos(angle) * b); | |||||
return a * b / Math.sqrt(w * w + h * h); | |||||
} | } | ||||
} | |||||
} | |||||
export default Ellipse; |
@ -0,0 +1,26 @@ | |||||
/** | |||||
* Created by Alex on 3/18/2015. | |||||
*/ | |||||
'use strict'; | |||||
class Empty { | |||||
constructor (options, labelModule) { | |||||
this.labelModule = labelModule; | |||||
this.setOptions(options); | |||||
this.top = undefined; | |||||
this.left = undefined; | |||||
this.height = undefined; | |||||
this.height = undefined; | |||||
this.boundingBox = {top: 0, left: 0, right: 0, bottom: 0}; | |||||
} | |||||
setOptions() {} | |||||
resize() {} | |||||
draw() {} | |||||
distanceToBorder() {} | |||||
} | |||||
export default Empty; |
@ -0,0 +1,73 @@ | |||||
/** | |||||
* Created by Alex on 3/18/2015. | |||||
*/ | |||||
'use strict'; | |||||
import NodeUtil from './nodeUtil' | |||||
class Icon extends NodeUtil { | |||||
constructor(options, body, labelModule) { | |||||
super(options, body, labelModule); | |||||
} | |||||
setOptions(options) { | |||||
this.options = options; | |||||
} | |||||
resize(ctx) { | |||||
if (this.width === undefined) { | |||||
var margin = 5; | |||||
var iconSize = { | |||||
width: Number(this.options.icon.iconSize), | |||||
height: Number(this.options.icon.iconSize) | |||||
}; | |||||
this.width = iconSize.width + 2 * margin; | |||||
this.height = iconSize.height + 2 * margin; | |||||
} | |||||
} | |||||
draw(ctx, x, y, selected, hover) { | |||||
this.resize(ctx); | |||||
this.options.icon.iconSize = this.options.icon.iconSize || 50; | |||||
this.left = x - this.width * 0.5; | |||||
this.top = y - this.height * 0.5; | |||||
this._icon(ctx, x, y, selected); | |||||
this.boundingBox.top = y - this.options.icon.iconSize * 0.5; | |||||
this.boundingBox.left = x - this.options.icon.iconSize * 0.5; | |||||
this.boundingBox.right = x + this.options.icon.iconSize * 0.5; | |||||
this.boundingBox.bottom = y + this.options.icon.iconSize * 0.5; | |||||
if (this.options.label !== undefined) { | |||||
var iconTextSpacing = 5; | |||||
this.labelModule.draw(ctx, x, y + this.height * 0.5 + iconTextSpacing, selected); | |||||
this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left); | |||||
this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width); | |||||
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height); | |||||
} | |||||
} | |||||
_icon(ctx, x, y, selected) { | |||||
let iconSize = Number(this.options.icon.iconSize); | |||||
let relativeIconSize = iconSize * this.body.view.scale; | |||||
if (this.options.icon.code && relativeIconSize > this.options.scaling.label.drawThreshold - 1) { | |||||
ctx.font = (selected ? "bold " : "") + iconSize + "px " + this.options.icon.iconFontFace; | |||||
// draw icon | |||||
ctx.fillStyle = this.options.icon.iconColor || "black"; | |||||
ctx.textAlign = "center"; | |||||
ctx.textBaseline = "middle"; | |||||
ctx.fillText(this.options.icon.code, x, y); | |||||
} | |||||
} | |||||
distanceToBorder(ctx, angle) { | |||||
this.resize(ctx); | |||||
this._distanceToBorder(angle); | |||||
} | |||||
} | |||||
export default Icon; |
@ -0,0 +1,70 @@ | |||||
/** | |||||
* Created by Alex on 3/18/2015. | |||||
*/ | |||||
'use strict'; | |||||
import NodeUtil from './nodeUtil' | |||||
class Image extends NodeUtil { | |||||
constructor (options, body, labelModule, imageObj) { | |||||
super(options, body, labelModule); | |||||
this.imageObj = imageObj; | |||||
} | |||||
setOptions(options) { | |||||
this.options = options; | |||||
} | |||||
resize() { | |||||
if (!this.width || !this.height) { // undefined or 0 | |||||
var width, height; | |||||
if (this.value) { | |||||
var scale = this.imageObj.height / this.imageObj.width; | |||||
if (scale !== undefined) { | |||||
width = this.options.size || this.imageObj.width; | |||||
height = this.options.size * scale || this.imageObj.height; | |||||
} | |||||
else { | |||||
width = 0; | |||||
height = 0; | |||||
} | |||||
} | |||||
else { | |||||
width = this.imageObj.width; | |||||
height = this.imageObj.height; | |||||
} | |||||
this.width = width; | |||||
this.height = height; | |||||
} | |||||
} | |||||
draw(ctx, x, y, selected, hover) { | |||||
this.resize(ctx); | |||||
this.left = x - this.width / 2; | |||||
this.top = y - this.height / 2; | |||||
this._drawImageAtPosition(ctx); | |||||
this.boundingBox.top = this.top; | |||||
this.boundingBox.left = this.left; | |||||
this.boundingBox.right = this.left + this.width; | |||||
this.boundingBox.bottom = this.top + this.height; | |||||
this._drawImageLabel(ctx, x, y, selected || hover); | |||||
this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left); | |||||
this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width); | |||||
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height); | |||||
} | |||||
distanceToBorder(ctx, angle) { | |||||
console.log(this.width) | |||||
this.resize(ctx); | |||||
var a = this.width / 2; | |||||
var b = this.height / 2; | |||||
var w = (Math.sin(angle) * a); | |||||
var h = (Math.cos(angle) * b); | |||||
return a * b / Math.sqrt(w * w + h * h); | |||||
} | |||||
} | |||||
export default Image; |
@ -0,0 +1,126 @@ | |||||
/** | |||||
* Created by Alex on 3/19/2015. | |||||
*/ | |||||
class NodeUtil { | |||||
constructor(options, body, labelModule) { | |||||
this.body = body; | |||||
this.labelModule = labelModule; | |||||
this.setOptions(options); | |||||
this.top = undefined; | |||||
this.left = undefined; | |||||
this.height = undefined; | |||||
this.height = undefined; | |||||
this.boundingBox = {top: 0, left: 0, right: 0, bottom: 0}; | |||||
} | |||||
_drawRawCircle(ctx, x, y, selected, hover, size) { | |||||
var borderWidth = this.options.borderWidth; | |||||
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; | |||||
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border; | |||||
ctx.lineWidth = (selected ? selectionLineWidth : borderWidth); | |||||
ctx.lineWidth *= this.networkScaleInv; | |||||
ctx.lineWidth = Math.min(this.width, ctx.lineWidth); | |||||
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background; | |||||
ctx.circle(x, y, size); | |||||
ctx.fill(); | |||||
ctx.stroke(); | |||||
} | |||||
_drawImageAtPosition(ctx) { | |||||
if (this.imageObj.width != 0) { | |||||
// draw the image | |||||
ctx.globalAlpha = 1.0; | |||||
ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height); | |||||
} | |||||
} | |||||
_distanceToBorder(angle) { | |||||
var borderWidth = 1; | |||||
return Math.min( | |||||
Math.abs(this.width / 2 / Math.cos(angle)), | |||||
Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth; | |||||
} | |||||
_resizeShape() { | |||||
if (this.width === undefined) { | |||||
var size = 2 * this.options.size; | |||||
this.width = size; | |||||
this.height = size; | |||||
} | |||||
} | |||||
_drawShape(ctx, shape, sizeMultiplier, x, y, selected, hover) { | |||||
this._resizeShape(); | |||||
this.left = x - this.width / 2; | |||||
this.top = y - this.height / 2; | |||||
var borderWidth = this.options.borderWidth; | |||||
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; | |||||
// choose draw method depending on the shape | |||||
switch (shape) { | |||||
case 'dot': | |||||
sizeMultiplier = 2; | |||||
break; | |||||
case 'square': | |||||
sizeMultiplier = 2; | |||||
break; | |||||
case 'triangle': | |||||
sizeMultiplier = 3; | |||||
break; | |||||
case 'triangleDown': | |||||
sizeMultiplier = 3; | |||||
break; | |||||
case 'star': | |||||
sizeMultiplier = 4; | |||||
break; | |||||
} | |||||
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border; | |||||
ctx.lineWidth = (selected ? selectionLineWidth : borderWidth); | |||||
ctx.lineWidth /= this.body.view.scale; | |||||
ctx.lineWidth = Math.min(this.width, ctx.lineWidth); | |||||
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background; | |||||
ctx[shape](x, y, this.options.size); | |||||
ctx.fill(); | |||||
ctx.stroke(); | |||||
this.boundingBox.top = y - this.options.size; | |||||
this.boundingBox.left = x - this.options.size; | |||||
this.boundingBox.right = x + this.options.size; | |||||
this.boundingBox.bottom = y + this.options.size; | |||||
if (this.options.label!== undefined) { | |||||
this.labelModule.draw(ctx, x, y + 0.5* this.height, selected, 'hanging'); | |||||
this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left); | |||||
this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width); | |||||
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height); | |||||
} | |||||
} | |||||
_drawImageLabel(ctx, x, y, selected) { | |||||
var yLabel; | |||||
var offset = 0; | |||||
if (this.height !== undefined) { | |||||
offset = this.height * 0.5; | |||||
var labelDimensions = this.labelModule.getTextSize(ctx); | |||||
if (labelDimensions.lineCount >= 1) { | |||||
offset += labelDimensions.height / 2; | |||||
offset += 3; | |||||
} | |||||
} | |||||
yLabel = y + offset; | |||||
this.labelModule.draw(ctx, x, yLabel, selected, 'hanging'); | |||||
} | |||||
} | |||||
export default NodeUtil; |
@ -0,0 +1,31 @@ | |||||
/** | |||||
* Created by Alex on 3/18/2015. | |||||
*/ | |||||
'use strict'; | |||||
import NodeUtil from './nodeUtil' | |||||
class Square extends NodeUtil { | |||||
constructor (options, body, labelModule) { | |||||
super(options, body, labelModule) | |||||
} | |||||
setOptions(options) { | |||||
this.options = options; | |||||
} | |||||
resize(ctx) { | |||||
this._resizeShape(); | |||||
} | |||||
draw(ctx, x, y, selected, hover) { | |||||
this._drawShape(ctx, 'square', 2, x, y, selected, hover); | |||||
} | |||||
distanceToBorder(ctx, angle) { | |||||
this.resize(ctx); | |||||
return this._distanceToBorder(angle); | |||||
} | |||||
} | |||||
export default Square; |
@ -0,0 +1,30 @@ | |||||
/** | |||||
* Created by Alex on 3/18/2015. | |||||
*/ | |||||
'use strict'; | |||||
import NodeUtil from './nodeUtil' | |||||
class Star extends NodeUtil { | |||||
constructor (options, body, labelModule) { | |||||
super(options, body, labelModule) | |||||
} | |||||
setOptions(options) { | |||||
this.options = options; | |||||
} | |||||
resize(ctx) { | |||||
this._resizeShape(); | |||||
} | |||||
draw(ctx, x, y, selected, hover) { | |||||
this._drawShape(ctx, 'star', 4, x, y, selected, hover); | |||||
} | |||||
distanceToBorder(ctx, angle) { | |||||
return this._distanceToBorder(angle); | |||||
} | |||||
} | |||||
export default Star; |
@ -0,0 +1,47 @@ | |||||
/** | |||||
* Created by Alex on 3/18/2015. | |||||
*/ | |||||
'use strict'; | |||||
import NodeUtil from './nodeUtil' | |||||
class Text extends NodeUtil { | |||||
constructor (options, body, labelModule) { | |||||
super(options, body, labelModule); | |||||
} | |||||
setOptions(options) { | |||||
this.options = options; | |||||
} | |||||
resize(ctx, selected) { | |||||
if (this.width === undefined) { | |||||
var margin = 5; | |||||
var textSize = this.labelModule.getTextSize(ctx,selected); | |||||
this.width = textSize.width + 2 * margin; | |||||
this.height = textSize.height + 2 * margin; | |||||
} | |||||
} | |||||
draw(ctx, x, y, selected, hover) { | |||||
this.resize(ctx, selected || hover); | |||||
this.left = x - this.width / 2; | |||||
this.top = y - this.height / 2; | |||||
this.labelModule.draw(ctx, x, y, selected || hover); | |||||
this.boundingBox.top = this.top; | |||||
this.boundingBox.left = this.left; | |||||
this.boundingBox.right = this.left + this.width; | |||||
this.boundingBox.bottom = this.top + this.height; | |||||
} | |||||
distanceToBorder(ctx, angle) { | |||||
console.log("hererer") | |||||
console.log(this._distanceToBorder(angle)) | |||||
this.resize(ctx); | |||||
return this._distanceToBorder(angle); | |||||
} | |||||
} | |||||
export default Text; |
@ -0,0 +1,30 @@ | |||||
/** | |||||
* Created by Alex on 3/18/2015. | |||||
*/ | |||||
'use strict'; | |||||
import NodeUtil from './nodeUtil' | |||||
class Triangle extends NodeUtil { | |||||
constructor (options, body, labelModule) { | |||||
super(options, body, labelModule) | |||||
} | |||||
setOptions(options) { | |||||
this.options = options; | |||||
} | |||||
resize(ctx) { | |||||
this._resizeShape(); | |||||
} | |||||
draw(ctx, x, y, selected, hover) { | |||||
this._drawShape(ctx, 'triangle', 3, x, y, selected, hover); | |||||
} | |||||
distanceToBorder(ctx, angle) { | |||||
return this._distanceToBorder(angle); | |||||
} | |||||
} | |||||
export default Triangle; |
@ -0,0 +1,30 @@ | |||||
/** | |||||
* Created by Alex on 3/18/2015. | |||||
*/ | |||||
'use strict'; | |||||
import NodeUtil from './nodeUtil' | |||||
class TriangleDown extends NodeUtil { | |||||
constructor (options, body, labelModule) { | |||||
super(options, body, labelModule) | |||||
} | |||||
setOptions(options) { | |||||
this.options = options; | |||||
} | |||||
resize(ctx) { | |||||
this._resizeShape(); | |||||
} | |||||
draw(ctx, x, y, selected, hover) { | |||||
this._drawShape(ctx, 'triangleDown', 3, x, y, selected, hover); | |||||
} | |||||
distanceToBorder(ctx, angle) { | |||||
return this._distanceToBorder(angle); | |||||
} | |||||
} | |||||
export default TriangleDown; |