前言
效果图
界面生成
var dm = new ht.DataModel();//数据容器
var gv = new ht.graph.GraphView(dm);//拓扑组件
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); //窗口变化事件
}
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]});
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'];
let lineName = 'Line' + num;
let line = window[lineName];
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][2]*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;
}
-
moveTo,占用 1 个点信息,代表一个新路径的起点
-
lineTo,占用 1 个点信息,代表从上次最后点连接到该点
-
quadraticCurveTo,占用 2 个点信息,第一个点作为曲线控制点,第二个点作为曲线结束点
-
bezierCurveTo,占用 3 个点信息,第一和第二个点作为曲线控制点,第三个点作为曲线结束点
-
closePath,不占用点信息,代表本次路径绘制结束,并闭合到路径的起始点
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);//这个属性设置只是为了用来区分“换乘站点”和“小站点”的,后面会用上
}
}
gv.fitContent(false, 0.00001);//自适应大小,参数1为是否动画,参数2为gv与边框的padding值
gv.setMovableFunc(function(){
return false;//设置gv上的节点不可移动
});
交互
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);
}
});
gv.enableToolTip();//打开 tooltip 的开关
if(num === '68') polyline.setToolTip('A P M');//设置提示信息
else if(num === '60') polyline.setToolTip('G F');
else polyline.setToolTip('Line' + num);
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是实际宽度。第三个参数是该行的高度
});
}
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)
}
});
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;
}
总结