mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-24 11:08:45 +02:00
Replacement of the impact Flash based analysis graph by graphviz + Raphael + TCPDF. ALPHA version.
SVN:trunk[3554]
This commit is contained in:
574
js/fraphael.js
Normal file
574
js/fraphael.js
Normal file
@@ -0,0 +1,574 @@
|
||||
/**
|
||||
* FRaphael
|
||||
* An extension for Raphael.js to make it easier to work with Filter Effects
|
||||
*
|
||||
* Copyright © 2013 Chris Scott <chris.scott@factmint.com>
|
||||
* Delivered with and licensed under the MIT licence
|
||||
*
|
||||
*/
|
||||
|
||||
// Create the global FRaphael object
|
||||
(function(scope) {
|
||||
var version = "0.0.1",
|
||||
license = "MIT";
|
||||
|
||||
var ns = "http://www.w3.org/2000/svg",
|
||||
idCounter = 0;
|
||||
|
||||
var FR = {
|
||||
// Object prototype for a filter
|
||||
Filter: function(id) {
|
||||
if (id == undefined) {
|
||||
id = "filter-" + idCounter++;
|
||||
while(FR.filters[id] != undefined) {
|
||||
id = "filter-" + idCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
if (FR.filters[id] != undefined) {
|
||||
throw "A filter with id " + id + " already exists";
|
||||
}
|
||||
|
||||
this.element = document.createElementNS(ns, "filter");
|
||||
this.element.setAttribute("id", id);
|
||||
this.element.setAttribute("x", "-25%");
|
||||
this.element.setAttribute("y", "-25%");
|
||||
this.element.setAttribute("width", "150%");
|
||||
this.element.setAttribute("height", "150%");
|
||||
|
||||
this.lastFEResult = null;
|
||||
|
||||
FR.filters[id] = this;
|
||||
this.id = id;
|
||||
},
|
||||
|
||||
// Object prototype for an effect
|
||||
FilterEffect: function(type, attributes) {
|
||||
this.element = document.createElementNS(ns, type);
|
||||
for (var key in attributes) {
|
||||
this.element.setAttribute(key, attributes[key]);
|
||||
}
|
||||
},
|
||||
|
||||
// Return the filter applied to an element or a new filter if none are currently applied
|
||||
getFilter: function(element) {
|
||||
var filterId = element.data("filterId");
|
||||
var filter = null;
|
||||
|
||||
if (filterId == undefined) {
|
||||
filterId = "element-filter-" + element.id;
|
||||
filter = element.paper.createFilter(filterId);
|
||||
element.filter(filterId);
|
||||
} else {
|
||||
filter = FR.filters[filterId];
|
||||
}
|
||||
|
||||
return filter;
|
||||
},
|
||||
|
||||
// maintain a list of filters by id
|
||||
filters: {}
|
||||
};
|
||||
|
||||
FR.Filter.prototype = {
|
||||
addEffect: function(type, attributes, children) {
|
||||
var effect = new FR.FilterEffect(type, attributes);
|
||||
|
||||
if (children) {
|
||||
if (children instanceof Array) {
|
||||
for (var x in children) {
|
||||
if (!children.hasOwnProperty(x)) continue;
|
||||
|
||||
effect.element.appendChild(children[x].element);
|
||||
}
|
||||
} else {
|
||||
effect.element.appendChild(children.element);
|
||||
}
|
||||
}
|
||||
|
||||
this.element.appendChild(effect.element);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
chainEffect: function(type, attributes, children) {
|
||||
if (attributes == undefined) {
|
||||
attributes = {};
|
||||
}
|
||||
|
||||
var inId;
|
||||
var outId;
|
||||
if (attributes.in == undefined) {
|
||||
inId = this.getLastResult();
|
||||
} else {
|
||||
inId = attributes.in;
|
||||
}
|
||||
if (attributes.result == undefined) {
|
||||
outId = idCounter++;
|
||||
} else {
|
||||
outId = attributes.result;
|
||||
}
|
||||
|
||||
this.lastFEResult = outId;
|
||||
|
||||
attributes.in = inId;
|
||||
attributes.result = outId;
|
||||
|
||||
this.addEffect(type, attributes, children);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
getLastResult: function() {
|
||||
return (this.lastFEResult == undefined) ? "SourceGraphic" : this.lastFEResult;
|
||||
},
|
||||
|
||||
merge: function(in1, in2, attributes) {
|
||||
var mergeNode1 = new FR.FilterEffect("feMergeNode", {
|
||||
in: in1
|
||||
});
|
||||
var mergeNode2 = new FR.FilterEffect("feMergeNode", {
|
||||
in: in2
|
||||
});
|
||||
|
||||
this.chainEffect("feMerge", attributes, [mergeNode1, mergeNode2]);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
compose: function(in1, in2, operator, attributes) {
|
||||
if (attributes == undefined) {
|
||||
attributes = {};
|
||||
}
|
||||
|
||||
if (operator == undefined) {
|
||||
operator = "over";
|
||||
}
|
||||
|
||||
attributes.in = in1;
|
||||
attributes.in2 = in2;
|
||||
attributes.operator = operator;
|
||||
|
||||
this.chainEffect("feComposite", attributes);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
arithmeticCompose: function(in1, in2, k1, k2, k3, k4) {
|
||||
if (k1 == undefined) {
|
||||
k1 = 0;
|
||||
}
|
||||
if (k2 == undefined) {
|
||||
k2 = 0;
|
||||
}
|
||||
if (k3 == undefined) {
|
||||
k3 = 0;
|
||||
}
|
||||
if (k4 == undefined) {
|
||||
k4 = 0;
|
||||
}
|
||||
|
||||
this.compose(in1, in2, "arithmetic", {
|
||||
k1: k1,
|
||||
k2: k2,
|
||||
k3: k3,
|
||||
k4: k4
|
||||
});
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
addBlur: function(stdDeviation, attributes) {
|
||||
if (!stdDeviation) {
|
||||
throw "Standard deviation is required to perform a blur filter";
|
||||
}
|
||||
|
||||
if (attributes == undefined) {
|
||||
attributes = {};
|
||||
}
|
||||
attributes.stdDeviation = stdDeviation;
|
||||
|
||||
this.chainEffect("feGaussianBlur", attributes);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
addOffset: function(dx, dy, attributes) {
|
||||
if (dx == undefined | dy == undefined) {
|
||||
throw "dx and dy values are required to perform an offset FE";
|
||||
}
|
||||
|
||||
if (attributes == undefined) {
|
||||
attributes = {};
|
||||
}
|
||||
attributes.dx = dx;
|
||||
attributes.dy = dy;
|
||||
|
||||
this.chainEffect("feOffset", attributes);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
addLighting: function(x, y, z, color, type, attributes) {
|
||||
if (x == undefined | y == undefined | z == undefined) {
|
||||
throw "Three co-ordinates are required to create a light source";
|
||||
}
|
||||
|
||||
var previousResult = this.getLastResult();
|
||||
|
||||
var id = idCounter++;
|
||||
|
||||
if (attributes == undefined) {
|
||||
attributes = {};
|
||||
}
|
||||
|
||||
attributes.result = id;
|
||||
if (color != undefined) {
|
||||
attributes["lighting-color"] = color;
|
||||
}
|
||||
|
||||
if (type == undefined || type == "diffuse") {
|
||||
type = "feDiffuseLighting";
|
||||
} else if (type == "specular") {
|
||||
type = "feSpecularLighting";
|
||||
}
|
||||
|
||||
var lightSource = new FR.FilterEffect("fePointLight", {
|
||||
x: x,
|
||||
y: y,
|
||||
z: z
|
||||
});
|
||||
|
||||
this.chainEffect(type, attributes, lightSource).arithmeticCompose(previousResult, id, 3, 0.2, 0, 0);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
addShiftToColor: function(color, moveBy, attributes) {
|
||||
if (color == undefined) {
|
||||
throw "A colour string is a required argument to create a colorMatrix";
|
||||
}
|
||||
if (moveBy == undefined) {
|
||||
moveBy = 0.5;
|
||||
}
|
||||
|
||||
var remainingColor = 1 - moveBy, x = remainingColor;
|
||||
|
||||
if (attributes == undefined) {
|
||||
attributes = {};
|
||||
}
|
||||
|
||||
var colorObject = Raphael.color(color);
|
||||
var r = colorObject.r * moveBy / 255,
|
||||
g = colorObject.g * moveBy / 255,
|
||||
b = colorObject.b * moveBy / 255;
|
||||
|
||||
/**
|
||||
* r' x 0 0 0 r r
|
||||
* g' 0 x 0 0 g g
|
||||
* b' = 0 0 x 0 b . b
|
||||
* a' 0 0 0 1 0 o
|
||||
* 1 1
|
||||
*/
|
||||
attributes.values = x + " 0 0 0 " + r + " 0 " + x + " 0 0 " + g + " 0 0 " + x + " 0 " + b + " 0 0 0 1 0 ";
|
||||
|
||||
this.chainEffect("feColorMatrix", attributes);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
addRecolor: function(color, opacity, attributes) {
|
||||
if (color == undefined) {
|
||||
throw "A colour string is a required argument to create a colorMatrix";
|
||||
}
|
||||
if (opacity == undefined) {
|
||||
opacity = 1;
|
||||
}
|
||||
|
||||
if (attributes == undefined) {
|
||||
attributes = {};
|
||||
}
|
||||
|
||||
var colorObject = Raphael.color(color);
|
||||
var r = colorObject.r / 255,
|
||||
g = colorObject.g / 255,
|
||||
b = colorObject.b / 255;
|
||||
|
||||
/**
|
||||
* r' 0 0 0 0 r r
|
||||
* g' 0 0 0 0 g g
|
||||
* b' = 0 0 0 0 b . b
|
||||
* a' 0 0 0 a 0 a
|
||||
* 1 1
|
||||
*/
|
||||
attributes.values = "0 0 0 0 " + r + " 0 0 0 0 " + g + " 0 0 0 0 " + b + " 0 0 0 " + opacity + " 0 ";
|
||||
|
||||
this.chainEffect("feColorMatrix", attributes);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
addDesaturate: function(saturation, attributes) {
|
||||
if (saturation == undefined) {
|
||||
saturnation = 0;
|
||||
}
|
||||
|
||||
if (attributes == undefined) {
|
||||
attributes = {};
|
||||
}
|
||||
|
||||
attributes.values = saturation;
|
||||
attributes.type = "saturate";
|
||||
|
||||
this.chainEffect("feColorMatrix", attributes);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
addConvolveMatrix: function(matrix, attributes) {
|
||||
if (matrix == undefined) {
|
||||
throw "A matrix (usually 9 numbers) must be provided to apply a convolve matrix transform";
|
||||
}
|
||||
|
||||
if (attributes == undefined) {
|
||||
attributes = {};
|
||||
}
|
||||
|
||||
attributes.kernelMatrix = matrix;
|
||||
|
||||
this.chainEffect("feConvolveMatrix", attributes);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
createShadow: function(dx, dy, blur, opacity, color) {
|
||||
if (dx == undefined) {
|
||||
throw "dx is required for the shadow effect";
|
||||
}
|
||||
if (dy == undefined) {
|
||||
throw "dy is required for the shadow effect";
|
||||
}
|
||||
if (blur == undefined) {
|
||||
throw "blur (stdDeviation) is required for the shadow effect";
|
||||
}
|
||||
|
||||
if (opacity == undefined) {
|
||||
opacity = 0.6;
|
||||
}
|
||||
|
||||
var previousResult = this.getLastResult();
|
||||
|
||||
if (color == undefined) {
|
||||
color = "#000000";
|
||||
}
|
||||
|
||||
this.addOffset(dx, dy, {
|
||||
in: "SourceAlpha"
|
||||
});
|
||||
|
||||
this.addRecolor(color, opacity);
|
||||
|
||||
this.addBlur(blur);
|
||||
|
||||
this.merge(this.getLastResult(), previousResult);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
createEmboss: function(height, x, y, z) {
|
||||
if (height == undefined) {
|
||||
height = 2;
|
||||
}
|
||||
if (x == undefined) {
|
||||
x = -1000;
|
||||
}
|
||||
if (y == undefined) {
|
||||
y = -5000;
|
||||
}
|
||||
if (z == undefined) {
|
||||
z = 300;
|
||||
}
|
||||
|
||||
// Create the highlight
|
||||
|
||||
this.addOffset(height * x / (x + y), height * y / (x + y), {
|
||||
in: "SourceAlpha"
|
||||
});
|
||||
|
||||
this.addBlur(height * 0.5);
|
||||
|
||||
var whiteLightSource = new FR.FilterEffect("fePointLight", {
|
||||
x: x,
|
||||
y: y,
|
||||
z: z
|
||||
});
|
||||
|
||||
this.chainEffect("feSpecularLighting", {
|
||||
surfaceScale: height,
|
||||
specularConstant: 0.8,
|
||||
specularExponent: 15
|
||||
}, whiteLightSource);
|
||||
|
||||
this.compose(this.getLastResult(), "SourceAlpha", "in");
|
||||
var whiteLight = this.getLastResult();
|
||||
|
||||
// Create the lowlight
|
||||
|
||||
this.addOffset(height * -1 * x / (x + y), height * -1 * y / (x + y), {
|
||||
in: "SourceAlpha"
|
||||
});
|
||||
|
||||
this.addBlur(height * 0.5);
|
||||
|
||||
var darkLightSource = new FR.FilterEffect("fePointLight", {
|
||||
x: -1 * x,
|
||||
y: -1 * y,
|
||||
z: z
|
||||
});
|
||||
|
||||
this.chainEffect("feSpecularLighting", {
|
||||
surfaceScale: height,
|
||||
specularConstant: 1.8,
|
||||
specularExponent: 6
|
||||
}, darkLightSource);
|
||||
|
||||
this.compose(this.getLastResult(), "SourceAlpha", "in");
|
||||
this.chainEffect("feColorMatrix", {
|
||||
values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0"
|
||||
});
|
||||
var darkLight = this.getLastResult();
|
||||
|
||||
this.arithmeticCompose(whiteLight, darkLight, 0, 0.8, 0.5, 0);
|
||||
|
||||
this.merge("SourceGraphic", this.getLastResult());
|
||||
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
scope.FRaphael = FR;
|
||||
})(this);
|
||||
|
||||
/**
|
||||
* add a filter to the paper by id
|
||||
*/
|
||||
Raphael.fn.createFilter = function(id) {
|
||||
var paper = this;
|
||||
var filter = new FRaphael.Filter(id);
|
||||
paper.defs.appendChild(filter.element);
|
||||
|
||||
return filter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply a filter to an element by id
|
||||
*/
|
||||
Raphael.el.filter = function(filter) {
|
||||
var id = (filter instanceof FRaphael.Filter) ? filter.id : filter;
|
||||
|
||||
this.node.setAttribute("filter", "url(#" + id + ")");
|
||||
this.data("filterId", id);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current filter for an element or a new one if not
|
||||
*/
|
||||
Raphael.el.getFilter = function() {
|
||||
return FRaphael.getFilter(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* A shorthand method for applying blur
|
||||
*/
|
||||
Raphael.el.blur = function(stdDeviation) {
|
||||
if (stdDeviation == undefined) {
|
||||
stdDeviation = 3;
|
||||
}
|
||||
|
||||
this.getFilter().addBlur(stdDeviation);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* A shorthand method for applying a drop shadow
|
||||
*/
|
||||
Raphael.el.shadow = function(dx, dy, blur, opacity, color) {
|
||||
if (dx == undefined) {
|
||||
dx = 3;
|
||||
}
|
||||
if (dy == undefined) {
|
||||
dy = 3;
|
||||
}
|
||||
if (blur == undefined) {
|
||||
blur = 3;
|
||||
}
|
||||
|
||||
this.getFilter().createShadow(dx, dy, blur, opacity, color);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* A shorthand method for applying lighting
|
||||
*/
|
||||
Raphael.el.light = function(x, y, z, color, type) {
|
||||
if (x == undefined) {
|
||||
x = this.paper.width;
|
||||
}
|
||||
if (y == undefined) {
|
||||
y = 0;
|
||||
}
|
||||
if (z == undefined) {
|
||||
z = 20;
|
||||
}
|
||||
|
||||
this.getFilter().addLighting(x, y, z, color, type);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* A shorthand method for applying a colour shift
|
||||
*/
|
||||
Raphael.el.colorShift = function(color, shift) {
|
||||
if (color == undefined) {
|
||||
color = "black";
|
||||
}
|
||||
if (shift == undefined) {
|
||||
shift = 0.5;
|
||||
}
|
||||
|
||||
this.getFilter().addShiftToColor(color, shift);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* A shorthand method for embossing
|
||||
*/
|
||||
Raphael.el.emboss = function(height) {
|
||||
this.getFilter().createEmboss(height);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* A shorthand method for desaturating
|
||||
*/
|
||||
Raphael.el.desaturate = function(saturation) {
|
||||
this.getFilter().addDesaturate(saturation);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* A shorthand method for complete desaturation
|
||||
*/
|
||||
Raphael.el.greyScale = function() {
|
||||
this.getFilter().addDesaturate(0);
|
||||
|
||||
return this;
|
||||
};
|
||||
326
js/simple_graph.js
Normal file
326
js/simple_graph.js
Normal file
@@ -0,0 +1,326 @@
|
||||
// jQuery UI style "widget" for displaying a graph
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// graph
|
||||
//
|
||||
$(function()
|
||||
{
|
||||
// the widget definition, where "itop" is the namespace,
|
||||
// "dashboard" the widget name
|
||||
$.widget( "itop.simple_graph",
|
||||
{
|
||||
// default options
|
||||
options:
|
||||
{
|
||||
xmin: 0,
|
||||
xmax: 0,
|
||||
ymin: 0,
|
||||
ymax: 0,
|
||||
align: 'center',
|
||||
'vertical-align': 'middle'
|
||||
},
|
||||
|
||||
// the constructor
|
||||
_create: function()
|
||||
{
|
||||
var me = this;
|
||||
this.aNodes = [];
|
||||
this.aEdges = [];
|
||||
this.fZoom = 1.0;
|
||||
this.xOffset = 0;
|
||||
this.yOffset = 0;
|
||||
this.iTextHeight = 12;
|
||||
//this.element.height(this.element.parent().height());
|
||||
this.oPaper = Raphael(this.element.get(0), this.element.width(), this.element.height());
|
||||
|
||||
this.auto_scale();
|
||||
|
||||
this.element
|
||||
.addClass('itop-simple-graph');
|
||||
|
||||
this._create_toolkit_menu();
|
||||
},
|
||||
|
||||
// called when created, and later when changing options
|
||||
_refresh: function()
|
||||
{
|
||||
this.draw();
|
||||
},
|
||||
// events bound via _bind are removed automatically
|
||||
// revert other modifications here
|
||||
_destroy: function()
|
||||
{
|
||||
var sId = this.element.attr('id');
|
||||
this.element
|
||||
.removeClass('itop-simple-graph');
|
||||
|
||||
$('#tk_graph'+sId).remove();
|
||||
|
||||
},
|
||||
// _setOptions is called with a hash of all options that are changing
|
||||
_setOptions: function()
|
||||
{
|
||||
this._superApply(arguments);
|
||||
},
|
||||
// _setOption is called for each individual option that is changing
|
||||
_setOption: function( key, value )
|
||||
{
|
||||
this._superApply(arguments);
|
||||
},
|
||||
draw: function()
|
||||
{
|
||||
this.oPaper.clear();
|
||||
for(var k in this.aNodes)
|
||||
{
|
||||
this._draw_node(this.aNodes[k]);
|
||||
}
|
||||
for(var k in this.aEdges)
|
||||
{
|
||||
this._draw_edge(this.aEdges[k]);
|
||||
}
|
||||
},
|
||||
_draw_node: function(oNode)
|
||||
{
|
||||
var iWidth = oNode.width;
|
||||
var iHeight = 32;
|
||||
var xPos = Math.round(oNode.x * this.fZoom + this.xOffset);
|
||||
var yPos = Math.round(oNode.y * this.fZoom + this.yOffset);
|
||||
oNode.tx = 0;
|
||||
oNode.ty = 0;
|
||||
switch(oNode.shape)
|
||||
{
|
||||
case 'disc':
|
||||
oNode.aElements.push(this.oPaper.circle(xPos, yPos, iWidth*this.fZoom / 2).attr(oNode.disc_attr));
|
||||
var oText = this.oPaper.text(xPos, yPos, oNode.label);
|
||||
oText.attr(oNode.text_attr);
|
||||
oText.transform('s'+this.fZoom);
|
||||
oNode.aElements.push(oText);
|
||||
break;
|
||||
|
||||
case 'group':
|
||||
oNode.aElements.push(this.oPaper.circle(xPos, yPos, iWidth*this.fZoom / 2).attr({fill: '#fff', 'stroke-width':0}));
|
||||
oNode.aElements.push(this.oPaper.circle(xPos, yPos, iWidth*this.fZoom / 2).attr(oNode.disc_attr));
|
||||
var xIcon = xPos - 18 * this.fZoom;
|
||||
var yIcon = yPos - 18 * this.fZoom;
|
||||
oNode.aElements.push(this.oPaper.image(oNode.icon_url, xIcon, yIcon, 16*this.fZoom, 16*this.fZoom).attr(oNode.icon_attr));
|
||||
oNode.aElements.push(this.oPaper.image(oNode.icon_url, xIcon + 18*this.fZoom, yIcon, 16*this.fZoom, 16*this.fZoom).attr(oNode.icon_attr));
|
||||
oNode.aElements.push(this.oPaper.image(oNode.icon_url, xIcon + 9*this.fZoom, yIcon + 18*this.fZoom, 16*this.fZoom, 16*this.fZoom).attr(oNode.icon_attr));
|
||||
var oText = this.oPaper.text(xPos, yPos +2, oNode.label);
|
||||
oText.attr(oNode.text_attr);
|
||||
oText.transform('s'+this.fZoom);
|
||||
var oBB = oText.getBBox();
|
||||
var dy = iHeight/2*this.fZoom + oBB.height/2;
|
||||
oText.remove();
|
||||
oText = this.oPaper.text(xPos, yPos +dy +2, oNode.label);
|
||||
oText.attr(oNode.text_attr);
|
||||
oText.transform('s'+this.fZoom);
|
||||
oNode.aElements.push(oText);
|
||||
oNode.aElements.push(this.oPaper.rect( xPos - oBB.width/2 -2, yPos - oBB.height/2 + dy, oBB.width +4, oBB.height).attr({fill: '#fff', stroke: '#fff', opacity: 0.9}));
|
||||
oText.toFront();
|
||||
break;
|
||||
|
||||
case 'icon':
|
||||
if(Raphael.svg)
|
||||
{
|
||||
// the colorShift plugin works only in SVG
|
||||
oNode.aElements.push(this.oPaper.image(oNode.icon_url, xPos - iWidth * this.fZoom/2, yPos - iHeight * this.fZoom/2, iWidth*this.fZoom, iHeight*this.fZoom).colorShift('#fff', 1));
|
||||
}
|
||||
oNode.aElements.push(this.oPaper.image(oNode.icon_url, xPos - iWidth * this.fZoom/2, yPos - iHeight * this.fZoom/2, iWidth*this.fZoom, iHeight*this.fZoom).attr(oNode.icon_attr));
|
||||
var oText = this.oPaper.text( xPos, yPos, oNode.label);
|
||||
oText.attr(oNode.text_attr);
|
||||
oText.transform('s'+this.fZoom);
|
||||
var oBB = oText.getBBox();
|
||||
var dy = iHeight/2*this.fZoom + oBB.height/2;
|
||||
oText.remove();
|
||||
oText = this.oPaper.text( xPos, yPos + dy, oNode.label);
|
||||
oText.attr(oNode.text_attr);
|
||||
oText.transform('s'+this.fZoom);
|
||||
oNode.aElements.push(oText);
|
||||
oNode.aElements.push(this.oPaper.rect( xPos - oBB.width/2 -2, yPos - oBB.height/2 + dy, oBB.width +4, oBB.height).attr({fill: '#fff', stroke: '#fff', opacity: 0.9}).toBack());
|
||||
break;
|
||||
}
|
||||
if (oNode.source)
|
||||
{
|
||||
oNode.aElements.push(this.oPaper.circle(xPos, yPos, 1.25*iWidth*this.fZoom / 2).attr({stroke: '#c33', 'stroke-width': 3*this.fZoom }).toBack());
|
||||
}
|
||||
if (oNode.sink)
|
||||
{
|
||||
oNode.aElements.push(this.oPaper.circle(xPos, yPos, 1.25*iWidth*this.fZoom / 2).attr({stroke: '#33c', 'stroke-width': 3*this.fZoom }).toBack());
|
||||
}
|
||||
|
||||
var me = this;
|
||||
for(k in oNode.aElements)
|
||||
{
|
||||
var sNodeId = oNode.id;
|
||||
oNode.aElements[k].drag(function(dx, dy, x, y, event) { me._move(sNodeId, dx, dy, x, y, event); }, function(x, y, event) { me._drag_start(sNodeId, x, y, event); }, function (event) { me._drag_end(sNodeId, event); });
|
||||
}
|
||||
},
|
||||
_move: function(sNodeId, dx, dy, x, y, event)
|
||||
{
|
||||
var origDx = dx / this.fZoom;
|
||||
var origDy = dy / this.fZoom;
|
||||
|
||||
var oNode = this._find_node(sNodeId);
|
||||
oNode.x = oNode.xOrig + origDx;
|
||||
oNode.y = oNode.yOrig + origDy;
|
||||
|
||||
for(k in oNode.aElements)
|
||||
{
|
||||
oNode.aElements[k].transform('t'+(oNode.tx + dx)+', '+(oNode.ty + dy));
|
||||
|
||||
for(j in this.aEdges)
|
||||
{
|
||||
var oEdge = this.aEdges[j];
|
||||
if ((oEdge.source_node_id == sNodeId) || (oEdge.sink_node_id == sNodeId))
|
||||
{
|
||||
var sPath = this._get_edge_path(oEdge);
|
||||
oEdge.aElements[0].attr({path: sPath});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_drag_start: function(sNodeId, x, y, event)
|
||||
{
|
||||
var oNode = this._find_node(sNodeId);
|
||||
oNode.xOrig = oNode.x;
|
||||
oNode.yOrig = oNode.y;
|
||||
|
||||
},
|
||||
_drag_end: function(sNodeId, event)
|
||||
{
|
||||
var oNode = this._find_node(sNodeId);
|
||||
oNode.tx += (oNode.x - oNode.xOrig) * this.fZoom;
|
||||
oNode.ty += (oNode.y - oNode.yOrig) * this.fZoom;
|
||||
oNode.xOrig = oNode.x;
|
||||
oNode.yOrig = oNode.y;
|
||||
},
|
||||
_get_edge_path: function(oEdge)
|
||||
{
|
||||
var oStart = this._find_node(oEdge.source_node_id);
|
||||
var oEnd = this._find_node(oEdge.sink_node_id);
|
||||
var iArrowSize = 5;
|
||||
|
||||
if ((oStart == null) || (oEnd == null)) return '';
|
||||
|
||||
var xStart = Math.round(oStart.x * this.fZoom + this.xOffset);
|
||||
var yStart = Math.round(oStart.y * this.fZoom + this.yOffset);
|
||||
var xEnd = Math.round(oEnd.x * this.fZoom + this.xOffset);
|
||||
var yEnd = Math.round(oEnd.y * this.fZoom + this.yOffset);
|
||||
|
||||
var sPath = Raphael.format('M{0},{1}L{2},{3}', xStart, yStart, xEnd, yEnd);
|
||||
var vx = (xEnd - xStart);
|
||||
var vy = (yEnd - yStart);
|
||||
var l = Math.sqrt(vx*vx+vy*vy);
|
||||
vx = vx / l;
|
||||
vy = vy / l;
|
||||
var ux = -vy;
|
||||
var uy = vx;
|
||||
var lPos = Math.max(l/2, l - 40*this.fZoom);
|
||||
var xArrow = xStart + vx * lPos;
|
||||
var yArrow = yStart + vy * lPos;
|
||||
sPath += Raphael.format('M{0},{1}l{2},{3}M{4},{5}l{6},{7}', xArrow, yArrow, this.fZoom * iArrowSize *(-vx + ux), this.fZoom * iArrowSize *(-vy + uy), xArrow, yArrow, this.fZoom * iArrowSize *(-vx - ux), this.fZoom * iArrowSize *(-vy - uy));
|
||||
return sPath;
|
||||
},
|
||||
_draw_edge: function(oEdge)
|
||||
{
|
||||
var fStrokeSize = Math.max(1, 2 * this.fZoom);
|
||||
var sPath = this._get_edge_path(oEdge);
|
||||
var oAttr = $.extend(oEdge.attr);
|
||||
oAttr['stroke-linecap'] = 'round';
|
||||
oAttr['stroke-width'] = fStrokeSize;
|
||||
oEdge.aElements.push(this.oPaper.path(sPath).attr(oAttr).toBack());
|
||||
},
|
||||
_find_node: function(sId)
|
||||
{
|
||||
for(var k in this.aNodes)
|
||||
{
|
||||
if (this.aNodes[k].id == sId) return this.aNodes[k];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
auto_scale: function()
|
||||
{
|
||||
var fMaxZoom = 1.5;
|
||||
iMargin = 10;
|
||||
xmin = this.options.xmin - iMargin;
|
||||
xmax = this.options.xmax + iMargin;
|
||||
ymin = this.options.ymin - iMargin;
|
||||
ymax = this.options.ymax + iMargin;
|
||||
var xScale = this.element.width() / (xmax - xmin);
|
||||
var yScale = this.element.height() / (ymax - ymin + this.iTextHeight);
|
||||
|
||||
this.fZoom = Math.min(xScale, yScale, fMaxZoom);
|
||||
switch(this.options.align)
|
||||
{
|
||||
case 'left':
|
||||
this.xOffset = -xmin * this.fZoom;
|
||||
break;
|
||||
|
||||
case 'right':
|
||||
this.xOffset = (this.element.width() - (xmax - xmin) * this.fZoom);
|
||||
break;
|
||||
|
||||
case 'center':
|
||||
this.xOffset = (this.element.width() - (xmax - xmin) * this.fZoom) / 2;
|
||||
break;
|
||||
}
|
||||
switch(this.options['vertical-align'])
|
||||
{
|
||||
case 'top':
|
||||
this.yOffset = -ymin * this.fZoom;
|
||||
break;
|
||||
|
||||
case 'bottom':
|
||||
this.yOffset = this.element.height() - (ymax + this.iTextHeight) * this.fZoom;
|
||||
break;
|
||||
|
||||
case 'middle':
|
||||
this.yOffset = (this.element.height() - (ymax - ymin + this.iTextHeight) * this.fZoom) / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
add_node: function(oNode)
|
||||
{
|
||||
oNode.aElements = [];
|
||||
this.aNodes.push(oNode);
|
||||
},
|
||||
add_edge: function(oEdge)
|
||||
{
|
||||
oEdge.aElements = [];
|
||||
this.aEdges.push(oEdge);
|
||||
},
|
||||
_create_toolkit_menu: function()
|
||||
{
|
||||
var sPopupMenuId = 'tk_graph'+this.element.attr('id');
|
||||
var sHtml = '<div class="itop_popup toolkit_menu" style="font-size: 12px;" id="'+sPopupMenuId+'"><ul><li><img src="../images/toolkit_menu.png"><ul>';
|
||||
sHtml += '<li><a href="#" id="'+sPopupMenuId+'_pdf">Export as PDF</a></li>';
|
||||
sHtml += '<li><a href="#" id="'+sPopupMenuId+'_document">Export as document...</a></li>';
|
||||
sHtml += '<li><a href="#" id="'+sPopupMenuId+'_reload">Refresh</a></li>';
|
||||
sHtml += '</ul></li></ul></div>';
|
||||
|
||||
this.element.before(sHtml);
|
||||
$('#'+sPopupMenuId).popupmenu();
|
||||
|
||||
var me = this;
|
||||
$('#'+sPopupMenuId+'_pdf').click(function() { me.export_as_pdf(); });
|
||||
$('#'+sPopupMenuId+'_document').click(function() { me.export_as_document(); });
|
||||
$('#'+sPopupMenuId+'_reload').click(function() { me.reload(); });
|
||||
|
||||
},
|
||||
export_as_pdf: function()
|
||||
{
|
||||
alert('Export as PDF: not yet implemented');
|
||||
},
|
||||
export_as_document: function()
|
||||
{
|
||||
alert('Export as document: not yet implemented');
|
||||
},
|
||||
reload: function()
|
||||
{
|
||||
alert('Reload: not yet implemented');
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user