@ -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. | |||
*/ | |||
'use strict'; | |||
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; |