的交互式大巴线路图,塑造基于jQuery的高品质T
分类:前端技术

依附 HTML5 Canvas 的交互式客车线路图

2018/03/14 · HTML5 · Canvas

原稿出处: xhload3d   

 前言

前二日在 echarts 上研究灵感的时候,看见了多数关于地图类似的例证,地图定位等等,可是好像正是未有大巴线路图,就融洽花了有的日子捣鼓出来了这几个交互式大巴线路图的 德姆o,客车线路上的点是在网络随意下载了二个,那篇小说记录自身的有个别获得(终归自身大概个新手)以致代码的达成,希望能够帮到一些爱人。当然,假诺有啥意见的可以间接跟自家说,我们一道沟通才会进步。

分子力(molecular force),又称分子间成效力、范得瓦耳斯力,是指成员间的相互成效。当二分子相距较远时,首要表现为吸重力,这种力珍视根源二个分子被另八个成员随即间连忙转变的电偶极矩所极化而引起的相互成效;当二分子特别周边时,则排斥力成为首要的,那是由于各成员的外围电子云开头重叠而爆发的排挤成效。

基于自家的门类实行景况,首若是多少个关键点:

效果图

图片 1

地图稍微内容有一点多,要全部展现,字显得略微小了,可是不要紧,能够遵从须求加大降低,字体和制图的从头到尾的经过并不会失真,毕竟都以用矢量绘制的~

HT for Web提供了弹力布局(也称之为力导向布局)的职能,即基于节点之间存在互斥力,相互连接的节点间存在重力, 弹力布局运转一段时间后,全体拓扑网络布局会稳步到达未有稳定的平衡动静。这几个功能很有意思,前天大家就将它的吸引力表现出来。

1:扶植静态的树,即三遍性将整体数目加载到顾客端。
2:异步树,即三遍只加载一流或若干级节点,子节点能够异步加载数据。
3:Checkbox树(恐怕是静态树也或然是异步树),用于选取(如选用社团机构,选择数据字典项)等,最佳是能力所能达到帮衬节点级联(这一个是难题)
4:能够继承大数据量,并品质表现不错
5:能够在主流浏览器中运营特出

界素不相识成

底层的 div 是由此 ht.graph.GraphView 组件生成的,然后就足以应用 HT for Web 提供好的法门,调用 canvas 画笔随意绘制就好,先来走访怎么变卦底层 div:

var dm = new ht.DataModel();//数据容器 var gv = new ht.graph.GraphView(dm);//拓扑组件 gv.addToDOM();//将拓扑图组件加多进body中

1
2
3
var dm = new ht.DataModel();//数据容器
var gv = new ht.graph.GraphView(dm);//拓扑组件
gv.addToDOM();//将拓扑图组件添加进body中

addToDOM 函数声称如下:

