arbor是一个画动态连接图的js库。
效果截图如下:
项目地址:http://arborjs.org/
一个使用它动态扩展的例子:http://nooshu.com/explore/arbor-visual-thesaurus/
文章地址是:http://nooshu.com/visual-thesaurus-using-arbor-js
实际使用中,(2011年11月时)发现有个bug,就是如果只构造一个节点,就会陷入死循环,所以要避免。下面是当时使用的代码。
使用前需要引入包jquery库和
hashmap.js //js实现的hashmap
arbor-graphics.js
arbor.js
arbor-tween.js
//
//解析器
//
var Parseur = function(){
var strip = function(s){ return s.replace(/^[\s\t]+|[\s\t]+$/g,''); }
var recognize = function(s){
// return the first {.*} mapping in the string (or "" if none)
var from = -1,
to = -1,
depth = 0;
$.each(s, function(i, c){
switch (c){
case '{':
if (depth==0 && from==-1) from = i;
depth++;
break;
case '}':
depth--;
if (depth==0 && to==-1) to = i+1;
break;
}
})
return s.substring(from, to);
}
var unpack = function(os){
// process {key1:val1, key2:val2, ...} in a recognized mapping str
if (!os) return {};
var pairs = os.substring(1,os.length-1).split(/\s*,\s*/);
var kv_data = {};
$.each(pairs, function(i, pair){
var kv = pair.split(':');
if (kv[0]===undefined || kv[1]===undefined) return;
var key = strip(kv[0]);
var val = strip(kv.slice(1).join(":")); // put back any colons that are part of the value
if (!isNaN(val)) val = parseFloat(val);
if (val=='true'||val=='false') val = (val=='true');
kv_data[key] = val;
})
// trace(os,kv_data)
return kv_data;
}
var lechs = function(s){
var tokens = [];
var buf = '',
inObj = false,
objBeg = -1,
objEnd = -1;
var flush = function(){
var bufstr = strip(buf);
if (bufstr.length>0) tokens.push({type:"ident", ident:bufstr});
buf = "";
}
s = s.replace(/([ \t]*)?;.*$/,''); // screen out comments
for (var i=0, j=s.length;;){
var c = s[i];
if (c===undefined) break;
if (c=='-'){
if (s[i+1]=='>' || s[i+1]=='-'){
flush();
var edge = s.substr(i,2);
tokens.push({type:"arrow",directed:(edge=='->')});
i+=2;
}else{
buf += c;
i++;
}
}else if (c=='{'){
var objStr = recognize(s.substr(i));
if (objStr.length==0){
buf += c;
i++;
}else{
var style = unpack(objStr);
if (!$.isEmptyObject(style)){
flush();
tokens.push({type:"style", style:style});
}
i+= objStr.length;
}
}else{
buf += c;
i++;
}
if (i>=j){
flush();
break;
}
}
return tokens;
}
var yack = function(statements){
var nodes = {};
var edges = {};
var nodestyle = {};
var edgestyle = {};
$.each(statements, function(i, st){
var types = $.map(st, function(token){
return token.type;
}).join('-');
// trace(st)
if (types.match(/ident-arrow-ident(-style)?/)){
// it's an edge
var edge = { src:st[0].ident, dst:st[2].ident, style:(st[3]&&st[3].style||{}) };
edge.style.directed = st[1].directed;
if (nodes[edge.src]===undefined) nodes[edge.src] = ($.isEmptyObject(nodestyle)) ? -2600 : objcopy(nodestyle);
if (nodes[edge.dst]===undefined) nodes[edge.dst] = ($.isEmptyObject(nodestyle)) ? -2600 : objcopy(nodestyle);
edges[edge.src] = edges[edge.src] || {};
edges[edge.src][edge.dst] = objmerge(edgestyle, edge.style);
}else if (types.match(/ident-arrow|ident(-style)?/)){
// it's a node declaration (or an edge typo but we can still salvage a node name)
var node = st[0].ident;
if (st[1]&&st[1].style){
nodes[node] = objmerge(nodestyle, st[1].style);
}else{
nodes[node] = ($.isEmptyObject(nodestyle)) ? -2600 : objcopy(nodestyle); // use defaults
}
}else if (types=='style'){
// it's a global style declaration for nodes
nodestyle = objmerge(nodestyle, st[0].style);
}else if (types=='arrow-style'){
// it's a global style declaration for edges
edgestyle = objmerge(edgestyle, st[1].style);
}
})
// find any nodes that were brought in via an edge then never styled explicitly.
// they get whatever the final nodestyle was built up to be
$.each(nodes, function(name, data){
if (data===-2600){
nodes[name] = objcopy(nodestyle);
}
})
return {nodes:nodes, edges:edges};
}
var that = {
lechs:lechs,
yack:yack,
parse:function(s){
var lines = s.split('\n');
var statements = [];
$.each(lines, function(i,line){
var tokens = lechs(line);
if (tokens.length>0) statements.push(tokens);
})
return yack(statements);
}
}
return that;
}
//
//
//
//
//渲染
//
var Renderer = function (view) {
var dom = $(view);
var canvas = dom.get(0);
//大小
var cWidth = canvas.width = 600;
var cHeight = canvas.height = 500;
var ctx = canvas.getContext("2d");
var particleSystem = null;
var gfx = arbor.Graphics(canvas);
// helpers for figuring out where to draw arrows (thanks springy.js)
var intersect_line_line = function(p1, p2, p3, p4)
{
var denom = ((p4.y - p3.y)*(p2.x - p1.x) - (p4.x - p3.x)*(p2.y - p1.y));
if (denom === 0) return false // lines are parallel
var ua = ((p4.x - p3.x)*(p1.y - p3.y) - (p4.y - p3.y)*(p1.x - p3.x)) / denom;
var ub = ((p2.x - p1.x)*(p1.y - p3.y) - (p2.y - p1.y)*(p1.x - p3.x)) / denom;
if (ua < 0 || ua > 1 || ub < 0 || ub > 1) return false;
return arbor.Point(p1.x + ua * (p2.x - p1.x), p1.y + ua * (p2.y - p1.y));
}
var intersect_line_box = function(p1, p2, boxTuple)
{
var p3 = {x:boxTuple[0], y:boxTuple[1]},
w = boxTuple[2],
h = boxTuple[3];
var tl = {x: p3.x, y: p3.y};
var tr = {x: p3.x + w, y: p3.y};
var bl = {x: p3.x, y: p3.y + h};
var br = {x: p3.x + w, y: p3.y + h};
return intersect_line_line(p1, p2, tl, tr) ||
intersect_line_line(p1, p2, tr, br) ||
intersect_line_line(p1, p2, br, bl) ||
intersect_line_line(p1, p2, bl, tl) ||
false;
}
var that = {
init:function (system) {
particleSystem = system;
particleSystem.screenSize(cWidth, cHeight);
//particleSystem.screenPadding(20);
//鼠标事件
this.initMouseHandling();
},
resize:function (width, height) {
cWidth = width;
cHeight = height;
particleSystem.screenSize(cWidth, cHeight);
},
redraw:function () {
if (!particleSystem) return;
ctx.clearRect(0,0, canvas.width, canvas.height);
//ctx.fillStyle = "white";
//ctx.fillRect(0, 0, cWidth, cHeight);
var nodeBoxes = {};
particleSystem.eachNode(function(node, pt){
var label = node.data.label||"";
var w = ctx.measureText(""+label).width + 10;
if (!(""+label).match(/^[ \t]*$/)){
pt.x = Math.floor(pt.x);
pt.y = Math.floor(pt.y);
}else{
label = null;
}
// draw a rectangle centered at pt
if (node.data.color) ctx.fillStyle = node.data.color;
// else ctx.fillStyle = "#d0d0d0"
else ctx.fillStyle = "rgba(0,0,0,.2)";
if (node.data.color=='none') ctx.fillStyle = "white";
// ctx.fillRect(pt.x-w/2, pt.y-10, w,20)
if (node.data.shape=='dot'){
gfx.oval(pt.x-w/2, pt.y-w/2, w,w, {fill:ctx.fillStyle});
nodeBoxes[node.name] = [pt.x-w/2, pt.y-w/2, w,w];
}else{
gfx.rect(pt.x-w/2, pt.y-14, w,30, 4, {fill:ctx.fillStyle});
nodeBoxes[node.name] = [pt.x-w/2, pt.y-14, w, 30];
}
// draw the text
if (label){
ctx.font = "13px Verdana";
ctx.textAlign = "center";
ctx.fillStyle = "white";
if (node.data.color=='none') ctx.fillStyle = '#333333';
ctx.fillText(label||"", pt.x, pt.y+4);
///ctx.fillText(label||"", pt.x, pt.y+4);
}
});
ctx.strokeStyle = "#cccccc";
ctx.lineWidth = 2;
ctx.beginPath();
particleSystem.eachEdge(function(edge, pt1, pt2){
// edge: {source:Node, target:Node, length:#, data:{}}
// pt1: {x:#, y:#} source position in screen coords
// pt2: {x:#, y:#} target position in screen coords
var weight = edge.data.weight;
var color = edge.data.color;
// trace(color)
if (!color || (""+color).match(/^[ \t]*$/)) color = null;
// find the start point
var tail = intersect_line_box(pt1, pt2, nodeBoxes[edge.source.name]);
var head = intersect_line_box(tail, pt2, nodeBoxes[edge.target.name]);
ctx.save();
ctx.beginPath();
if (!isNaN(weight)) ctx.lineWidth = weight;
if (color) ctx.strokeStyle = color;
// if (color) trace(color)
ctx.fillStyle = null;
ctx.moveTo(tail.x, tail.y);
ctx.lineTo(head.x, head.y);
ctx.stroke();
ctx.restore();
// draw an arrowhead if this is a -> style edge
if (edge.data.directed){
ctx.save();
// move to the head position of the edge we just drew
var wt = !isNaN(weight) ? parseFloat(weight) : ctx.lineWidth;
var arrowLength = 10 + wt;
var arrowWidth = 6 + wt;
ctx.fillStyle = (color) ? color : ctx.strokeStyle;
ctx.translate(head.x, head.y);
ctx.rotate(Math.atan2(head.y - tail.y, head.x - tail.x));
// delete some of the edge that's already there (so the point isn't hidden)
ctx.clearRect(-arrowLength/2,-wt/2, arrowLength/2,wt);
// draw the chevron
ctx.beginPath();
ctx.moveTo(-arrowLength, arrowWidth);
ctx.lineTo(0, 0);
ctx.lineTo(-arrowLength, -arrowWidth);
ctx.lineTo(-arrowLength * 0.8, -0);
ctx.closePath();
ctx.fill();
ctx.restore();
}
});
},
initMouseHandling:function () {
var _mouseP = null;
var selected = null;
var dragged = null;
var nearest = null;
var oldmass = 1;
var handler = {
moved:function (e) {
if (dragged!=undefined && dragged!=null && dragged.node !== null){
dragged.node.fixed = true;
return false;
}
var pos = $(canvas).offset();
_mouseP = arbor.Point(e.pageX-pos.left, e.pageY-pos.top);
nearest = particleSystem.nearest(_mouseP);
if (nearest!=undefined && nearest!=null && nearest.node !== null){
//selected = (nearest.distance < 50) ? nearest : null;
if(nearest.distance < 50){
dom.addClass('domhover');
nearest.node.fixed = true;
} else {
dom.removeClass('domhover');
}
}
return false;
},
clicked:function (e) {
var pos = $(canvas).offset();
_mouseP = arbor.Point(e.pageX - pos.left, e.pageY - pos.top);
nearest = particleSystem.nearest(_mouseP);
if (nearest!=undefined && nearest!=null && nearest.node !== null){
dragged = selected = (nearest.distance < 50) ? nearest : null;
if(selected){
selected.node.fixed = true;
//显示信息
traceObj.tracemessage(selected.node.name);
}
}
$(canvas).bind("mousemove", handler.dragged);
$(window).bind("mouseup", handler.dropped);
return false;
},
dragged:function (e) {
var pos = $(canvas).offset();
var s = arbor.Point(e.pageX-pos.left, e.pageY-pos.top);
if (dragged!=undefined && dragged!=null && dragged.node!==null){
var p = particleSystem.fromScreen(s);
dragged.node.p = p; //{x:p.x, y:p.y}
}
return false;
},
dropped:function (e) {
if (dragged == null || dragged.node == undefined || dragged.node == null) {
return;
}
if (dragged.node !== null) {
dragged.node.fixed = false;
}
dragged.node.tempMass = 1000;
dragged = null;
selected = null;
$(canvas).unbind("mousemove", handler.dragged);
$(window).unbind("mouseup", handler.dropped);
_mouseP = null;
return false;
}};
// start listening
$(canvas).mousedown(handler.clicked);
$(canvas).mousemove(handler.moved);
}};
return that;
};
//
//
//
//
//追溯操作对象
//
var traceObj = function () {
//结点颜色
var colors = ["red","orange","#922E00","#a7af00", "#FC930A", "#95cde5"];
//文本解析
var parse = Parseur().parse;
var trace = arbor.etc.trace;
var objmerge = arbor.etc.objmerge;
var objcopy = arbor.etc.objcopy;
//追溯数据
var epinfo = new HashMap();; //企业信息
var epcinfo = new HashMap();; //流程信息
var indi = new HashMap();; //指标信息
var draw = new HashMap();; //画图信息
var prev = new Array(); //待请求临时队列
var curfrom = null; //当前查询epc的下家
var curepc = null; //当前查询epc
var stop = 0; //是否停止 0 可以画 1 停止
var isajax = 0; //是否在请求中 0 否 1 是
var callback_ = false; //停止回调
var debug_ = false; //debug回调
var print_ = false; //显示回调
var data_ = null;
//arbor 粒子系统
var sys = null;
return {
init:function () {
sys = arbor.ParticleSystem({
"friction":0.5, //摩擦力,灵活性,当为100%时则固定不动
"stiffness":600, //僵硬,聚拢度,值越大,靠的越近
"repulsion":1000, //排斥力,值越大,目标结点相互离的越远
"gravity":false, //引力,true则都向中间靠拢
"fps":60,
"dt":0.6,
"precision":0.08});
//sys.parameters({stiffness:900, repulsion:2000, gravity:true, dt:0.015})
sys.renderer = Renderer("#viewport");
//sys.renderer.resize(200,200);
sys.screenPadding(5);
//sys.renderer.init(sys);
//src_txt = "114 -> 88\n114 -> 39\n114 -> 67\n116 -> 36\n121 -> 2\n121 -> 35\n121 -> 131\n124 -> 40\n124 -> 113\n131 -> 65\n131 -> 62\n";
//var network = parse(src_txt);
//$.each(network.nodes, function(nname, ndata){
// if (ndata.label===undefined) ndata.label = nname;
//})
//sys.merge(network);
//清理
//traceObj.clear();
//画初始图
//traceObj.initshow();
},
clear:function(){
debug_("clear");
//清空画图
sys.prune(function(node, from, to){return true;});
//初始化容器
epinfo.clear();
epcinfo.clear();
indi.clear();
draw.clear();
for(var i=0;i<prev.length;i++){
prev.pop();
}
},
initshow:function(){
//debug_("initshow start");
sys.addNode("home", {shape:'dot',label:"请输入30位追溯码", alpha:'1', color: colors[0], expanded: true});
sys.addNode('noun', {label:'追溯查询需要时间比较多,请耐心等待', alpha:'1', color: colors[1], expanded: true});
sys.addEdge('home','noun', {directed:1,length:0.75});
sys.addNode('verb', {label:'您随时可以单击停止按钮停止查询', alpha:'1', color: colors[2], expanded: true});
sys.addEdge('home','verb', {directed:1,length:0.75});
//debug_("initshow end");
},
tracerequest:function(){
if(isajax == 1){
return;
}
debug_("prev.length:"+prev.length);
if(stop == 1 || prev.length == 0){
traceObj.tracedraw();
return;
}
var tmp = prev.shift();
//debug_("tmp:"+tmp);
var t = tmp.split("->");
if(t.length==1){
curfrom = null;
curepc = t[0];
}else{
curfrom = t[1];
curepc = t[0];
}
debug_("curepc:"+curepc);
debug_("curfrom:"+curfrom);
//进行查询
var addr = "/food/trace/trace.action?epc="+curepc;
isajax = 1;
$.ajax({
type: "get",
url: addr,
data: "{}",
dataType: "json",
contentType: "application/x-www-form-urlencoded; charset=utf-8",
success:traceObj.tracesuccess,
error:traceObj.traceerror
});
},
tracesuccess:function(data, textStatus){
//debug_("tracesuccess");
if(data==undefined || data==null){
epinfo.put(curepc,null);
epcinfo.put(curepc,null);
indi.put(curepc,null);
draw.put(curepc,curfrom);
traceObj.tracedraw();
return;
}
indi.put(curepc,data.indi);
epinfo.put(curepc,data.epinfo);
epcinfo.put(curepc,data.epcinfo);
draw.put(curepc,curfrom);
var prs = data.prev;
if(prs!=undefined && prs!=null && prs!=""){
var ps = prs.split(',');
for(var i=0;i<ps.length;i++){
prev.push(ps[i]+'->'+curepc);
}
}
traceObj.tracedraw();
},
traceerror:function(data, msg){
epinfo.put(curepc,null);
epcinfo.put(curepc,null);
indi.put(curepc,null);
draw.put(curepc,curfrom);
traceObj.tracedraw();
},
tracedraw:function(){
//debug_("draw:"+data);
isajax = 0;
if(prev.length > 0){
if(stop==0){
return traceObj.tracerequest();
}
}
var cur_ = null; //当前epc
var from_ = null; //cur_指向
var color_ = null; //颜色
var name_ = null; //企业名字
var ep_ = null; //企业对象
var eptmp_ = null; //企业json
var list = null; //所有epc列表
//获取节点
list = draw.keySet();
if(list==undefined || list==null || list.length<1){
sys.addNode("home0", {shape:'dot',label:"没有信息", alpha:'1', color: colors[0], expanded: true});
sys.addNode("home", {label:"请输入30位追溯码", alpha:'1', color: colors[0], expanded: true});
sys.addEdge('home0','home', {directed:1,length:0.75});
sys.addNode('noun', {label:'追溯查询需要时间比较多,请耐心等待', alpha:'1', color: colors[1], expanded: true});
sys.addEdge('home0','noun', {directed:1,length:0.75});
sys.addNode('verb', {label:'您随时可以单击停止按钮停止查询', alpha:'1', color: colors[2], expanded: true});
sys.addEdge('home0','verb', {directed:1,length:0.75});
if(callback_ != null){
callback_();
}
return;
}else if(list.length==1){
cur_ = list[0];
if(cur_==undefined || cur_==null){
return;
}
//企业信息
eptmp_ = epinfo.get(cur_);
ep_ = null;
name_ = cur_;
if(eptmp_==null || eptmp_==undefined || eptmp_==''){
}else{
ep_ = $.parseJSON(eptmp_);
}
if(ep_==undefined || ep_==null){
}else{
if(ep_.name==undefined || ep_.name==null){
}else{
name_ = ep_.name;
}
}
//指向epc
from_ = null;
from_ = draw.get(cur_);
if(from_ == undefined){
from_ = null;
}
//画图
debug_("addNode:"+cur_);
if(from_==null){
sys.addNode(cur_, {label:name_, alpha:'1', color: colors[0], expanded: true});
}else{
sys.addNode(cur_, {label:name_, alpha:'1', color: colors[0], expanded: true});
sys.addEdge(cur_,from_, {label:cur_, directed:1,length:0.75});
}
sys.addNode("home", {shape:'dot', label:"只有这一条信息", alpha:'1', color: colors[3], expanded: true});
sys.addEdge(cur_,"home", {directed:0,length:0.75});
if(callback_ != null){
callback_();
}
return;
}
for(var i=0;i<list.length;i++){
cur_ = list[i];
if(cur_==undefined || cur_==null){
continue;
}
//企业信息
eptmp_ = epinfo.get(cur_);
ep_ = null;
name_ = cur_;
if(eptmp_==null || eptmp_==undefined || eptmp_==''){
}else{
ep_ = $.parseJSON(eptmp_);
}
if(ep_==undefined || ep_==null){
}else{
if(ep_.name==undefined || ep_.name==null){
}else{
name_ = ep_.name;
}
}
//指向epc
from_ = null;
from_ = draw.get(cur_);
if(from_ == undefined){
from_ = null;
}
//颜色
color_ = i%5;
//画图
debug_("addNode:"+cur_);
if(from_==null){
sys.addNode(cur_, {label:name_, alpha:'1', color: colors[color_], expanded: true});
}else{
sys.addNode(cur_, {label:name_, alpha:'1', color: colors[color_], expanded: true});
sys.addEdge(cur_,from_, {label:cur_, directed:1,length:0.75});
}
}
//debug_(cur_+'->'+from_+';'+name_+';');
//if(epcfrom_ == null){
// sys.addNode("home", {fixed:'fixed',shape:'dot',label:"请输入30位追溯码", alpha:'1', color: color[0], expanded: true});
//}
/*
if(from_==null){
sys.addNode('030356901234000109111019014857', {label:'030356901234000109111019014857', alpha:'1', color: colors[color_], expanded: true});
sys.addNode('030356901234000109111019042551', {label:'030356901234000109111019042551', alpha:'1', color: colors[color_], expanded: true});
sys.addEdge('030356901234000109111019042551','030356901234000109111019014857', {directed:1,length:0.75});
sys.addNode('030356901234000310111008092236', {label:'030356901234000310111008092236', alpha:'1', color: colors[color_], expanded: true});
sys.addEdge('030356901234000310111008092236','030356901234000109111019014857', {directed:1,length:0.75});
sys.addNode('030356901234000210111011052277', {label:'030356901234000210111011052277', alpha:'1', color: colors[color_], expanded: true});
sys.addEdge('030356901234000210111011052277','030356901234000109111019014857', {directed:1,length:0.75});
}
*/
//画线
//if(from_!=null){
//sys.addEdge(cur_+'',from_+'', {directed:1,length:0.75});
//debug_("addEdge:"+cur_+"-"+from_);
//}
//
//isajax = 0;
//traceObj.tracerequest();
if(callback_ != null){
callback_();
}
},
tracestart:function(data){
if(isajax == 1){
return;
}
data_ = data;
traceObj.clear();
//setTimeout(traceObj.traceenstart,1500);
traceObj.traceenstart();
},
traceenstart:function(){
stop = 0;
isajax = 0;
prev.push(data_);
traceObj.tracerequest();
},
tracestop:function(){
stop = 1;
},
tracestopcallback:function(call_){
callback_ = call_;
},
tracedebug:function(call_){
debug_ = call_;
},
traceprint:function(call_){
print_ = call_;
},
tracemessage:function(data){
if(data==undefined || data==null){
return;
}
if(print_ == null){
return;
}
var str = null;
var cur_ = data;
//企业信息
str = "<div class=\"title\">企业信息</div>";
var eptmp_ = null;
var ep_ = null;
eptmp_ = epinfo.get(cur_);
if(eptmp_==null || eptmp_==undefined){
}else{
ep_ = $.parseJSON(eptmp_);
}
if(ep_==undefined || ep_==null){
str = str+"<div class=\"info red\">没有企业信息</div>";
}else{
str = str+"<div class=\"info\"><table><tbody>"
+"<tr><td class=\"right\">企业名称</td><td class=\"left\">"+ep_.name
+"</td></tr><tr><td class=\"right\">企业电话</td><td class=\"left\">"+ep_.phone
+"</td></tr><tr><td class=\"right\">企业地址</td><td class=\"left\">"+ep_.address
+"</td></tr><tr><td class=\"right\">邮政编码</td><td class=\"left\">"+ep_.zipcode
+"</td></tr><tr><td class=\"right\">企业传真</td><td class=\"left\">"+ep_.fax
+"</td></tr><tr><td class=\"right\">电子邮箱</td><td class=\"left\">"+ep_.email
+"</td></tr></tbody></table>";
}
//流通角色
str = str+"<div class=\"title\">流通角色</div>";
if(ep_==undefined || ep_==null){
str = str+"<div class=\"info red\">没有流通角色信息</div>";
}else{
str = str+"<div class=\"info\"><table><tbody>"
+"<tr><td class=\"right\">角色名称</td><td class=\"left\">"+ep_.type
+"</td></tr></tbody></table>";
}
//产品信息
str = str+"<div class=\"title\">产品信息</div>";
var epctmp_ = null;
var epc_ = null;
epctmp_ = epcinfo.get(cur_);
if(epctmp_==null || epctmp_==undefined){
}else{
epc_ = $.parseJSON(epctmp_);
}
if(epc_==undefined || epc_==null){
str = str+"<div class=\"info red\">没有产品信息</div>";
}else{
str = str+"<div class=\"info\"><table><tbody>"
+"<tr><td class=\"right\">产品名称</td><td class=\"left\">"+epc_.name
+"</td></tr><tr><td class=\"right\">交易时间</td><td class=\"left\">"+epc_.time
+"</td></tr><tr><td class=\"right\">交易码</td><td></td>"
+"</tr><tr><td colspan=\"2\">"+cur_
+"</td></tr></tbody></table>";
}
//指标信息
str = str+"<div class=\"title\">指标信息</div>";
var inditmp_ = null;
var indi_ = null;
inditmp_ = indi.get(cur_);
if(inditmp_==null || inditmp_==undefined){
}else{
indi_ = $.parseJSON(inditmp_);
}
if(indi_==undefined || indi_==null){
str = str+"<div class=\"info red\">没有指标信息</div>";
}else{
str = str+"<div class=\"info\"><table><tbody><tr><td class=\"center\">名称</td><td class=\"center\">值</td><td class=\"center\">单位</td></tr>";
var itemNames=new Array();
var itemValues=new Array();
var itemUnits=new Array();
for (var item in indi_){
var itmp = item.split("||");
itemNames.push(itmp[0]);
itemUnits.push(itmp[1]);
itemValues.push(indi_[item]);
}
var itemsLength = itemNames.length;
var i=0;
for(i=0;i<itemsLength;i++){
str = str+"<tr><td class=\"center\">"+itemNames[i]
+"</td><td class=\"right\">"+itemValues[i]
+"</td><td class=\"left\">"+itemUnits[i]+"</td></tr>";
}
str = str+"</tbody></table>";
}
print_(str);
}
};
}();
使用前,初始化
traceObj.tracedebug(window.debug_);
traceObj.tracestopcallback(window.stop_);
traceObj.traceprint(window.print_);
traceObj.init();
前面是三个回调函数。
调用traceObj.tracestart(“asfdsf”);发起一次请求。
转载自:http://www.cnblogs.com/afarmer/archive/2012/03/30/2426050.html
另外有参考其他的
web开发可视化工具。