多页面应用画拓扑图利器-jTopo
前言
jTopo主要应用在多页面web网站上,一款完全基于HTML5 Canvas的关系、拓扑图形化界面开发工具包。
优点是免费而且不依赖其它包,体积小。
参考jtopo官网
入门
要想让官网例子源码运行,需要jquery框架,倒不是jtopo依赖jquery,只是使用了jquery框架的ready事件函数
$(document).ready(function(){
}};
一个HelloWorld例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript" src="./js/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="./js/jtopo-0.4.8-min.js"></script>
<script>
$(document).ready(function(){
var canvas = document.getElementById('canvas');
var stage = new JTopo.Stage(canvas); // 创建一个舞台对象
var scene = new JTopo.Scene(stage); // 创建一个场景对象
scene.background = './img/backgroud.png';
var node = new JTopo.Node("Hello"); // 创建一个节点
node.setLocation(300,200); // 设置节点坐标
scene.add(node); // 放入到场景中
});
</script>
</head>
<body>
<canvas id="canvas" width="1000" height="400"></canvas>
</body>
</html>
其中
var canvas = document.getElementById('canvas');
var stage = new JTopo.Stage(canvas); // 创建一个舞台对象
var scene = new JTopo.Scene(stage); // 创建一个场景对象
scene.background = './img/backgroud.png';
代码基本上就这些,放在首位。scene.background必需指定为图片,不能设置为颜色
。
创建一个结点代码 var node = new JTopo.Node(“Hello”); // 创建一个节点看起来就是这么简单。
运行一个jtopo例子很简单。如上将官网例子代码替换到scripte标签里即可。
可以负责人说的,jtopo比较简单,只要掌握了node和Link类,剩余大部分工作是用js处理逻辑,
api
要初步了解jtopo。有2个缺一不可,结点和连接线。
结点
jtopo结点分如下4种:
JTopo.Node:普通结点
JTopo.TextNode:文本结点
JTopo.LinkNode:超链接结点,类似a标签
JTopo.CircleNode:图形结点
可详参jtopo所有api
连接
jtopo折线分如下4种:
JTopo.Link:简单连线
JTopo.FoldLink:折线
JTopo.FlexionalLink:二次折线
JTopo.CurveLink:曲线
其它
其实这些简单的api官网源码都有,这里不想罗列了,说说jtopo缺点吧。
由于jtopo是在canvas上画的,由数据单向渲染, 组件不能绑定数据,导致拿结点对应数据不方便。换句话说操作数据不友好。比如我们想通过双击不同结点打开不同页面的话就不方便。如果解决呢?
解决数据问题
jtopo没提供好的方式操作数据,我用了一个比较普通的方式,将唯一的数据绑定到node.id上,单击或双击时通过id值查找源数据。
下面是一个例子,有关于我的方法的内容。
以一个例子结束jtopo入门。画一个树型结构拓扑图,双击结点时,打开百度搜索页面搜索这个结点name值。
效果如下
用json提供数据,单向渲染
var json = {name:"刘邦", id: "root",childrens:[{name:"刘肥", id: "liuChangAn",childrens:[{name:"刘章",id:"liuLing",childrens:null},{name:"刘喜",id:"liuYiYing",childrens:[{name:"刘义",id:"liuBai",childrens:null},{name:"刘牛",id:"liuBai",childrens:null}]},{name:"刘延",id:"liuChang",childrens:[{name:"刘顺",id:"liuBai",childrens:null}]}]},{name:"刘恒",id: "liuOuGan",childrens:[{name:"刘启",id:"liuBai",childrens:null},{name:"刘武",id:"liuHei",childrens:null}]}]};
源码如下:
<!DOCTYPE html lang="zh">
<head>
<meta charset="UTF-8">
<style type="text/css">
.outc{
height:110px;
}
.inc
{
background-color:#00FFFF;
width:150px;
height:150px;
overflow: scroll;
}
</style>
<script type="text/javascript" src="./js/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="./js/jtopo-0.4.8-min.js"></script>
<script>
//json数据
var json = {name:"刘邦", id: "root",childrens:[{name:"刘肥", id: "liuChangAn",childrens:[{name:"刘章",id:"liuLing",childrens:null},{name:"刘喜",id:"liuYiYing",childrens:[{name:"刘义",id:"liuBai",childrens:null},{name:"刘牛",id:"liuBai",childrens:null}]},{name:"刘延",id:"liuChang",childrens:[{name:"刘顺",id:"liuBai",childrens:null}]}]},{name:"刘恒",id: "liuOuGan",childrens:[{name:"刘启",id:"liuBai",childrens:null},{name:"刘武",id:"liuHei",childrens:null}]}]};
//根据id查询json里数据
function getJsonDataById(data, id){
var result = null;
console.log("type:" + typeof data + "," + data.constructor + "," + Object.prototype.toString.call(data));
var type = Object.prototype.toString.call(data);
if(type == "[object Object]"){
if(data.id == id)result = data;
else{
if(undefined != data.childrens && data.childrens.length > 0){
result = getJsonDataById(data.childrens, id);
}
}
}else if(type == "[object Array]"){
var n = null;
for(var i=0;i<data.length;i++){
var element = data[i];
result = getJsonDataById(element, id);
if(null != result)break;
}
}
return result;
}
$(document).ready(function(){
var canvas = document.getElementById('canvas');
var stage = new JTopo.Stage(canvas);
var scene = new JTopo.Scene();
stage.add(scene);
scene.background = './img/backgroud.png';
var rootNode;
drawFromDb(json, null);
//画树图
function drawFromDb(data, parentNode){
if(null == data)return;
var node = new JTopo.Node(data.name);
node.id = data.id;
//双击
node.dbclick(function(event){
var se = getJsonDataById(json, this.id);
if(null != se){
window.open("https://www.baidu.com/s?wd=" + se.name + "&rsv_spt=1&rsv_iqid=0xd54ecd980000b116&issp=1&f=8&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=62095104_2_oem_dg&rsv_enter=1&rsv_sug3=3&rsv_sug1=3&rsv_sug7=101");
}
});
if(null == parentNode || undefined == parentNode){
//根结点
node.setImage('./img/1.png');
node.setSize(30, 26);
node.setLocation(360,130);
node.layout = {type: 'tree', width:180, height: 100}
scene.add(node);
rootNode = node;
}else{
//非根结点
node.setImage('./img/2.png');
node.setLocation(scene.width * Math.random(), scene.height * Math.random());
if(undefined != data.childrens && data.childrens.length > 0){
node.layout = {type: 'tree', width:50, height: 100};
}
scene.add(node);
scene.add(new JTopo.Link(parentNode, node));
}
if(undefined != data.childrens && data.childrens.length > 0){
for(var p in data.childrens){
//遍布json时出现了del数据,原因未知,可能我环境问题。视情况删除
if(p == 'del')continue;
console.log("p:" + p)
drawFromDb(data.childrens[p], node);
}
}
}
JTopo.layout.layoutNode(scene, rootNode, true);
});
</script>
</head>
<body>
<h1>刘姓族谱</h1>
<canvas id="canvas" width="910" height="500"></canvas>
</body>
</html>
源码地址
提取码:0pfg