Added basic functionality for image nodes
Extended the drawNode function to include basic image drawing. Adjusted the height and width functions to accommodate natural image dimensions as well as those set with node.data.image.width etc.
This commit is contained in:
parent
98369ebcb9
commit
96f889ca41
116
springyui.js
116
springyui.js
|
@ -1,5 +1,5 @@
|
||||||
/**
|
/**
|
||||||
Copyright (c) 2010 Dennis Hotson
|
Copyright (c) 2010 Dennis Hotson, 2014 Taylor Smith
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
Permission is hereby granted, free of charge, to any person
|
||||||
obtaining a copy of this software and associated documentation
|
obtaining a copy of this software and associated documentation
|
||||||
|
@ -33,6 +33,7 @@ jQuery.fn.springy = function(params) {
|
||||||
var repulsion = params.repulsion || 400.0;
|
var repulsion = params.repulsion || 400.0;
|
||||||
var damping = params.damping || 0.5;
|
var damping = params.damping || 0.5;
|
||||||
var nodeSelected = params.nodeSelected || null;
|
var nodeSelected = params.nodeSelected || null;
|
||||||
|
var nodeImages = {};
|
||||||
|
|
||||||
var canvas = this[0];
|
var canvas = this[0];
|
||||||
var ctx = canvas.getContext("2d");
|
var ctx = canvas.getContext("2d");
|
||||||
|
@ -121,26 +122,62 @@ jQuery.fn.springy = function(params) {
|
||||||
dragged = null;
|
dragged = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
Springy.Node.prototype.getWidth = function() {
|
var getTextWidth = function(node) {
|
||||||
var text = (this.data.label !== undefined) ? this.data.label : this.id;
|
var text = (node.data.label !== undefined) ? node.data.label : node.id;
|
||||||
if (this._width && this._width[text])
|
if (node._width && node._width[text])
|
||||||
return this._width[text];
|
return node._width[text];
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.font = (this.data.font !== undefined) ? this.data.font : nodeFont;
|
ctx.font = (node.data.font !== undefined) ? node.data.font : nodeFont;
|
||||||
var width = ctx.measureText(text).width + 10;
|
var width = ctx.measureText(text).width;
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
|
|
||||||
this._width || (this._width = {});
|
node._width || (node._width = {});
|
||||||
this._width[text] = width;
|
node._width[text] = width;
|
||||||
|
|
||||||
return width;
|
return width;
|
||||||
};
|
};
|
||||||
|
|
||||||
Springy.Node.prototype.getHeight = function() {
|
var getTextHeight = function(node) {
|
||||||
return 20;
|
return 16;
|
||||||
|
// In a more modular world, this would actually read the font size, but I think leaving it a constant is sufficient for now.
|
||||||
|
// If you change the font size, I'd adjust this too.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var getImageWidth = function(node) {
|
||||||
|
var width = (node.data.image.width !== undefined) ? node.data.image.width : nodeImages[node.data.image.src].object.width;
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
var getImageHeight = function(node) {
|
||||||
|
var height = (node.data.image.height !== undefined) ? node.data.image.height : nodeImages[node.data.image.src].object.height;
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
Springy.Node.prototype.getHeight = function() {
|
||||||
|
var height;
|
||||||
|
if (this.data.image == undefined) {
|
||||||
|
height = getTextHeight(this);
|
||||||
|
} else {
|
||||||
|
if (this.data.image.src in nodeImages && nodeImages[this.data.image.src].loaded) {
|
||||||
|
height = getImageHeight(this);
|
||||||
|
} else {height = 10;}
|
||||||
|
}
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
Springy.Node.prototype.getWidth = function() {
|
||||||
|
var width;
|
||||||
|
if (this.data.image == undefined) {
|
||||||
|
width = getTextWidth(this);
|
||||||
|
} else {
|
||||||
|
if (this.data.image.src in nodeImages && nodeImages[this.data.image.src].loaded) {
|
||||||
|
width = getImageWidth(this);
|
||||||
|
} else {width = 10;}
|
||||||
|
}
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
var renderer = this.renderer = new Springy.Renderer(layout,
|
var renderer = this.renderer = new Springy.Renderer(layout,
|
||||||
function clear() {
|
function clear() {
|
||||||
ctx.clearRect(0,0,canvas.width,canvas.height);
|
ctx.clearRect(0,0,canvas.width,canvas.height);
|
||||||
|
@ -173,11 +210,14 @@ jQuery.fn.springy = function(params) {
|
||||||
// Figure out how far off center the line should be drawn
|
// Figure out how far off center the line should be drawn
|
||||||
var offset = normal.multiply(-((total - 1) * spacing)/2.0 + (n * spacing));
|
var offset = normal.multiply(-((total - 1) * spacing)/2.0 + (n * spacing));
|
||||||
|
|
||||||
|
var paddingX = 6;
|
||||||
|
var paddingY = 6;
|
||||||
|
|
||||||
var s1 = toScreen(p1).add(offset);
|
var s1 = toScreen(p1).add(offset);
|
||||||
var s2 = toScreen(p2).add(offset);
|
var s2 = toScreen(p2).add(offset);
|
||||||
|
|
||||||
var boxWidth = edge.target.getWidth();
|
var boxWidth = edge.target.getWidth() + paddingX;
|
||||||
var boxHeight = edge.target.getHeight();
|
var boxHeight = edge.target.getHeight() + paddingY;
|
||||||
|
|
||||||
var intersection = intersect_line_box(s1, s2, {x: x2-boxWidth/2.0, y: y2-boxHeight/2.0}, boxWidth, boxHeight);
|
var intersection = intersect_line_box(s1, s2, {x: x2-boxWidth/2.0, y: y2-boxHeight/2.0}, boxWidth, boxHeight);
|
||||||
|
|
||||||
|
@ -249,11 +289,18 @@ jQuery.fn.springy = function(params) {
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
var boxWidth = node.getWidth();
|
// Pulled out the padding aspect sso that the size functions could be used in multiple places
|
||||||
var boxHeight = node.getHeight();
|
// These should probably be settable by the user (and scoped higher) but this suffices for now
|
||||||
|
var paddingX = 6;
|
||||||
|
var paddingY = 6;
|
||||||
|
|
||||||
|
var contentWidth = node.getWidth();
|
||||||
|
var contentHeight = node.getHeight();
|
||||||
|
var boxWidth = contentWidth + paddingX;
|
||||||
|
var boxHeight = contentHeight + paddingY;
|
||||||
|
|
||||||
// clear background
|
// clear background
|
||||||
ctx.clearRect(s.x - boxWidth/2, s.y - 10, boxWidth, 20);
|
ctx.clearRect(s.x - boxWidth/2, s.y - boxHeight/2, boxWidth, boxHeight);
|
||||||
|
|
||||||
// fill background
|
// fill background
|
||||||
if (selected !== null && selected.node !== null && selected.node.id === node.id) {
|
if (selected !== null && selected.node !== null && selected.node.id === node.id) {
|
||||||
|
@ -263,15 +310,36 @@ jQuery.fn.springy = function(params) {
|
||||||
} else {
|
} else {
|
||||||
ctx.fillStyle = "#FFFFFF";
|
ctx.fillStyle = "#FFFFFF";
|
||||||
}
|
}
|
||||||
ctx.fillRect(s.x - boxWidth/2, s.y - 10, boxWidth, 20);
|
ctx.fillRect(s.x - boxWidth/2, s.y - boxHeight/2, boxWidth, boxHeight);
|
||||||
|
|
||||||
ctx.textAlign = "left";
|
|
||||||
ctx.textBaseline = "top";
|
|
||||||
ctx.font = (node.data.font !== undefined) ? node.data.font : nodeFont;
|
|
||||||
ctx.fillStyle = "#000000";
|
|
||||||
var text = (node.data.label !== undefined) ? node.data.label : node.id;
|
|
||||||
ctx.fillText(text, s.x - boxWidth/2 + 5, s.y - 8);
|
|
||||||
|
|
||||||
|
if (node.data.image == undefined) {
|
||||||
|
ctx.textAlign = "left";
|
||||||
|
ctx.textBaseline = "top";
|
||||||
|
ctx.font = (node.data.font !== undefined) ? node.data.font : nodeFont;
|
||||||
|
ctx.fillStyle = "#000000";
|
||||||
|
var text = (node.data.label !== undefined) ? node.data.label : node.id;
|
||||||
|
ctx.fillText(text, s.x - contentWidth/2, s.y - contentHeight/2);
|
||||||
|
} else {
|
||||||
|
// Currently we just ignore any labels if the image object is set. One might want to extend this logic to allow for both, or other composite nodes.
|
||||||
|
var src = node.data.image.src; // There should probably be a sanity check here too, but un-src-ed images aren't exaclty a disaster.
|
||||||
|
if (src in nodeImages) {
|
||||||
|
if (nodeImages[src].loaded) {
|
||||||
|
// Our image is loaded, so it's safe to draw
|
||||||
|
ctx.drawImage(nodeImages[src].object, s.x - contentWidth/2, s.y - contentHeight/2, contentWidth, contentHeight);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
// First time seeing an image with this src address, so add it to our set of image objects
|
||||||
|
// Note: we index images by their src to avoid making too many duplicates
|
||||||
|
nodeImages[src] = {};
|
||||||
|
var img = new Image();
|
||||||
|
nodeImages[src].object = img;
|
||||||
|
img.addEventListener("load", function () {
|
||||||
|
// HTMLImageElement objects are very finicky about being used before they are loaded, so we set a flag when it is done
|
||||||
|
nodeImages[src].loaded = true;
|
||||||
|
});
|
||||||
|
img.src = src;
|
||||||
|
}
|
||||||
|
}
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user