根据 HTML5 Canvas完成 的互动式地铁路线图

日期:2021-02-26 类型:科技新闻 

关键词:自助建站免费建站平台,网站的建设服务,自助建站平台,如何自己建网站,怎么建设网站

序言

前两天在 echarts 上找寻设计灵感的情况下,看到了许多相关地形图相近的事例,地形图精准定位这些,可是仿佛便是沒有地铁路线图,就自身花了1些時间捣鼓出来了这个互动式地铁路线图的 Demo,地铁路线上的点是在网络上随意免费下载了1个,这篇文章内容纪录自身的1些获得(终究我還是个菜鸟)和编码的完成,期待可以帮到1些盆友。自然,假如有甚么建议的能够立即跟我说,大伙儿1起沟通交流才会发展。

实际效果图

 

http://www.hightopo.com/demo/subway/index.html

地形图略微內容有点多,要所有展现,字显得有点小了,可是没事儿,能够依照要求变大变小,字体样式和绘图的內容其实不会失真,终究全是用矢量绘图的~

页面转化成

最底层的 div 是根据 ht.graph.GraphView 组件转化成的,随后便可以运用 HT for Web 出示好的方式,启用 canvas 画笔随意绘图就好,先看来看如何转化成最底层 div:
 

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); //对话框转变恶性事件           
}

如今我便可以在这个 div 上乱涂乱画了~最先我获得免费下载好的地铁路线图上的点,我将它们放在 subway.js 中,这个 js 文档所有全是免费下载的內容,我沒有做别的的修改,关键是将这些点依据路线来分分派加上到数字能量数组中,例如:

mark_Point13 = [];//路线 数字能量数组内包括路线的起始点和终点站座标和这条路线的名字
t_Point13 = [];//换为站点 数字能量数组内包括路线中的换乘站点座标和换为站点名字
n_Point13 = [];//小站点 数字能量数组内包括路线中的小站点座标和小站点名字
mark_Point13.push({ name: '103号线', value: [113.4973,23.1095]}); 
mark_Point13.push({ name: '103号线', value: [113.4155,23.1080]}); 
t_Point13.push({ name: '鱼珠', value: [113.41548,23.10547]}); 
n_Point13.push({ name: '裕丰围', value: [113.41548,23.10004]}); 

接下来来勾勒地铁路线,我申明了1个数字能量数组 lineNum,用来装 js 中全部的地铁路线的序号,和1个 color 数字能量数组,用来装全部的地铁线的色调,这些色调的 index 与 lineNum 中地铁线序号的 index 是11对应的:

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 文档中的取名方法也是有规律性的,哪1条路线,则取名后边1定会再加对应的数据,因此大家只必须将标识符串与这个序号融合便可得到 js 中对应的数字能量数组了:

let lineName = 'Line' + num;
let line = window[lineName];
createLine 的界定也十分简易,我的编码设定了很多的款式,因此看起来有点多。建立1个 ht.Polyline 管线,大家能够根据 polyline.addPoint() 涵数向这个自变量中加上实际的点,根据 setSegments 能够设定点的联接方法。
function createLine(num, color) {//绘图地形图线
    var polyline = new ht.Polyline();//多边形 管线
    polyline.setTag(num);//设定连接点tag标识,做为唯1标识
    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线(有两条,可是点是在同1个数字能量数组中的)
                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 有1个“弹跳”点的状况,因此大家务必“弹跳”以往,篇数比较有限 Line68 数字能量数组实际的申明自主看 subway.js。

这里表明1点,假如用的是 addPoint 涵数,不设定 segments 时,默认设置将加上进的点用平行线联接,segments 的界定以下:

1: moveTo,占有 1 个点信息内容,意味着1个新相对路径的起始点
 

2: lineTo,占有 1 个点信息内容,意味着从之前最终点联接到该点
 

3: quadraticCurveTo,占有 2 个点信息内容,第1个点做为曲线图操纵点,第2个点做为曲线图完毕点
 

4: bezierCurveTo,占有 3 个点信息内容,第1和第2个点做为曲线图操纵点,第3个点做为曲线图完毕点
 

5: closePath,不占有点信息内容,意味着本次相对路径绘图完毕,并闭合到相对路径的起止点

因此大家要做“弹跳”的个人行为设定 segments 为 1 便可。

最终绘图这些地铁网上的点,这个一部分 subway.js 中也分离出来出来了,取名以“mark_Point”、“t_Point”和“n_Point”开始,我在前面 js 的展现一部分有对这些数字能量数组开展解释,大伙儿动动中指划上去看看。

大家在这些点的部位加上 ht.Node 连接点,当连接点1加上进 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中每一个点之间的偏位量很小,因此我迫不得已把连接点设定小1些
        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 涵数,大家顺带将拓扑图上的全部物品不能挪动也设定1下:

gv.fitContent(false, 0.00001);//自融入尺寸,主要参数1为是不是动漫,主要参数2为gv与边框的padding值
gv.setMovableFunc(function(){
    return false;//设定gv上的连接点不能挪动
});

这下你的地铁路线图便可以显示信息啦~接下看来看互动。

互动

最先是电脑鼠标挪动恶性事件,电脑鼠标滑过实际路线时,路线会变粗,悬停1会儿还能看到这条路线的序号;当电脑鼠标挪动到“换乘站点”或“小站点”,站点对应的标志都会增大而且变色,字体样式也会增大,电脑鼠标移开标志变回原先的色调而且字体样式缩小。不一样点在于电脑鼠标挪动到“换乘站点”时,“换乘站点”会转动。

 

电脑鼠标拖动恶性事件,我立即根据 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')) {//若并不是同1个连接点,而且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();//做为“上1个连接点”的储存自变量,能够根据这个值来获得连接点
    }
    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);

