金沙国际官网_金沙国际平台登录

因为这个金沙国际官网_金沙国际平台登录网站与很多的大型澳门赌场都有合作,金沙国际官网_金沙国际平台登录尽职尽责,高效执行,保持好奇心,不断学习,追求卓越,点击进入金沙国际官网_金沙国际平台登录马上体验吧,所以现在也正式地开始了营业。

您的位置:金沙国际官网 > web前端 > 隔行扫描算法,的交互式地铁线路图

隔行扫描算法,的交互式地铁线路图

发布时间:2019-11-16 10:37编辑:web前端浏览(74)

    nodejs部署方式-pm2(一)

    2016/12/03 · JavaScript · NodeJS

    本文作者: 伯乐在线 - pangjian 。未经作者许可,禁止转载!
    欢迎加入伯乐在线 专栏作者。

    图片 1

    目前Nodejs开发中有很多痛点,其中有一个是修改完代码以后需要我们重启服务才能看到效果。这样一次次的杀进程、重启,杀进程、重启很让人头大。程序员是最痛恨重复工作的物种,之前有了解过的同学可能知道foreverforever可以帮我们解决上面的问题,通过对资源变化的检测做到变化后自动重启。开发阶段我们使用node file.js来启动另外由于Nodejs的单线程,任何异常都会导致整个服务中断,这对于生产上长时间提供服务的程序来讲是不可以的,forever可以帮我们在异常后重启,保证服务一直在线,我想这也就是它名字的由来吧。但我想说的是forever不够“高!大!上!”。接下来我要介绍一个足够高大上的神器– pm2

    基于 HTML5 Canvas 的交互式地铁线路图

    2018/03/14 · HTML5 · Canvas

    原文出处: xhload3d   

     前言

    前两天在 echarts 上寻找灵感的时候,看到了很多有关地图类似的例子,地图定位等等,但是好像就是没有地铁线路图,就自己花了一些时间捣鼓出来了这个交互式地铁线路图的 Demo,地铁线路上的点是在网上随便下载了一个,这篇文章记录自己的一些收获(毕竟我还是个菜鸟)以及代码的实现,希望能够帮到一些朋友。当然,如果有什么意见的可以直接跟我说,大家一起交流才会进步。

    png的故事:隔行扫描算法

    2017/06/21 · 基础技术 · PNG

    原文出处: AlloyTeam/june01   

    简介

    pm2=P(rocess) M(anager)2,是可以用于生产环境的Nodejs的进程管理工具,并且它内置一个负载均衡。它不仅可以保证服务不会中断一直在线,并且提供0秒reload功能,还有其他一系列进程管理、监控功能。并且使用起来非常简单。下面我将把我的使用过程分享出来,Nodejs应用是一个基于Express 4.x的应用,名称是Wolverine

    效果图

    图片 2

    地图稍微内容有点多,要全部展示,字显得有点小了,但是没关系,可以按照需求放大缩小,字体和绘制的内容并不会失真,毕竟都是用矢量绘制的~

    前言

    前文已经讲解过如何解析一张png图片,然而对于扫描算法里只是说明了逐行扫描的方式。其实png还支持一种隔行扫描技术,即Adam7隔行扫描算法。

    安装

    环境清单:

    • windows7 x64
    • node v5.0.0
    • npm 3.3.6

    全局安装pm2

    $ npm install pm2 -g

    1
    $ npm install pm2 -g

    更新

    $ pm2 update

    1
    $ pm2 update

    界面生成

    底层的 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: 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上的节点不可移动
    });

    这下你的地铁线路图就可以显示啦~接下来看看交互。

    优劣

    使用隔行扫描有什么好处呢?如果大家有去仔细观察的话,会发现网络上有一些png图在加载时可以做到先显示出比较模糊的图片,然后逐渐越来越清晰,最后显示出完整的图片,类似如下效果:图片 3

    这就是隔行扫描能带来的效果。隔行扫描一共会进行1到7次扫描,每一次都是跳着部分像素点进行扫描的,先扫描到像素点可以先渲染,每多一次扫描,图片就会更清晰,到最后一次扫描时就会扫描完所有像素点,进而渲染出完整的图片。

    当然,也因为要进行跳像素扫描,整张图片会存储更多额外数据而导致图片大小会稍微变大,具体增加了什么额外数据下文会进行讲解。

    启动

    以前启动Wolverine是利用package.json的scripts来实现的,只需要执行npm run start就可以启动,配置如下:

    "scripts": { "start": "node ./bin/www", "debug": "node debug ./bin/www" },

    1
    2
    3
    4
    5
    "scripts": {
        "start": "node ./bin/www",
        "debug": "node debug ./bin/www"
     
      },

    使用pm2我们可以在start处配置成 pm2 ./bin/www,命令后面支持加参数来实现watch、cluster多进程模式等功能。我不太喜欢一大串的命令,于是我使用了配置文件的方式。
    Wolverine的根目录,我创建了一个processes.json配置文件,配置文件内容如下,注释写的也很清楚了

    { "apps" : [{ "name" : "Wolverine", //名称 "script": "./bin/www", //程序入库 "cwd": "./", //根目录 "watch":[ "bin", "common", "configs", "public", "routes", "views" ],//需要监控的目录 "error_file":"./logs/app-err.log",//错误输出日志 "out_file":"./logs/app-out.log", //日志 "log_date_format":"YYYY-MM-DD HH:mm Z" //日期格式 }] }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    {
      "apps" : [{
        "name" : "Wolverine",  //名称
        "script": "./bin/www", //程序入库
        "cwd": "./",           //根目录
        "watch":[
    "bin",
    "common",
    "configs",
    "public",
    "routes",
    "views"
    ],//需要监控的目录
        "error_file":"./logs/app-err.log",//错误输出日志
        "out_file":"./logs/app-out.log",  //日志
        "log_date_format":"YYYY-MM-DD HH:mm Z" //日期格式
        }]
    }

    随后,我在package.json中增加了一条

    "pm2": "pm2 start processes.json"

    1
    "pm2": "pm2 start processes.json"

    在启动就直接输入如下命令就好:

    $ npm run pm2

    1
    $ npm run pm2

    看到下面的界面,就启动成功了,然后我们就可以关掉这个窗口了,服务不会因此停止,是不是高大上多了。
    图片 4

    交互

    首先是鼠标移动事件,鼠标滑过具体线路时,线路会变粗,悬停一会儿还能看到这条线路的编号;当鼠标移动到“换乘站点”或“小站点”,站点对应的图标都会变大并且变色,字体也会变大,鼠标移开图标变回原来的颜色并且字体变小。不同点在于鼠标移动到“换乘站点”时,“换乘站点”会旋转。

    图片 5

    鼠标滑动事件,我直接基于 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 表单,单击表单上的具体线路,或者双击拓扑图上任意一个“站点”或者线路,则拓扑图会自适应到对应的部分,将被双击的部分展现到拓扑图的中央。

    图片 6

    form 表单的声明部分我好像还没有解释。。。就是通过 new 一个 ht.widget.FomePane 类创建一个 form 表单组件,通过 form.getView() 获取表单组件的底层 div,将这个 div 摆放在 body 右下角,然后通过 addRow 函数向 form 表单中添加一行的表单项,可以在这行中添加任意多个项,通过 addRow 函数的第二个参数(一个数组),对添加进的表单项进行宽度的设置,通过第三个参数设置这行的高度:

    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是实际宽度。第三个参数是该行的高度 }); }

    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 是我们用户来自定义的属性,一般是通过调用字符串来调用结果的,这个字符串对应的可以是常量也可以是函数,还是很灵活的。

    最后还做了一个小小的部分,选中“站点”,则该“站点”的上方会显示一个红色的会“呼吸”的用来注明当前选中的“站点”。

    图片 7

    “呼吸”的部分是利用 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;
    }

    全部代码结束!

    生成

    要导出一张基于Adam7隔行扫描的png图片是非常简单,我们可以借助Adobe的神器——PhotoShop(以下简称ps)。我们把一张普通的图片拖入到ps中,然后依次点选【文件】-【存储为Web所用的格式】,在弹出的框里选择存储为PNG-24,然后勾选交错,最后点击存储即可。

    这里的交错就是只将扫描算法设为Adam7隔行扫描,如果不勾选交错,则是普通逐行扫描的png图片。

    本文由金沙国际官网发布于web前端,转载请注明出处:隔行扫描算法,的交互式地铁线路图

    关键词:

上一篇:没有了

下一篇:没有了