addToDOM = function(){ var self = this, view = self.getView(), style = view.style; document.body.appendChild(view); //将组件底层div增多到body中 style.left = '0';//暗中同意组件是纯属定位,所以要安装岗位 style.right = '0'; style.top = '0'; style.bottom = '0'; window.addEventListener('resize', function () { self.iv(); }, false); //窗口变化事件 }

1
2
3
4
5
6
7
8
9
10
11
addToDOM = function(){  
    var self = this,
        view = self.getView(),  
        style = view.style;
    document.body.appendChild(view); //将组件底层div添加到body中          
    style.left = '0';//默认组件是绝对定位,所以要设置位置
    style.right = '0';
    style.top = '0';
    style.bottom = '0';      
    window.addEventListener('resize', function () { self.iv(); }, false); //窗口变化事件          
}

今昔作者就能够在此个 div 上乱涂乱画了~首先本人收获下载好的地铁线路图上的点,笔者将它们放在 subway.js 中,那个 js 文件全都以下载的剧情,我未有做任何的改动,首假若将这个点依据线路来分分配增添到数组中,举个例子:

mark_Point13 = [];//线路 数组内包括线路的起源和顶峰坐标以至那条路径的名目 t_Point13 = [];//换到站点 数组内满含线路中的换乘站点坐标以致换到站点名称 n_Point13 = [];//小站点 数组内包含线路中的小站点坐标以至小站点名称 mark_Point13.push({ name: '十三号线', value: [113.4973,23.1095]}); mark_Point13.push({ name: '十三号线', value: [113.4155,23.1080]}); t_Point13.push({ name: '鱼珠', value: [113.41548,23.10547]}); n_Point13.push({ name: '裕丰围', value: [113.41548,23.10004]});

1
2
3
4
5
6
7
mark_Point13 = [];//线路 数组内包含线路的起点和终点坐标以及这条线路的名称
t_Point13 = [];//换成站点 数组内包含线路中的换乘站点坐标以及换成站点名称
n_Point13 = [];//小站点 数组内包含线路中的小站点坐标以及小站点名称
mark_Point13.push({ name: '十三号线', value: [113.4973,23.1095]});
mark_Point13.push({ name: '十三号线', value: [113.4155,23.1080]});
t_Point13.push({ name: '鱼珠', value: [113.41548,23.10547]});
n_Point13.push({ name: '裕丰围', value: [113.41548,23.10004]});

接下去来形容地铁线路,笔者证明了多个数组 lineNum,用来装 js 中享有的客车线路的编号,以至三个 color 数组,用来装全体的大巴线的颜色,这几个颜色的 index 与 lineNum 中大巴线编号的 index 是逐条对应的:

var lineNum = ['1', '2', '3', '30', '4', '5', '6', '7', '8', '9', '13', '14', '32', '18', '21', '22', '60', '68']; var color = ['#f1cd44', '#0060a1', '#ed9b4f', '#ed9b4f', '#007e3a', '#cb0447', '#7a1a57', '#18472c', '#008193', '#83c39e', '#8a8c29', '#82352b', '#82352b', '#09a1e0', '#8a8c29', '#82352b', '#b6d300', '#09a1e0'];

1
2
var lineNum = ['1', '2', '3', '30', '4', '5', '6', '7', '8', '9', '13', '14', '32', '18', '21', '22', '60', '68'];
var color = ['#f1cd44', '#0060a1', '#ed9b4f', '#ed9b4f', '#007e3a', '#cb0447', '#7a1a57', '#18472c', '#008193', '#83c39e', '#8a8c29', '#82352b', '#82352b', '#09a1e0', '#8a8c29', '#82352b', '#b6d300', '#09a1e0'];

接着遍历 lineNum,将 lineNum 中的元素和颜料传到 createLine 函数中,依照那五个参数来绘制地铁线路以至配色,毕竟 js 文件中的命有名的模特式也会有规律的,哪一条路径,则命名后边必然会加上对应的数字,所以大家只须求将字符串与这一个号码结合就能够获得js 中对应的数组了:

let lineName = 'Line' num; let line = window[lineName];

1
2
let lineName = 'Line' num;
let line = window[lineName];

createLine 的概念也很简单,笔者的代码设置了众多的体裁,所以看起来有一些多。创立三个ht.Polyline 管线,我们可以通过 polyline.addPoint() 函数向这些变量中增加具体的点,通过 setSegments 能够设置点的连日情势。

function createLine(num, color) {//绘制地图线 var polyline = new ht.Polyline();//多边形 管线 polyline.setTag(num);//设置节点tag标签,作为独一标示 if(num === '68') polyline.setToolTip('A P M');//设置提醒音讯 else if(num === '60') polyline.setToolTip('G F'); else polyline.setToolTip('Line' num); if(color) { polyline.s({//s 为 setStyle 的简写,设置样式 'shape.border.width': 0.4,//设置多边形的边框宽度 'shape.border.color': color,//设置多边形的边框颜色 'select.width': 0.2,//设置选中节点的边框宽度 'select.color': color//设置选中节点的边框颜色 }); } let lineName = 'Line' num; let line = window[lineName]; for(let i = 0; i < line.length; i ) { for(let j = 0; j < line[i].coords.length; j ) { polyline.addPoint({x: line[i].coords[j][0]*300, y: -line[i].coords[j][1]*300}); if(num === '68'){//APM线(有两条,可是点是在同二个数组中的) if(i === 0 && j === 0) { polyline.setSegments([1]); } else if(i === 1 && j === 0) { polyline.getSegments().push(1); } else { polyline.getSegments().push(2); } } } } polyline.setLayer('0');//将线设置在下层,点设置在上层“top” dm.add(polyline);//将管线加多进数据容器中积攒,不然那些管线属于“游离”状态,是不博览会示在拓扑图上的 return polyline; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
function createLine(num, color) {//绘制地图线
    var polyline = new ht.Polyline();//多边形 管线
    polyline.setTag(num);//设置节点tag标签,作为唯一标示
    
    if(num === '68') polyline.setToolTip('A P M');//设置提示信息
    else if(num === '60') polyline.setToolTip('G F');
    else polyline.setToolTip('Line' num);
 
    if(color) {
        polyline.s({//s 为 setStyle 的简写,设置样式
            'shape.border.width': 0.4,//设置多边形的边框宽度
            'shape.border.color': color,//设置多边形的边框颜色
            'select.width': 0.2,//设置选中节点的边框宽度
            'select.color': color//设置选中节点的边框颜色
        });
    }
 
    let lineName = 'Line' num;
    let line = window[lineName];
    for(let i = 0; i < line.length; i ) {
        for(let j = 0; j < line[i].coords.length; j ) {
            polyline.addPoint({x: line[i].coords[j][0]*300, y: -line[i].coords[j][1]*300});
            if(num === '68'){//APM线(有两条,但是点是在同一个数组中的)
                if(i === 0 && j === 0) {
                    polyline.setSegments([1]);
                }
                else if(i === 1 && j === 0) {
                    polyline.getSegments().push(1);
                }
                else {
                    polyline.getSegments().push(2);
                }
            }    
        }
    }
 
    polyline.setLayer('0');//将线设置在下层,点设置在上层“top”
    dm.add(polyline);//将管线添加进数据容器中储存,不然这个管线属于“游离”状态,是不会显示在拓扑图上的
    return polyline;
}

地方代码中增加大巴线上的点有分为二种境况,是因为 js 中设置线的时候 Line68 有三个“跳跃”点的情景,所以大家必得“跳跃”过去,篇幅有限 Line68 数组具体的评释自行看 subway.js。

那边说多美滋些,假若用的是 addPoint 函数,不设置 segments 时,私下认可将增多进的点用直线连接,segments 的定义如下:

  • 1: moveTo,占用 1 个点消息,代表多个新路线的起源
  • 2: lineTo,占用 1 个点信息,代表从上次最终点连接到该点
  • 3: quadraticCurveTo,占用 2 个点音讯,第叁个点作为曲线调控点,第4个点作为曲线甘休点
  • 4: bezierCurveTo,占用 3 个点音信,第一和第贰个点作为曲线调节点,第多少个点作为曲线截至点
  • 5: closePath,不占用点音信,代表本次路线绘制截止,并关闭到路径的起头点

故此我们要做“跳跃”的一言一动设置 segments 为 1 就能够。

末段绘制那个地铁线上的点,这么些局地 subway.js 中也分离出来了,命名以“mark_Point”、“t_Point”以及“n_Point”开首,作者在后边js 的突显部分有对那些数组实行说明,大家动动中指划上去探访。

大家在这里些点的地方增加 ht.Node 节点,当节点一增加进 dm 数据容器中时,就可以在拓扑图上显得,当然,前提是以此拓扑图组件 gv 设置的多寡容器是其一 dm。篇幅有限,增加大巴线上的点的代码部分自身只显示丰硕“换乘站点”的点:

var tName = 't_Point' num; var tP = window[tName];//大站点 if(tP) {//有些线路未有“换乘站点” for(let i = 0; i < tP.length; i ) { let node = createNode(tP[i].name, tP[i].value, color[index]);//在得到的线路上的点的坐标地点增加节点 node.s({//设置节点的体裁style 'label.scale': 0.05,//文本缩放,可避防止浏览器限制的细小字号难点 'label.font': 'bold 12px arial, sans-serif'//设置文本的font }); node.setSize(0.6, 0.6);//设置节点大小。由于js中每一个点期间的偏移量太小,所以小编不得不把节点设置小片段 node.setImage('images/旋转箭头.json');//设置节点的图纸 node.a('alarmColor1', 'rgb(150, 150, 150)');//attr属性,能够在这里中间安装任何的事物,alarmColor1是在上边安装的image的json中绑定的品质,具体参看 HT for Web 矢量手册() node.a('alarmColor2', 'rgb(150, 150, 150)');//同上 node.a('tpNode', true);//这几个性格设置只是为着用来差距“换乘站点”和“小站点”的,前边会用上 } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var tName = 't_Point' num;
var tP = window[tName];//大站点
if(tP) {//有些线路没有“换乘站点”
    for(let i = 0; i < tP.length; i ) {
        let node = createNode(tP[i].name, tP[i].value, color[index]);//在获取的线路上的点的坐标位置添加节点
        node.s({//设置节点的样式style
            'label.scale': 0.05,//文本缩放,可以避免浏览器限制的最小字号问题
            'label.font': 'bold 12px arial, sans-serif'//设置文本的font
        });
        node.setSize(0.6, 0.6);//设置节点大小。由于js中每个点之间的偏移量太小,所以我不得不把节点设置小一些
        node.setImage('images/旋转箭头.json');//设置节点的图片
        node.a('alarmColor1', 'rgb(150, 150, 150)');//attr属性,可以在这里面设置任何的东西,alarmColor1是在上面设置的image的json中绑定的属性,具体参看 HT for Web 矢量手册(http://www.hightopo.com/guide/guide/core/vector/ht-vector-guide.html#ref_binding)
        node.a('alarmColor2', 'rgb(150, 150, 150)');//同上
        node.a('tpNode', true);//这个属性设置只是为了用来区分“换乘站点”和“小站点”的,后面会用上
    }
}

有着的大巴线路乃至站点都加上达成。不过!你大概会看不见自个儿绘制的图,因为他们太小了,今年可以设置 graphView 拓扑组件上的 fitContent 函数,大家顺便将拓扑图上的具备东西不足移动也设置一下:

gv.fitContent(false, 0.00001);//自适应大小,参数1为是不是动画,参数2为gv与边框的padding值 gv.setMovableFunc(function(){ return false;//设置gv上的节点不可移动 });

1
2
3
4
gv.fitContent(false, 0.00001);//自适应大小,参数1为是否动画,参数2为gv与边框的padding值
gv.setMovableFunc(function(){
    return false;//设置gv上的节点不可移动
});

那下你的大巴线路图就足以显得啦~接下来看看互相。

本例地址:

那笔者要创制的TreeView正是为了贯彻那个5个重大目的的。

交互

第一是鼠标移动事件,鼠标滑过具体路径时,线路会变粗,悬停一会儿仍是可以够看到那条路径的编号;当鼠标移动到“换乘站点”或“小站点”,站点对应的Logo都会变大並且变色,字体也会变大,鼠标移开Logo变回原本的水彩而且字体变小。不相同点在于鼠标移动到“换乘站点”时,“换乘站点”会旋转。

图片 2

鼠标滑动事件,作者直接基于 gv 的底层 div 实行的 mousemove 事件,通过 ht 封装的 getDataAt 函数字传送入事件 event 参数,获取事件下相应的节点,然后就能够轻便操作节点了:

gv.getView().addEventListener('mousemove', function(e) { var data = gv.getDataAt(e);//传入逻辑坐标点恐怕交互event事件参数,重临当前点下的图元 if(name) { originNode(name);//不管何时都要让节点保持原本的大小 } if (data instanceof ht.Polyline) {//剖断事件节点的类型 dm.sm().ss(data);//选中“管道” name = ''; clearInterval(interval); } else if (data instanceof ht.Node) { if(data.getTag() !== name && data.a('tpNode')) {//若不是同叁个节点,而且mousemove的事件指标为ht.Node类型,那么设置节点的团团转 interval = setInterval(function() { data.setRotation(data.getRotation()

  • Math.PI/16); //在本人旋转的根底上再旋转 }, 100); } if(data.a('npNode')) {//如果鼠标移到“小站点”也要停下动画 clearInterval(interval); } expandNode(data, name);////自定义的拓展节点函数,相比较便于,笔者不粘代码了,能够去 查看 dm.sm().ss(data);//设置选中节点 name = data.getTag();//作为“上一个节点”的囤积变量,能够经过那些值来获取节点 } else {//其余任何情状则不选中任何内容还要解决“换乘站点”上的卡通 dm.sm().ss(null); name = ''; clearInterval(interval); } });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
gv.getView().addEventListener('mousemove', function(e) {
    var data = gv.getDataAt(e);//传入逻辑坐标点或者交互event事件参数,返回当前点下的图元
    if(name) {
        originNode(name);//不管什么时候都要让节点保持原来的大小
    }
 
    if (data instanceof ht.Polyline) {//判断事件节点的类型
        dm.sm().ss(data);//选中“管道”
        name = '';
        clearInterval(interval);
    }
    else if (data instanceof ht.Node) {
        if(data.getTag() !== name && data.a('tpNode')) {//若不是同一个节点,并且mousemove的事件对象为ht.Node类型,那么设置节点的旋转
            interval = setInterval(function() {
                data.setRotation(data.getRotation() - Math.PI/16); //在自身旋转的基础上再旋转
            }, 100);
        }
        if(data.a('npNode')) {//如果鼠标移到“小站点”也要停止动画
            clearInterval(interval);
        }
        expandNode(data, name);////自定义的放大节点函数,比较容易,我不粘代码了,可以去http://hightopo.com/   查看
        dm.sm().ss(data);//设置选中节点
        name = data.getTag();//作为“上一个节点”的存储变量,可以通过这个值来获取节点
    }
    else {//其他任何情况则不选中任何内容并且清除“换乘站点”上的动画
        dm.sm().ss(null);
        name = '';
        clearInterval(interval);
    }
});

鼠标悬停在大巴线路上时显示“具体路径新闻”,小编是经过安装 tooltip 来造成的(注意:要开发 gv 的 tooltip 按钮):

gv.enableToolTip();//张开 tooltip 的按钮 if(num === '68') polyline.setToolTip('A P M');//设置提示新闻 else if(num === '60') polyline.setToolTip('G F'); else polyline.setToolTip('Line' num);

1
2
3
4
gv.enableToolTip();//打开 tooltip 的开关
if(num === '68') polyline.setToolTip('A P M');//设置提示信息
else if(num === '60') polyline.setToolTip('G F');
else polyline.setToolTip('Line' num);

接下来自身利用右下角的 form 表单,单击表单上的实际路径,恐怕双击拓扑图上放肆叁个“站点”只怕线路,则拓扑图会自适应到对应的局地,将被双击的片段呈现到拓扑图的中心。

图片 3

form 表单的宣示部分自身就像还未曾表明。。。就是经过 new 三个ht.widget.FomePane 类成立多少个 form 表单组件,通过 form.getView() 获取表单组件的尾巴部分 div,将以此 div 摆放在 body 右下角,然后通过 addRow 函数向 form 表单中增多一行的表单项,可以在此行中丰裕大肆多个项,通过 addRow 函数的第1个参数(二个数组),对增多进的表单项举行小幅度的设置,通过第多个参数设置那行的高度:

function createForm() {//创立右下角的form表单 var form = new ht.widget.FormPane(); form.setWidth(200);//设置表单宽度 form.setHeight(416);//设置表单中度 let view = form.getView(); document.body.appendChild(view);//将表单加多进body中 view.style.zIndex = 1000; view.style.bottom = '10px';//ht组件大致都设置相对路线view.style.right = '10px'; view.style.background = 'rgba(211, 211, 211, 0.8)'; names.forEach(function(nameString) { form.addRow([//向表单中增多行 {//这一行中的第三个表单项 button: {//向表单中加多button开关 icon: 'images/Line' nameString.value '.json',//设置按键的Logo background: '',//设置开关的背景 borderColor: '',//设置按键的边框颜色 clickable: false//设置开关不可点击 } }, {//第一个表单项 button: { label: nameString.name, labelFont: 'bold 14px arial, sans-serif', labelColor: '#fff', background: '', borderColor: '', onClicked: function() {//按键点击回调事件 gv.sm().ss(dm.getDataByTag(nameString.value));//设置选中按下的按键对应的路径gv.fitData(gv.sm().ld(), true, 5);//将当选的大巴线路展现在拓扑图的核心 } } } ], [0.1, 0.2], 23);//第三个参数是设置第一参数中的数组的小幅,小于1是比例,大于1是实际上增长幅度。第四个参数是该行的万丈 }); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function createForm() {//创建右下角的form表单
    var form = new ht.widget.FormPane();
    form.setWidth(200);//设置表单宽度
    form.setHeight(416);//设置表单高度
    let view = form.getView();
    document.body.appendChild(view);//将表单添加进body中
    view.style.zIndex = 1000;
    view.style.bottom = '10px';//ht组件几乎都设置绝对路径
    view.style.right = '10px';
    view.style.background = 'rgba(211, 211, 211, 0.8)';
 
    names.forEach(function(nameString) {
        form.addRow([//向表单中添加行
            {//这一行中的第一个表单项
                button: {//向表单中添加button按钮
                    icon: 'images/Line' nameString.value '.json',//设置按钮的图标
                    background: '',//设置按钮的背景
                    borderColor: '',//设置按钮的边框颜色
                    clickable: false//设置按钮不可点击
                }
            },
            {//第二个表单项
                button: {
                    label: nameString.name,
                    labelFont: 'bold 14px arial, sans-serif',
                    labelColor: '#fff',
                    background: '',
                    borderColor: '',
                    onClicked: function() {//按钮点击回调事件
                        gv.sm().ss(dm.getDataByTag(nameString.value));//设置选中按下的按钮对应的线路
                        gv.fitData(gv.sm().ld(), true, 5);//将选中的地铁线路显示在拓扑图的中央
                    }
                }
            }
        ], [0.1, 0.2], 23);//第二个参数是设置第一参数中的数组的宽度,小于1是比例,大于1是实际宽度。第三个参数是该行的高度
    });
}

单击“站点”显示粉红标记,双击节点自适应放置到拓扑图宗旨以至双击空白处将革命注脚掩盖的从头到尾的经过都是由此对拓扑组件 gv 的事件监听来决定的,极其清晰易懂,代码如下:

var node = createRedLight();//成立二个新的节点,显示为“红灯”的体裁 gv.mi(function(e) {//ht 中拓扑组件中的事件监听 if(e.kind === 'clickData' && (e.data.a('tpNode') || e.data.a('npNode'))) {//e.kind获取当前风浪类型,e.data获取当前事件下的节点 node.s('2d.visible', true);//设置node节点可见node.setPosition(e.data.getPosition().x, e.data.getPosition().y);//设置node的坐标为前段时间事件下节点的岗位 } else if(e.kind === 'doubleClickData') {//双击节点 gv.fitData(e.data, false, 10);//将事件下的节点自适应到拓扑图的核心,参数1为自适应的节点,参数2为是或不是动画,参数3为gv与边框的padding } else if(e.kind === 'doubleClickBackground') {//双击空白处 node.s('2d.visible', false);//设置node节点不可以知道 查看 HT for Web 样式手册( } });

1
2
3
4
5
6
7
8
9
10
11
12
13
var node = createRedLight();//创建一个新的节点,显示为“红灯”的样式
gv.mi(function(e) {//ht 中拓扑组件中的事件监听
    if(e.kind === 'clickData' && (e.data.a('tpNode') || e.data.a('npNode'))) {//e.kind获取当前事件类型,e.data获取当前事件下的节点
        node.s('2d.visible', true);//设置node节点可见
        node.setPosition(e.data.getPosition().x, e.data.getPosition().y);//设置node的坐标为当前事件下节点的位置
    }
    else if(e.kind === 'doubleClickData') {//双击节点
        gv.fitData(e.data, false, 10);//将事件下的节点自适应到拓扑图的中央,参数1为自适应的节点,参数2为是否动画,参数3为gv与边框的padding
    }
    else if(e.kind === 'doubleClickBackground') {//双击空白处
        node.s('2d.visible', false);//设置node节点不可见 查看 HT for Web 样式手册(http://www.hightopo.com/guide/guide/core/theme/ht-theme-guide.html#ref_style)
    }
});

注意 s(style) 和 a(attr) 定义是如此的,s 是 ht 预订义的局地体制属性,而 a 是大家顾客来源定义的习性,常常是透过调用字符串来调用结果的,这么些字符串对应的能够是常量也足以是函数,照旧很灵敏的。

说起底还做了多个纤维的有的,选中“站点”,则该“站点”的上边会呈现一个革命的会“呼吸”的用来注脚当前选中的“站点”。

图片 4

“呼吸”的一部分是采取 ht 的 setAnimation 函数来变成的,在用那么些函数在此以前要先开采数据容器的动画片按钮,然后设置动画:

dm.enableAnimation();//张开数据容器的动画按钮 function createRedLight() { var node = new ht.Node(); node.setImage('images/红灯.json');//设置节点的图样 node.setSize(1, 1);//设置节点的轻重 node.setLayer('firstTop');//设置节点展现在gv的最上层 node.s('2d.visible', false);//节点不可以见到 node.s('select.width', 0);//节点选中时的边框为0,不可以知道 node.s('2d.selectable', false);//设置那个本性,则节点不可选中 node.setAnimation({//设置动画 具体参见 HT for Web 动画手册( expandWidth: { property: "width",//设置那本性情,并且未安装 accessType,则默许通过 setWidth/getWidth 来安装和猎取属性。这里的 width 和上边包车型客车 height 都以透过前边设置的 size 获得的 from: 0.5, //动画起头时的属性值 to: 1,//动画甘休时的习性值 next: "collapseWidth"//字符串类型,钦命当前卡通实现将来,要实施的下个卡通,可将多个卡通融合}, collapseWidth: { property: "width", from: 1, to: 0.5, next: "expandWidth" }, expandHeight: { property: "height", from: 0.5, to: 1, next: "collapseHeight" }, collapseHeight: { property: "height", from: 1, to: 0.5, next: "expandHeight" }, start: ["expandWidth", "expandHeight"]//数组,用于钦定要开动的一个或三个动画 }); dm.add(node); return node; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
dm.enableAnimation();//打开数据容器的动画开关
function createRedLight() {
    var node = new ht.Node();
    node.setImage('images/红灯.json');//设置节点的图片
    node.setSize(1, 1);//设置节点的大小
    node.setLayer('firstTop');//设置节点显示在gv的最上层
    node.s('2d.visible', false);//节点不可见
    node.s('select.width', 0);//节点选中时的边框为0,不可见
    node.s('2d.selectable', false);//设置这个属性,则节点不可选中
 
    node.setAnimation({//设置动画 具体参见 HT for Web 动画手册(http://www.hightopo.com/guide/guide/plugin/animation/ht-animation-guide.html)
        expandWidth: {
            property: "width",//设置这个属性,并且未设置 accessType,则默认通过 setWidth/getWidth 来设置和获取属性。这里的 width 和下面的 height 都是通过前面设置的 size 得到的
            from: 0.5, //动画开始时的属性值
            to: 1,//动画结束时的属性值
            next: "collapseWidth"//字符串类型,指定当前动画完成之后,要执行的下个动画,可将多个动画融合
        },
        collapseWidth: {
            property: "width",
            from: 1,
            to: 0.5,
            next: "expandWidth"
        },
        expandHeight: {
            property: "height",
            from: 0.5,
            to: 1,
            next: "collapseHeight"
        },
        collapseHeight: {
            property: "height",
            from: 1,
            to: 0.5,
            next: "expandHeight"
        },
        start: ["expandWidth", "expandHeight"]//数组,用于指定要启动的一个或多个动画
    });
    dm.add(node);
    return node;
}

方方面面代码停止!

图片 5

先来看下效果图

总结

以此 德姆o 花了自身二日时间成功,总感到有一些不甘心啊,然则有的时候思维又转但是弯来,开销了不菲的时刻,可是总的来讲收获依旧广大的,作者原先一直认为假若经过 getPoints().push 来向多边形中加多点就能够了,求助了大神之后,开采原本这么些办法不但绕弯路並且还有大概会合世五光十色的主题材料,例如getPoints 以前,应当要在多方面形中已经有 points 才方可,不过在多数意况下,伊始化的 points 并不好设置,并且会招致代码很麻烦,直接通过 addPoint 方法,直接将点加多进多边形变量中,况且还有大概会私下认可将点通过直线的艺术连接,也不用设置 segments,多喜人的三个函数。

再有正是因为 ht 私下认可缩放大小是 20,而自己那个 德姆o 的间距又一点都不大,导致缩放到最大客车线路图彰显也异常的小,所以本身在 htconfig 中更换了 ht 的暗许 zoom马克斯 属性,记住,更动这一个值一定要在具有的 ht 调用以前,因为在 htconfig 中安装的值在后边定义都是不足更换的。

由此可见,那二日自身的头脑细胞死了广大,也再也生长了无数,人都以在不断进步的嘛~

1 赞 1 收藏 评论

图片 6

利用弹力布局功效须要在引进ht.js`核心库之后,再引入一个ht-forcelayout.js `的弹力布局插件库,因为还用到了 form 表单,所以要引进 ht-form.js 的表单插件库:

图片 7

<script src="../../guide/lib/core/ht.js"></script>
<script src="../../guide/lib/plugin/ht-forcelayout.js"></script>
<script src="../../guide/lib/plugin/ht-form.js"></script>

上海教室是中华行政区域的数据树,总共得节点是3500 。

ht.layout.Force3dLayout类提供 3D弹力布局,构造函数可传入 DataModel和 Graph3dView二种参数。 暗许仅对未选中图元实行布局,倘使构造函数参数为 Graph3dView时,则视图组件的 isMovable和 isVisible函数将影响图元是不是可布局, 图元 style上的 layoutable脾气也可设为 false阻挡图元参预布局。

那正是说大家要开工了;

介绍完 HT 封装的弹力布局的背景之后,接下去正是扶持你们也能自在地落到实处那一个功用。

1:第一个规定的节点Dom结构(即用哪些的HTML来创设节点)

先是大家定义八个颜料数组变量,存款和储蓄各种弹力球的水彩,还定义了三个自由函数,用来生成数随机的数组中的颜色:

  • 比较土的是table套table的(样式上好调节,不过大数据量,和档次较深的树,这种组织自然顶不住的)
  • 还应该有一种是比较至极的UL套LI的措施,那是今后广大书选用的不二秘诀如Jquery.treeview正是利用的这种格式,好处相比较分明正是构造轻巧,
    况兼在不协助Js的浏览器上,一样也能表现出树的造型(这种情景实际上笔者能够忽略),可是Jquery.treeview的节点在IE下,特别是IE6下不能够被内部因素撑开,(IE7,8当达到自然深度时不能撑开),请离奇的情状(作者揣测是因为运用padding来做缩进,margin-left:负值来调节图标地方有关,不过修改起来难度也很大),在此种情状下书会变形(Jquery.treeview)就有这种主题素材,只可以通过设置节点的width来减轻。
var colorList = ['#FFAFA4', '#B887C5', '#B9EA9C', '#CFD9E7', '#4590B8', '#FF9C30'], 
    colorLen = colorList.length;
var randomColor = function() {
    var ran = Math.random() * colorLen;
    return colorList[Math.floor(ran)];//随机6种颜色
};

图片 8

继之创设弹力球,轻便生成二个3D 节点,通过安装这么些节点的 style 样式属性来调整节点的展现形式,个中将“shape3d”设置为“sphere”就能够将 ht.Node 六面体产生 3D 球人体模型型,再安装“shape3d”属性为日前定义的即兴颜色,s3 是 HT 封装的安装 3D 节点大小的 setSize3d 函数的简写,最后将这一个节点增多进数据模型 dataModel 中:

JQuery.treeview的节点结构

var createNode = function(dm) {//创建node节点 圆
    var node = new ht.Node();
    node.s({//设置样式为 setStyle 的简写
        'shape3d': 'sphere',
        'shape3d.color': randomColor()//设置随机颜色
    });
    node.s3(40, 40, 40);
    dm.add(node);
    return node;
};

图片 9

当今效力图上出现的还恐怕有各类弹力球之间的连线,那几个连线大家一看就以为很反常,也是经过组织三个三个节点,这几个节点是因而 HT for Web 建立模型手册 setShape3dModel函数自定义的 ht.Default.createRingModel 依据 xy 平面包车型地铁曲线,环绕一周造成的 3D 环形模型,将其取名字为‘custom’:

Jquery.TreeView  IE6 下 张开第三级即出现错位

ht.Default.setShape3dModel(//创建模型 根据xy平面的曲线,环绕一周形成3D模型。
    'custom', ht.Default.createRingModel( [0.5, 0.5, -0.2, 0, 0.5, -0.5], [1, 3] )
);

图片 10 IE8下进展到第5级

HT 将客户自定义的性质和 HT 暗许的习性调用方法分为 node.a 和 node.s 那样就能够将二者有效地区分开来(具体参照 HT for Web 入门手册 style 章节),大家在成立管线的时候就用了这种艺术:

  • 还会有点是div套table的法子,CSDN的领航树就是这种,是种折中的方法(节点也不算太复杂,而且CSS也正如好写),如下图所示
    图片 11
var updatePipeline = function(edge) {//重新设置edge的样式
    var pipeline = edge.a('pipeline');
    pipeline.s3(1, 1, 1);//设置大小
    pipeline.p3(0, 0, 0);//设置坐标

    var node1 = edge.getSourceAgent(),//获取图形上连接的起始节点
    node2 = edge.getTargetAgent();//获取图形上连接的目标节点
    pipeline.s('mat', createMatrix(node1.p3(), node2.p3(), 20));//3d整体图形矩阵变化
};

 

最隐私的是什么能做出让几个节点“若即若离”的效益?

 

大家掌握,矩阵能描述大肆线性别变化换。线性别变化换保留了直线和平行线,线性别变化换保留直线的还要,别的的几何性质如长度、角度、面积和体量或许被撤换退换了。简单的讲,线性别变化换可能“拉伸”坐标系,但不会“盘曲”或“卷折”坐标系。这么些函数首假使将大家的连接线在拖动掸力球后被拖拉的一而再线的展开叁个“变化矩阵”的操作,变化矩阵也是 HT 封装的 ht.Default.createMatrix 函数,通过将节点的 style 属性 mat 设置为八个自定义的函数,便是将这一个节点的坐标乘上在“mat”属性对应的值,也便是说借使当前以此管线的转动角为 [Math.PI/6, 0, 0],假如咱们在 createMatrix 函数中设置 r3 为 [Math.PI/3, 0, 0],那么那些节点会旋转 90 度。相当的轻易地开创下转变矩阵:

 

var createMatrix = function(p1, p2, width) {//createMatrix(array, matrix)将一组JSON描述的缩放、移动和旋转等操作转换成对应的变化矩阵
    var vec = [p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]],
        dist = ht.Default.getDistance(p1, p2);//获取两点之间距离,或向量长度
    return ht.Default.createMatrix({
        s3: [width, dist, width],
    r3: [Math.PI/2 - Math.asin(vec[1]/dist), Math.atan2(vec[0], vec[2]), 0],
    rotationMode: 'xyz',
    t3: [(p1[0] p2[0])/2, (p1[1] p2[1])/2, (p1[2] p2[2])/2]
    });
};

而自身利用的也是第两种方法,可是缩进选拔了增加补充的办法,即缩进的岗位用空白的图纸填充来幸免Jquery.treeview的题材

基本功配件全体定义完成,接着正是将“shape3d”属性设置为自定义的 3D 模型“custom” ,并将“layoutable”属性设置为“false”阻止图元参加布局,并将点时期的连线通过edge.a('pipeline', node)重新刷新,并加多进数据模型 dataModel 中:

图片 12

var createEdge = function(dm, node1, node2) {//创建‘custom’模型的edge
    var node = new ht.Node();
    node.s({
        'shape3d': 'custom',
        'shape3d.color': '#ECE0D4',
        'layoutable': false
    });
    dm.add(node);

    var edge = new ht.Edge(node1, node2);
    edge.a('pipeline', node);
    edge.s('edge.color', 'rgba(0, 0, 0, 0)');
    dm.add(edge);
    return edge;
};

自己的树节点结构

插:大家还是能够在工业上用 HeatMap 热图上做小说,效果照旧很炫,具体地址http://hightopo.com/guide/guide/plugin/forcelayout/examples/example_heatmap3d.html

鲜明了节点的HTML我们就能够来写CSS了。有了效果图,有个节点结构接着就编写CSS了

图片 13

上面是CSS的总体代码

界面上的图纸全部绘制完结,剩下的就只有form 表单,首先将 form 表单增加进 HTML 页面,用的是 HT 封装的 ht.widget.FormPane 函数:

复制代码 代码如下:

var formPane = new ht.widget.FormPane();
formPane.setWidth(230);
formPane.setHeight(125);
formPane.addToDOM();

.ie .bbit-tree .bbit-tree-bwrap{
}
.bbit-tree ul,.bbit-tree li
{
list-style-type:none;
margin:0px;
padding:0px;
}
.bbit-tree-body
{
font-size:12px;
}
.bbit-tree-icon, .bbit-tree-ec-icon, .bbit-tree-node-cb,.bbit-tree-elbow-line, .bbit-tree-elbow, .bbit-tree-elbow-end, .bbit-tree-elbow-plus, .bbit-tree-elbow-minus, .bbit-tree-elbow-end-plus, .bbit-tree-elbow-end-minus{
border: 0 none;
height: 18px;
margin: 0;
padding: 0;
vertical-align: top;
width: 16px;
background-repeat: no-repeat;
}
.bbit-tree-node-cb
{
height:16px;
}
.bbit-tree-node-collapsed .bbit-tree-node-icon, .bbit-tree-node-expanded .bbit-tree-node-icon, .bbit-tree-node-leaf .bbit-tree-node-icon{
border: 0 none;
height: 18px;
margin: 0;
padding: 0;
vertical-align: top;
width: 16px;
background-position:center;
background-repeat: no-repeat;
}
.ie .bbit-tree-node-indent img, .ie .bbit-tree-node-icon, .ie .bbit-tree-ec-icon {
vertical-align:middle !important;
}
.bbit-tree-noicon .bbit-tree-node-icon{
width:0; height:0;
}
/* No line styles 没无线的体制 */
.bbit-tree-no-lines .bbit-tree-elbow{
background:transparent;
}
.bbit-tree-no-lines .bbit-tree-elbow-end{
background:transparent;
}
.bbit-tree-no-lines .bbit-tree-elbow-line{
background:transparent;
}
/* Arrows Vista系统树的体裁只有箭头*/
.bbit-tree-arrows .bbit-tree-elbow{
background:transparent;
}
.bbit-tree-arrows .bbit-tree-elbow-plus{
background:transparent no-repeat 0 0;
}
.bbit-tree-arrows .bbit-tree-elbow-minus{
background:transparent no-repeat -16px 0;
}
.bbit-tree-arrows .bbit-tree-elbow-end{
background:transparent;
}
.bbit-tree-arrows .bbit-tree-elbow-end-plus{
background:transparent no-repeat 0 0;
}
.bbit-tree-arrows .bbit-tree-elbow-end-minus{
background:transparent no-repeat -16px 0;
}
.bbit-tree-arrows .bbit-tree-elbow-line{
background:transparent;
}
.bbit-tree-arrows .bbit-tree-ec-over .bbit-tree-elbow-plus{
background-position:-32px 0;
}
.bbit-tree-arrows .bbit-tree-ec-over .bbit-tree-elbow-minus{
background-position:-48px 0;
}
.bbit-tree-arrows .bbit-tree-ec-over .bbit-tree-elbow-end-plus{
background-position:-32px 0;
}
.bbit-tree-arrows .bbit-tree-ec-over .bbit-tree-elbow-end-minus{
background-position:-48px 0;
}
.bbit-tree-elbow-plus, .bbit-tree-elbow-minus, .bbit-tree-elbow-end-plus, .bbit-tree-elbow-end-minus{
cursor:pointer;
}
.ie ul.bbit-tree-node-ct{
font-size:0;
line-height:0;
zoom:1;
}
.bbit-tree-node{
white-space: nowrap;
}
.bbit-tree-node-el {
line-height:18px;
cursor:default;
/* cursor:pointer;*/
}
.bbit-tree-node a{
text-decoration:none;
-khtml-user-select:none;
-moz-user-select:none;
-webkit-user-select:ignore;
-kthml-user-focus:normal;
-moz-user-focus:normal;
-moz-outline: 0 none;
outline:0 none;
}
.bbit-tree-node a span{
text-decoration:none;
padding:1px 3px 1px 2px;
}
.bbit-tree-node .bbit-tree-node-disabled .bbit-tree-node-icon{
-moz-opacity: 0.5;
opacity:.5;
filter: alpha(opacity=50);
}
.bbit-tree-node .bbit-tree-node-inline-icon{
background:transparent;
}
.bbit-tree-node a:hover{
text-decoration:none;
}

切记,form 表单要设置宽高,不然不突显。

/* Fix for ie rootVisible:false issue,改良二个IEdebug */
.bbit-tree-root {
zoom:1;
}

form 表单增添行是经过 addRow 函数,我们入眼来讲一下底下的几行,Color、Range 和 Intensity,那多少个名字根本是用来决定“头灯”的。在 HT 中一向通过 setHeadlightColor/setHeadlightRange/setHeadlightIntensity 四个函数来决定“头灯”的水彩、范围以致灯的强度,onValueChanged 属性,看名称就会想到其意义属性值退换之后触发的风云:

/***********此处是Logo了,能够在此替换哦*****************/
.bbit-tree-node-expanded .bbit-tree-node-icon{
background-image:url(images/tree/folder-open.gif);
}
.bbit-tree-node-leaf .bbit-tree-node-icon{
background-image:url(images/tree/leaf.gif);
}
.bbit-tree-node-collapsed .bbit-tree-node-icon{
background-image:url(images/tree/folder.gif);
}
.bbit-tree-node-loading .bbit-tree-node-icon{
background-image:url(images/tree/loading.gif) !important;
}
.bbit-tree-node .bbit-tree-node-inline-icon {
background-image: none;
}
.bbit-tree-node-loading a span{
font-style: italic;
color:#444444;
}
.bbit-tree-lines .bbit-tree-elbow{
background-image:url(images/tree/elbow.gif);
}
.bbit-tree-lines .bbit-tree-elbow-plus{
background-image:url(images/tree/elbow-plus.gif);
}
.bbit-tree-lines .bbit-tree-elbow-minus{
background-image:url(images/tree/elbow-minus.gif);
}
.bbit-tree-lines .bbit-tree-elbow-end{
background-image:url(images/tree/elbow-end.gif);
}
.bbit-tree-lines .bbit-tree-elbow-end-plus{
background-image:url(images/tree/elbow-end-plus.gif);
}
.bbit-tree-lines .bbit-tree-elbow-end-minus{
background-image:url(images/tree/elbow-end-minus.gif);
}
.bbit-tree-lines .bbit-tree-elbow-line{
background-image:url(images/tree/elbow-line.gif);
}
.bbit-tree-no-lines .bbit-tree-elbow-plus{
background-image:url(images/tree/elbow-plus-nl.gif);
}
.bbit-tree-no-lines .bbit-tree-elbow-minus{
background-image:url(images/tree/elbow-minus-nl.gif);
}
.bbit-tree-no-lines .bbit-tree-elbow-end-plus{
background-image:url(images/tree/elbow-end-plus-nl.gif);
}
.bbit-tree-no-lines .bbit-tree-elbow-end-minus{
background-image:url(images/tree/elbow-end-minus-nl.gif);
}
.bbit-tree-arrows .bbit-tree-elbow-plus{
background-image:url(images/tree/arrows.gif);
}
.bbit-tree-arrows .bbit-tree-elbow-minus{
background-image:url(images/tree/arrows.gif);
}
.bbit-tree-arrows .bbit-tree-elbow-end-plus{
background-image:url(images/tree/arrows.gif);
}
.bbit-tree-arrows .bbit-tree-elbow-end-minus{
background-image:url(images/tree/arrows.gif);
}
/*TreeNode 选中的Disabled的部分颜料,字体样式*/
.bbit-tree-node{
color:#000;
font: normal 11px arial, tahoma, helvetica, sans-serif;
}
.bbit-tree-node a{
color:#000;
}
.bbit-tree-node a span{
color:#000;
}
.bbit-tree-node .bbit-tree-node-disabled a span{
color:gray !important;
}
.bbit-tree-node .bbit-tree-node-over {
background-color: #eee;
}
.bbit-tree-node .bbit-tree-selected {
background-color: #d9e8fb;
}

['Color', 'Range', 'Intensity'].forEach(function(name) {
    var obj = { id: name },
    func = function(oV, nV) {
        g3d['setHeadlight'   name](nV);// === g3d.setHeadlightColor(nV)/g3d.setHeadlightRange(nV)/g3d.setHeadlightIntensity(nV)
    };
    if (name === 'Color')
        obj.colorPicker = {//ht.widget.ColorPicker为颜色选择框 
        instant: true,
        value: g3d['getHeadlight'   name](),// === g3d.getHeadlightColor()
        onValueChanged: func
    };
    else 
        obj.slider = {//滑动条
            min: 0,
        max: name === 'Range' ? 20000 : 3,
        step: 0.1,
        value: g3d['getHeadlight'   name](),
        onValueChanged: func
        };
    formPane.addRow([ name, obj ], [ 70, 0.1 ]);
});

地点了树的中坚样式外,定义了二个有 号带line的体裁和 号不带line的样式

slider 和 colorPicker 都以 HT 自定义的滑动条和颜料选用器,详情请参谋 HT for Web 表双手册。

图片 14 那正是非凡 号带line的体裁

假使还应该有不懂的请咨询笔者,可能能够平昔上 HT for Web 官方网站查阅手册。

css中所用到的持有图片

 

图片 15 图片 16 图片 17 图片 18 图片 19 图片 20 图片 21 图片 22 图片 23 图片 24 图片 25 图片 26 图片 27 图片 28 图片 29 图片 30

 

图片 31 图片 32 图片 33

2:明确数据结构

复制代码 代码如下:

var menudata = [{
id: "0.1",//唯一的ID即可
text: "Beyondbit UI Demo",
hasChildren: true,
isexpand: true,
complete: true,
ChildNodes: [{
id: "0.1.1",
text: "日期选用",
hasChildren: true,
isexpand: false,
complete: true,
ChildNodes: [{
id: "0.1.1.1",
text: "控件演示",
value: "Testpages/datepickerDemo.htm",
hasChildren: false,
isexpand: false,
complete: true,
ChildNodes: null
},
...
]

如此的组织有个低价就多少作者是带档次的,特别方便遍历,在后头的级联关联合中学会看见
3: 面子做好了那就从头做里子了,编写脚本(Javascript)
自家是JQuery得拥护者,所以自然js的框架自然是接纳Jquery了
先上个一体化代码,再逐条分析

复制代码 代码如下:

/****************************************
author:[email protected]
page:
***************************************/
(function($) {
$.fn.swapClass = function(c1, c2) {
return this.removeClass(c1).addClass(c2);
}
$.fn.switchClass = function(c1, c2) {
if (this.hasClass(c1)) {
return this.swapClass(c1, c2);
}
else {
return this.swapClass(c2, c1);
}
}
$.fn.treeview = function(settings) {
var dfop =
{
method: "POST",
datatype: "json",
url: false,
cbiconpath: "/images/icons/",
icons: ["checkbox_0.gif", "checkbox_1.gif", "checkbox_2.gif"],
showcheck: false, //是或不是出示选取
oncheckboxclick: false, //当checkstate状态变化时所接触的风浪,不过不会触发因级联选用而引起的浮动
onnodeclick: false,
cascadecheck: true,
data: null,
clicktoggle: true, //点击节点进行和缩小子节点
theme: "bbit-tree-arrows" //bbit-tree-lines ,bbit-tree-no-lines,bbit-tree-arrows
}
$.extend(dfop, settings);
var treenodes = dfop.data;
var me = $(this);
var id = me.attr("id");
if (id == null || id == "") {
id = "bbtree" new Date().getTime();
me.attr("id", id);
}
var html = [];
buildtree(dfop.data, html);
me.addClass("bbit-tree").html(html.join(""));
InitEvent(me);
html = null;
//预加载图片
if (dfop.showcheck) {
for (var i = 0; i < 3; i ) {
var im = new Image(16,16);
im.src = dfop.cbiconpath dfop.icons[i];
}
}
//region
function buildtree(data, ht) {
ht.push("<div class='bbit-tree-bwrap'>"); // Wrap ;
ht.push("<div class='bbit-tree-body'>"); // body ;
ht.push("<ul class='bbit-tree-root ", dfop.theme, "'>"); //root
var l = data.length;
for (var i = 0; i < l; i ) {
buildnode(data[i], ht, 0, i, i == l - 1);
}
ht.push("</ul>"); // root and;
ht.push("</div>"); // body end;
ht.push("</div>"); // Wrap end;
}
//endregion
function buildnode(nd, ht, deep, path, isend) {
ht.push("<li class='bbit-tree-node'>");
ht.push("<div id='", id, "_", nd.id, "' tpath='", path, "' unselectable='on'");
var cs = [];
cs.push("bbit-tree-node-el");
if (nd.hasChildren) {
cs.push(nd.isexpand ? "bbit-tree-node-expanded" : "bbit-tree-node-collapsed");
}
else {
cs.push("bbit-tree-node-leaf");
}
if (nd.classes) { cs.push(nd.classes); }
ht.push(" class='", cs.join(" "), "'>");
//span indent
ht.push("<span class='bbit-tree-node-indent'>");
if (deep == 1) {
ht.push("<img class='bbit-tree-icon' src='../Themes/Shared/images/s.gif'/>");
}
else if (deep > 1) {
ht.push("<img class='bbit-tree-icon' src='../Themes/Shared/images/s.gif'/>");
for (var j = 1; j < deep; j ) {
ht.push("<img class='bbit-tree-elbow-line' src='../Themes/Shared/images/s.gif'/>");
}
}
ht.push("</span>");
//img
cs.length = 0;
if (nd.hasChildren) {
if (nd.isexpand) {
cs.push(isend ? "bbit-tree-elbow-end-minus" : "bbit-tree-elbow-minus");
}
else {
cs.push(isend ? "bbit-tree-elbow-end-plus" : "bbit-tree-elbow-plus");
}
}
else {
cs.push(isend ? "bbit-tree-elbow-end" : "bbit-tree-elbow");
}
ht.push("<img class='bbit-tree-ec-icon ", cs.join(" "), "' src='../Themes/Shared/images/s.gif'/>");
ht.push("<img class='bbit-tree-node-icon' src='../Themes/Shared/images/s.gif'/>");
//checkbox
if (dfop.showcheck && nd.showcheck) {
if (nd.checkstate == null || nd.checkstate == undefined) {
nd.checkstate = 0;
}
ht.push("<img id='", id, "_", nd.id, "_cb' class='bbit-tree-node-cb' src='", dfop.cbiconpath, dfop.icons[nd.checkstate], "'/>");
}
//a
ht.push("<a hideFocus class='bbit-tree-node-anchor' tabIndex=1 href='javascript:void(0);'>");
ht.push("<span unselectable='on'>", nd.text, "</span>");
ht.push("</a>");
ht.push("</div>");
//Child
if (nd.hasChildren) {
if (nd.isexpand) {
ht.push("<ul class='bbit-tree-node-ct' style='z-index: 0; position: static; visibility: visible; top: auto; left: auto;'>");
if (nd.ChildNodes) {
var l = nd.ChildNodes.length;
for (var k = 0; k < l; k ) {
nd.ChildNodes[k].parent = nd;
buildnode(nd.ChildNodes[k], ht, deep 1, path "." k, k == l - 1);
}
}
ht.push("</ul>");
}
else {
ht.push("<ul style='display:none;'></ul>");
}
}
ht.push("</li>");
nd.render = true;
}
function getItem(path) {
var ap = path.split(".");
var t = treenodes;
for (var i = 0; i < ap.length; i ) {
if (i == 0) {
t = t[ap[i]];
}
else {
t = t.ChildNodes[ap[i]];
}
}
return t;
}
function check(item, state, type) {
var pstate = item.checkstate;
if (type == 1) {
item.checkstate = state;
}
else {// 上溯
var cs = item.ChildNodes;
var l = cs.length;
var ch = true;
for (var i = 0; i < l; i ) {
if ((state == 1 && cs[i].checkstate != 1) || state == 0 && cs[i].checkstate != 0) {
ch = false;
break;
}
}
if (ch) {
item.checkstate = state;
}
else {
item.checkstate = 2;
}
}
//change show
if (item.render && pstate != item.checkstate) {
var et = $("#" id "_" item.id "_cb");
if (et.length == 1) {
et.attr("src", dfop.cbiconpath dfop.icons[item.checkstate]);
}
}
}
//遍历子节点
function cascade(fn, item, args) {
if (fn(item, args, 1) != false) {
if (item.ChildNodes != null && item.ChildNodes.length > 0) {
var cs = item.ChildNodes;
for (var i = 0, len = cs.length; i < len; i ) {
cascade(fn, cs[i], args);
}
}
}
}
//冒泡的祖宗
function bubble(fn, item, args) {
var p = item.parent;
while (p) {
if (fn(p, args, 0) === false) {
break;
}
p = p.parent;
}
}
function nodeclick(e) {
var path = $(this).attr("tpath");
var et = e.target || e.srcElement;
var item = getItem(path);
//debugger;
if (et.tagName == "IMG") {
// 号供给进行
if ($(et).hasClass("bbit-tree-elbow-plus") || $(et).hasClass("bbit-tree-elbow-end-plus")) {
var ul = $(this).next(); //"bbit-tree-node-ct"
if (ul.hasClass("bbit-tree-node-ct")) {
ul.show();
}
else {
var deep = path.split(".").length;
if (item.complete) {
item.ChildNodes != null && asnybuild(item.ChildNodes, deep, path, ul, item);
}
else {
$(this).addClass("bbit-tree-node-loading");
asnyloadc(ul, item, function(data) {
item.complete = true;
item.ChildNodes = data;
asnybuild(data, deep, path, ul, item);
});
}
}
if ($(et).hasClass("bbit-tree-elbow-plus")) {
$(et).swapClass("bbit-tree-elbow-plus", "bbit-tree-elbow-minus");
}
else {
$(et).swapClass("bbit-tree-elbow-end-plus", "bbit-tree-elbow-end-minus");
}
$(this).swapClass("bbit-tree-node-collapsed", "bbit-tree-node-expanded");
}
else if ($(et).hasClass("bbit-tree-elbow-minus") || $(et).hasClass("bbit-tree-elbow-end-minus")) { //- 号须求收缩
$(this).next().hide();
if ($(et).hasClass("bbit-tree-elbow-minus")) {
$(et).swapClass("bbit-tree-elbow-minus", "bbit-tree-elbow-plus");
}
else {
$(et).swapClass("bbit-tree-elbow-end-minus", "bbit-tree-elbow-end-plus");
}
$(this).swapClass("bbit-tree-node-expanded", "bbit-tree-node-collapsed");
}
else if ($(et).hasClass("bbit-tree-node-cb")) // 点击了Checkbox
{
var s = item.checkstate != 1 ? 1 : 0;
var r = true;
if (dfop.oncheckboxclick) {
r = dfop.oncheckboxclick.call(et, item, s);
}
if (r != false) {
if (dfop.cascadecheck) {
//遍历
cascade(check, item, s);
//上溯
bubble(check, item, s);
}
else {
check(item, s, 1);
}
}
}
}
else {
if (dfop.citem) {
$("#" id "_" dfop.citem.id).removeClass("bbit-tree-selected");
}
dfop.citem = item;
$(this).addClass("bbit-tree-selected");
if (dfop.onnodeclick) {
dfop.onnodeclick.call(this, item);
}
}
}
function asnybuild(nodes, deep, path, ul, pnode) {
var l = nodes.length;
if (l > 0) {
var ht = [];
for (var i = 0; i < l; i ) {
nodes[i].parent = pnode;
buildnode(nodes[i], ht, deep, path "." i, i == l - 1);
}
ul.html(ht.join(""));
ht = null;
InitEvent(ul);
}
ul.addClass("bbit-tree-node-ct").css({ "z-index": 0, position: "static", visibility: "visible", top: "auto", left: "auto", display: "" });
ul.prev().removeClass("bbit-tree-node-loading");
}
function asnyloadc(pul, pnode, callback) {
if (dfop.url) {
var param = builparam(pnode);
$.ajax({
type: dfop.method,
url: dfop.url,
data: param,
dataType: dfop.datatype,
success: callback,
error: function(e) { alert("error occur!"); }
});
}
}
function builparam(node) {
var p = [{ name: "id", value: encodeURIComponent(node.id) }
, { name: "text", value: encodeURIComponent(node.text) }
, { name: "value", value: encodeURIComponent(node.value) }
, { name: "checkstate", value: node.checkstate}];
return p;
}
function InitEvent(parent) {
var nodes = $("li.bbit-tree-node>div", parent);
nodes.each(function(e) {
$(this).hover(function() {
$(this).addClass("bbit-tree-node-over");
}, function() {
$(this).removeClass("bbit-tree-node-over");
})
.click(nodeclick)
.find("img.bbit-tree-ec-icon").each(function(e) {
if (!$(this).hasClass("bbit-tree-elbow")) {
$(this).hover(function() {
$(this).parent().addClass("bbit-tree-ec-over");
}, function() {
$(this).parent().removeClass("bbit-tree-ec-over");
});
}
});
});
}
function getck(items, c, fn) {
for (var i = 0, l = items.length; i < l; i ) {
items[i].checkstate == 1 && c.push(fn(items[i]));
if (items[i].ChildNodes != null && items[i].ChildNodes.length > 0) {
getck(items[i].ChildNodes, c, fn);
}
}
}
me[0].t = {
getSelectedNodes: function() {
var s = [];
getck(treenodes, s, function(item) { return item });
return s;
},
getSelectedValues: function() {
var s = [];
getck(treenodes, s, function(item) { return item.value });
return s;
},
getCurrentItem: function() {
return dfop.citem;
}
};
return me;
}
//获取具有入选的节点的Value数组
$.fn.getTSVs = function() {
if (this[0].t) {
return this[0].t.getSelectedValues();
}
return null;
}
//获取具备入选的节点的Item数组
$.fn.getTSNs = function() {
if (this[0].t) {
return this[0].t.getSelectedNodes();
}
return null;
}
$.fn.getTCT = function() {
if (this[0].t) {
return this[0].t.getCurrentItem();
}
return null;
}
})(jQuery);

先是步:自然是有着Jquery的控件的首先步都是搭这一个架子,宽容JQuery和$防止闭包,制止和别的类库冲突,接受一个参数(是个目的)

复制代码 代码如下:

;(function($) {
//也得以利用$.fn.extend(treeview:function(setting){})
$.fn.treeview = function(settings) {
}
})(jQuery);

那第二步:给控件加一些参数暗中同意参数,同一时间能调用方法$.extend让最后调用时的参数覆盖暗中同意的(若无则选拔暗中认可)

复制代码 代码如下:

var dfop ={
method: "POST",//默许使用POST提交数据
datatype: "json",//数据类型是json
url: false,//异步央求的url
cbiconpath: "/images/icons/",//checkbox icon的目录地点
icons: ["checkbox_0.gif", "checkbox_1.gif", "checkbox_2.gif"],//checkbxo三态的图形
showcheck: false, //是不是出示checkbox
oncheckboxclick: false, //点击checkbox时接触的平地风波
onnodeclick: false,//点击node触发的岁月
cascadecheck: true,//是不是启用级联
data: null,//早先化数据
theme: "bbit-tree-arrows" //二种风格备选bbit-tree-lines ,bbit-tree-no-lines,bbit-tree-arrows
}
//用传进来的参数覆盖暗许,没传则保留
$.extend(dfop, settings);

其三步:生成默许数据的HTML(依据大家的剖判节点的Dom结构,数据的数据结构,生成节点那是极度的简易),,增添到当前容器中。最终是登记事件这里有叁个十分首要的地点,即懒加载(没有进展的节点HTML是不转移的),那将供给大家在树内部要维护一套数据(开支一点都不大),对于质量的升高那是一对一的显明。另外三个主要的地点,正是选拔壹遍变动全部开展节点的HTML并由此innerHTML属性来生成Dom,并非通过append操作,因为向来操作innerHTML比通过dom原生的措施要快上N倍(节点越来越多,N越大),切记切记!

复制代码 代码如下:

var treenodes = dfop.data; //内部的数额,其实一直用 dfop.data也足以
var me = $(this);
var id = me.attr("id");
if (id == null || id == "") {
id = "bbtree" new Date().getTime();
me.attr("id", id);
}//全局独一的ID
var html = [];
buildtree(dfop.data, html);//生成开展节点的HTML,push到数组中
me.addClass("bbit-tree").html(html.join(""));
Init伊夫nt(me);//开端化事件
html = null;

在节点生成进程中,同不经常候可生育节点的Path(节点路线),方便寻找

复制代码 代码如下:

if (nd.hasChildren) { //存在子节点
if (nd.isexpand) {//同一时候节点已经进行则输出子节点
ht.push("<ul class='bbit-tree-node-ct' style='z-index: 0; position: static; visibility: visible; top: auto; left: auto;'>");
if (nd.ChildNodes) {
var l = nd.ChildNodes.length;
for (var k = 0; k < l; k ) {//递归调用并生育节点的门路
nd.ChildNodes[k].parent = nd;
buildnode(nd.ChildNodes[k], ht, deep 1, path "." k, k == l - 1);
}
}
ht.push("</ul>");
}
else { //不然是待输出状态
ht.push("<ul style='display:none;'></ul>");
}
}

挂号事件,接受参数parent,即从某一父节点最先增大事件(因为做了个hover效果,所以事件是在各种节点上,如若裁撤该意义,事件可平素附加Tree上经过伊芙nt的srcElement来散发可略提升品质)

复制代码 代码如下:

function InitEvent(parent) {
var nodes = $("li.bbit-tree-node>div", parent);
nodes.each(function(e) {
$(this).hover(function() {
$(this).addClass("bbit-tree-node-over"); //鼠标浮动节点的体裁变化
}, function() {
$(this).removeClass("bbit-tree-node-over");
})
.click(nodeclick)//node的onclick事件,这几个是重中之重哦
.find("img.bbit-tree-ec-icon").each(function(e) { //arrow的hover事件,为了落实vista那么些风格的
if (!$(this).hasClass("bbit-tree-elbow")) {
$(this).hover(function() {
$(this).parent().addClass("bbit-tree-ec-over");
}, function() {
$(this).parent().removeClass("bbit-tree-ec-over");
});
}
});
});
}

此地最关键的或许node的click事件,因为他要拍卖的政工相当多,如树的进展降低(假如实节点官样文章,但是hasChildren为真,同时complete属性不为真则要求异步加载子节点,如子节点存在,不过尚未Render那么就要Render),点击checkbox要出发级联的事件和oncheckbox事件,点击任何则触发配置原则的nodeonclick事件,这一切都通过前边event的源元素的class来差异点击的靶子

复制代码 代码如下:

function nodeclick(e) {
var path = $(this).attr("tpath");//获取节点路线
var et = e.target || e.srcElement;//获取事件源
var item = getItem(path);//依据path获取节点的多少
//debugger;
if (et.tagName == "IMG") {
// 号供给举行,管理加减号
if ($(et).hasClass("bbit-tree-elbow-plus") || $(et).hasClass("bbit-tree-elbow-end-plus")) {
var ul = $(this).next(); //"bbit-tree-node-ct"
if (ul.hasClass("bbit-tree-node-ct")) {
ul.show();
}
else {
var deep = path.split(".").length;
if (item.complete) {
item.ChildNodes != null && asnybuild(item.ChildNodes, deep, path, ul, item);
}
else {
$(this).addClass("bbit-tree-node-loading");
asnyloadc(ul, item, function(data) {
item.complete = true;
item.ChildNodes = data;
asnybuild(data, deep, path, ul, item);
});
}
}
if ($(et).hasClass("bbit-tree-elbow-plus")) {
$(et).swapClass("bbit-tree-elbow-plus", "bbit-tree-elbow-minus");
}
else {
$(et).swapClass("bbit-tree-elbow-end-plus", "bbit-tree-elbow-end-minus");
}
$(this).swapClass("bbit-tree-node-collapsed", "bbit-tree-node-expanded");
}
else if ($(et).hasClass("bbit-tree-elbow-minus") || $(et).hasClass("bbit-tree-elbow-end-minus")) { //- 号要求缩小
$(this).next().hide();
if ($(et).hasClass("bbit-tree-elbow-minus")) {
$(et).swapClass("bbit-tree-elbow-minus", "bbit-tree-elbow-plus");
}
else {
$(et).swapClass("bbit-tree-elbow-end-minus", "bbit-tree-elbow-end-plus");
}
$(this).swapClass("bbit-tree-node-expanded", "bbit-tree-node-collapsed");
}
else if ($(et).hasClass("bbit-tree-node-cb")) // 点击了Checkbox
{
var s = item.checkstate != 1 ? 1 : 0;
var r = true;
if (dfop.oncheckboxclick) { //触发配置的函数
r = dfop.oncheckboxclick.call(et, item, s);
}
if (r != false) {//假如重返值不为false,即checkbxo变化使得
if (dfop.cascadecheck) {//允许触发级联
//遍历
cascade(check, item, s);//则向下关联
//上溯
bubble(check, item, s); //向上关联
}
else {
check(item, s, 1);//不然只管本人
}
}
}
}
else {//点击到了其他地点
if (dfop.citem) { //上三个脚下节点
$("#" id "_" dfop.citem.id).removeClass("bbit-tree-selected");
}
dfop.citem = item;//此次的当下节点
$(this).addClass("bbit-tree-selected");
if (dfop.onnodeclick) {
dfop.onnodeclick.call(this, item);
}
}
}

举办节点,异步央求的局地代码应该不是很复杂就不细诉了,关键来说一下级联
级联有多少个难题要拍卖,第二个是遍历子节点,第1个是上溯到祖节点,因为大家的数据结构那五个操作都体现很轻易

复制代码 代码如下:

//遍历子节点
function cascade(fn, item, args) {
if (fn(item, args, 1) != false) {
if (item.ChildNodes != null && item.ChildNodes.length > 0) {
var cs = item.ChildNodes;
for (var i = 0, len = cs.length; i < len; i ) {
cascade(fn, cs[i], args);
}
}
}
}
//冒泡的古人
function bubble(fn, item, args) {
var p = item.parent;
while (p) {
if (fn(p, args, 0) === false) {
break;
}
p = p.parent;
}
}

找到节点的同期都会触发check那些回调函数,来判断当前节点的情况,详细请看上面代码中的注释部分应该是相比明晰,描写了那些历程

复制代码 代码如下:

function check(item, state, type) {
var pstate = item.checkstate; //当前气象
if (type == 1) {
item.checkstate = state; //假若是遍历子节点,父是什么子正是何等
}
else {// 上溯 ,这几个就错综复杂一些了
var cs = item.ChildNodes; //获取当前节点的全数子节点
var l = cs.length;
var ch = true; //是不是不是中间状态 半选
for (var i = 0; i < l; i ) {
if ((state == 1 && cs[i].checkstate != 1) || state == 0 && cs[i].checkstate != 0) {
ch = false;
break;//他的子节点只要有三个没选中,那么他就是半选
}
}
if (ch) {
item.checkstate = state;//不是半选,则子节点是怎么着他就是怎样
}
else {
item.checkstate = 2; //半选
}
}
//change show 假如节点已出口,而其前后状态分裂,则变化checkbxo的呈现
if (item.render && pstate != item.checkstate) {
var et = $("#" id "_" item.id "_cb");
if (et.length == 1) {
et.attr("src", dfop.cbiconpath dfop.icons[item.checkstate]);
}
}
}

至此大家树的重视功能已经完全完结了。其余就是公开一些艺术等,大家可详细代码,示例中公然了七个三个当下入选的保有节点,其他二个当下的节点。 

我们能够透过以下网站查看文中的演示,selected拼错了,我们海涵! windows azure安插照旧麻烦懒得修改了3500 节点贰回加载,我们能够点击根节点的全选来拜候速度

  

异步加载,按需加载的情事也是不行常用的,使用的是SQL Azure服务器在U.S.A.ing,所以可能异步有一些慢,本地数据源那是一下子的

FAQ:

1:如何设置各个节点不相同的Logo?

回答:

骨子里毫不扩大,本人就帮衬,只是未有表明而已,我们来看一下那些代码吧?在BuildNode方法中有如此一句?      
if (nd.classes) { cs.push(nd.classes); }

在节点的数据结构中得以设置属性classes ,该属性将用作节点特殊的Css Class 增加到节点上。那么利用那点,就足以设置节点的Logo了

图片 34

下一场正是编辑三个Style 就能够

图片 35

最终来看下效果啊?

图片 36

1:协助静态的树,即一遍性将一切数据加载到客商端。 2:异步树,即三回只加载一流或若干...

本文由pc28.am发布于前端技术,转载请注明出处:的交互式大巴线路图,塑造基于jQuery的高品质T

上一篇:nodejs部署方式,编程基础 下一篇:没有了
猜你喜欢
热门排行
精彩图文
  • Canvas完毕监察和控制种类页面呈现,json工控风机
    Canvas完毕监察和控制种类页面呈现,json工控风机
    传说 HTML5 Canvas 达成客车站监察和控制 2017/11/21 · HTML5 ·Canvas 初稿出处: hightopo    陪伴国内经济的长足发展,大家对安全的渴求更为高。为了防卫下列景
  • 不足挂齿的,层叠上下文
    不足挂齿的,层叠上下文
    深入领会CSS中的层叠上下文和层叠顺序 2016/01/10 · CSS ·层叠上下文 原稿出处:张鑫旭    零、凡间的道理都以想通的 在此个世界上,所有的事都有个前后
  • 那或许是史上最全的CSS自适应布局总计,html清除
    那或许是史上最全的CSS自适应布局总计,html清除
    那或许是史上最全的CSS自适应布局计算 2016/05/11 · CSS ·自适应布局 原来的文章出处: 茄果    题目严谨坚守了新广告法,你再不爽,小编也没不合规呀!
  • 网页内文字如何拉长和压扁
    网页内文字如何拉长和压扁
    一、IE和Chrome等浏览器与zoom 还在几年前, zoom 还只是IE浏览器自身个人的玩意儿,不过,以后,除了FireFox浏览器,其余,非常Chrome和平运动动端浏览器已经
  • 资源大全,开发资源
    资源大全,开发资源
    CSS 资源大全 2015/12/25 · CSS · 1评论 ·CSS 本文由 伯乐在线 -iLeo翻译,艾凌风校稿。未经许可,禁止转载! 英文出处:github.com。欢迎加入翻译组。 sotayamash