随后我运用右下角的 form 表单,点击表单上的实际路线,或双击鼠标拓扑图就任意1个“站点”或路线,则拓扑图会自融入到对应的一部分,将被双击鼠标的一部分呈现到拓扑图的中间。

 

form 表单的申明一部分我仿佛都还没解释。。。便是根据 new 1个 ht.widget.FomePane 类建立1个 form 表单组件,根据 form.getView() 获得表单组件的最底层 div,将这个 div 放置在 body 右下角,随后根据 addRow 涵数向 form 表单中加上1行的表单项,能够在这行中加上随意好几个项,根据 addRow 涵数的第2个主要参数(1个数字能量数组),对加上进的表单项开展宽度的设定,根据第3个主要参数设定这行的高宽比:

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([//向表单中加上行
            {//这1行中的第1个表单项
                button: {//向表单中加上button按钮
                    icon: 'images/Line'+nameString.value+'.json',//设定按钮的标志
                    background: '',//设定按钮的情况
                    borderColor: '',//设定按钮的边框色调
                    clickable: false//设定按钮不能点一下
                }
            },
            {//第2个表单项
                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);//第2个主要参数是设定第1主要参数中的数字能量数组的宽度,小于1是占比,超过1是具体宽度。第3个主要参数是该行的高宽比
    });
}

点击“站点”显示信息鲜红色标明,双击鼠标连接点自融入置放到拓扑图中间和双击鼠标空白处将鲜红色标明掩藏的內容全是根据对拓扑组件 gv 的恶性事件监视来操纵的,十分清楚易懂,编码以下:

var node = createRedLight();//建立1个新的连接点,显示信息为“红灯”的款式
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 预订义的1些款式特性,而 a 是大家客户来自定的特性,1般是根据启用标识符串来启用結果的,这个标识符串对应的能够是变量定义还可以是涵数,還是很灵便的。

最终还做了1个小小的的一部分,选定“站点”,则该“站点”的上方会显示信息1个鲜红色的会“吸气”的用来注明当今选定的“站点”。

 

“吸气”的一部分是运用 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 动漫手册(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"]//数字能量数组,用于特定要起动的1个或好几个动漫
    });
    dm.add(node);
    return node;
}

所有编码完毕!

总结

这个 Demo 花了我两天和间进行,总感觉有点不甘愿啊,可是有时逻辑思维又转但是弯来,花销了很多的時间,可是总的来讲获得還是许多的,我之前1直认为要是根据 getPoints().push 来向多边形中加上点便可以了,求助了高手以后,发现原先这个方式不但绕弯路并且还会出現各种各样各种各样的难题,例如 getPoints 以前,1定要在多边形中早已有 points 才能够,可是在许多状况下,原始化的 points 其实不好设定,并且会导致编码很繁琐,立即根据 addPoint 方式,立即将点加上进多边变形量中,而且还会默认设置将点根据平行线的方法联接,也无需设定 segments,多讨人喜欢的1个涵数。

也有便是由于 ht 默认设置放缩尺寸是 20,而我这个 Demo 的间隔又很小,致使放缩到最大地铁路线图显示信息也很小,因此我在 htconfig 中变更了 ht 的默认设置 zoomMax 特性,记牢,变更这个值1定要在全部的 ht 启用以前,由于在 htconfig 中设定的值在后边界定全是不能变更的。

以上所述是网编给大伙儿详细介绍的根据 HTML5 Canvas完成 的互动式地铁路线图,期待对大伙儿有一定的协助,假如大伙儿有任何疑惑请给我留言,网编会立即回应大伙儿的。在此也十分谢谢大伙儿对脚本制作之家网站的适用!