菜单

pwa重构东京大巴线路图

2019年4月5日 - Html/Html5

准备

准备工作先做好,在 vue 和 react 之间,小编依旧选取了后世。基于
create-react-app
来搭建环境,crp 为您准备了3个开箱即用的支付环境,因而你无需本人亲手配置
webpack,由此你也不要求变成一名 webpack 配置工程师了。

除此以外一边,大家还亟需有的数额,包涵站点音信,线路途径,文字表达等等。基于在此以前的施用,能够通过一小段的代码获取新闻。就此如要大家收获大家原先的站点在
svg 图中的相关属性,普通的站点使用 circle 成分,为了取得其质量:

const circles = document.querySelectorAll(‘circle’); let result = [];
circles.forEach(circle => { let ele = { cx: circle.cx, cy: circle.cy,
sroke: circle.stroke, id: circle.id }; result.push(ele); }) const str =
JSON.stringify(result);

1
2
3
4
5
6
7
8
9
10
11
12
13
const circles = document.querySelectorAll(‘circle’);
let result = [];
circles.forEach(circle => {
  let ele = {
    cx: circle.cx,
    cy: circle.cy,
    sroke: circle.stroke,
    id: circle.id
  };
  result.push(ele);
})
const str = JSON.stringify(result);
 

经过如此的代码大家就能够收获 svg
普通站点音信,同理还可收获中间转播站音讯,线路途径信息以及站点以及线路 label
音讯。还有,大家还索要获得每个站点的时刻表消息,卫生间地点消息,无障碍电梯音信以及出入口消息。那里是写了壹部分爬虫去官网爬取并做了1部分数目处理,再次就不一壹赘述。

效果图

图片 1

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

地图稍微内容有点多,要全方位突显,字显得有些小了,可是没什么,能够根据供给加大收缩,字体和制图的剧情并不会失真,终归都以用矢量绘制的~

同步

class InfoCard extends React.Component { constructor(props) {  
 super(props) { …    }  }  … }

1
2
3
4
5
6
7
8
9
class InfoCard extends React.Component {
  constructor(props) {
   super(props) {
    …
   }
 }
 …
}
 

据他们说 HTML5 Canvas 的交互式地铁线路图

2018/03/14 · HTML5 ·
Canvas

原稿出处: xhload3d   

 前言

前二日在 echarts
上寻找灵感的时候,看到了不胜枚举有关地图类似的例证,地图定位等等,不过好像就是从未地铁线路图,就自身花了有的时光捣鼓出来了那一个交互式地铁线路图的
德姆o,地铁线路上的点是在网上随便下载了一个,那篇文章记录自个儿的一对到手(毕竟作者要么个菜鸟)以及代码的达成,希望能够帮到壹些情人。当然,假诺有哪些意见的能够平昔跟自家说,大家壹道调换才会发展。

部署

此时此刻的布局方案是使用 create-react-app 的官方提出,通过 gh-pages 完成将
build 的打包文件上传到 gh-pages 分支上从而完毕安插。

交互

先是是鼠标移动事件,鼠标滑过具体路线时,线路会变粗,悬停1会儿仍是能够看到那条线路的号子;当鼠标移动到“换乘站点”或“小站点”,站点对应的图标都会变大并且变色,字体也会变大,鼠标移开图标变回原来的水彩并且字体变小。分裂点在于鼠标移动到“换乘站点”时,“换乘站点”会旋转。

图片 2

鼠标滑动事件,我一贯基于 gv 的平底 div 举行的 mousemove 事件,通过 ht
封装的 getDataAt 函数字传送入事件 event
参数,获取事件下相应的节点,然后就足以随意操作节点了:

gv.getView().add伊夫ntListener(‘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()

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
表单,单击表单上的切切实实线路,只怕双击拓扑图上4意2个“站点”或许线路,则拓扑图会自适应到相应的有的,将被双击的局部突显到拓扑图的宗旨。

图片 3

form 表单的扬言部分本身好像还不曾解释。。。正是经过 new 2个ht.widget.FomePane 类创立一个 form 表单组件,通过 form.getView()
获取表单组件的底部 div,将那个 div 摆放在 body 右下角,然后经过 addRow
函数向 form 表单中添加一行的表单项,能够在那行中加上任意八个项,通过
addRow
函数的第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 =
一千; view.style.bottom = ‘拾px’;//ht组件大约都安装相对路径
view.style.right = ‘拾px’; view.style.background = ‘rgba(211, 21一, 21一,
0.八)’; names.forEach(function(nameString) {
form.addRow([//向表单中添加行 {//那一行中的第1个表单项 button:
{//向表单中添加button按钮 icon:
‘images/Line’+nameString.value+’.json’,//设置按钮的图标 background:
”,//设置按钮的背景 borderColor: ”,//设置按钮的边框颜色 clickable:
false//设置按钮不可点击 } }, {//第三个表单项 button: { label:
nameString.name, labelFont: ‘bold 1四px 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],
二三);//第3个参数是安装第3参数中的数组的增进率,小于一是比例,大于一是事实上拉长率。第一个参数是该行的冲天
}); }

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(‘二d.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为自适应的节点,参数二为是还是不是动画,参数三为gv与边框的padding
} else if(e.kind === ‘doubleClickBackground’) {//双击空白处
node.s(‘二d.visible’, false);//设置node节点不可知 查看 HT for Web
样式手册(http://www.hightopo.com/guide/guide/core/theme/ht-theme-guide.html\#ref\_style)
} });

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
预订义的1部分体裁属性,而 a
是大家用户来源定义的个性,一般是因而调用字符串来调用结果的,这几个字符串对应的能够是常量也可以是函数,仍然很灵活的。

末尾还做了2个小小的的一对,选中“站点”,则该“站点”的顶端会议及展览示三个水绿的会“呼吸”的用来申明当前入选的“站点”。

图片 4

“呼吸”的片段是使用 ht 的 setAnimation
函数来成功的,在用那么些函数从前要先开辟数据容器的动画开关,然后设置动画:

dm.enableAnimation();//打开数据容器的动画开关 function createRedLight()
{ var node = new ht.Node();
node.setImage(‘images/红灯.json’);//设置节点的图形 node.setSize(1,
一);//设置节点的尺寸 node.setLayer(‘firstTop’);//设置节点显示在gv的最上层
node.s(‘二d.visible’, false);//节点不可知 node.s(‘select.width’,
0);//节点选中时的边框为0,不可知 node.s(‘二d.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: 一, to: 0.5, next:
“expandWidth” }, expandHeight: { property: “height”, from: 0.五, to: 一,
next: “collapseHeight” }, collapseHeight: { property: “height”, from: 一,
to: 0.五, next: “expandHeight” }, start: [“expandWidth”,
“expandHeight”]//数组,用于内定要开动的1个或多少个动画 }); 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;
}

全体代码停止!

本性优化

上述那几个的开发得益于在此之前的保卫安全,所以重构过程恐怕比较快的,稍微熟知了下
react 的用法就做到了重构。可是,在上线之后选拔 lighthouse
做分析,performan 的得分是 0 分。首屏渲染以及可相互得分都以 0
分,首先来分析一下。因为任何应用都是透过 js 来渲染,而非常基本的便是可怜
svg。整个看下去,有几点值得注意:

找到标题点,就足以想到一些化解方案了。第九个相比简单,压缩 json
数据,去除一些不必要的信息。第二个,好的化解办法正是经过异步加载来促成组件加载,效果显明,尤其是对此
InfoCard 组件:

界面生成

底层的 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_Point一叁.push({ name: ’10叁号线’, 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]});

接下去来形容大巴线路,笔者注明了3个数组 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标签,作为唯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.四,//设置多边形的边框宽度 ‘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(一); } else { polyline.getSegments().push(二);
} } } } 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 中设置线的时候
Line6捌 有3个“跳跃”点的风貌,所以我们亟须“跳跃”过去,篇幅有限 Line6八数组具体的扬言自行看 subway.js。

此间说爱他美(Aptamil)(Beingmate)些,如若用的是 addPoint 函数,不设置 segments
时,暗中同意将添加进的点用直线连接,segments 的定义如下:

于是我们要做“跳跃”的一言一行设置 segments 为 一 即可。

最后绘制那一个大巴线上的点,那么些局地 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.陆,
0.6);//设置节点大小。由于js中每种点之间的偏移量太小,所以笔者只可以把节点设置小一些
node.setImage(‘images/旋转箭头.json’);//设置节点的图纸
node.a(‘alarmColor一’, ‘rgb(150, 150,
150)’);//attr属性,能够当中安装任何的东西,alarmColor壹是在上边安装的image的json中绑定的质量,具体参看
HT for Web
矢量手册(http://www.hightopo.com/guide/guide/core/vector/ht-vector-guide.html\#ref\_binding)
node.a(‘alarmColor二’, ‘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.0000壹);//自适应大小,参数一为是不是动画,参数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上的节点不可移动
});

那下你的大巴线路图就能够体现啦~接下来看看相互。

兼容性

眼前该利用在 Chrome 浏览器的扶助性是最棒的,安卓浏览器提议安装 Chrome
浏览器采取,小编1般也都相比欣赏在手提式有线电话机上利用谷歌(Google)浏览器。对于 Safari
浏览器,别的的浏览作用就像从未什么大标题,近日理应还没协助添加到主荧屏。但是在未来的
ios 版本好像对于 pwa 有着更进一步的帮衬。

总结

其壹 德姆o
花了自己两日时间完结,总认为有点不甘心啊,可是有时思维又转不过弯来,开销了成百上千的时辰,可是总的来说收获依旧广大的,笔者原先一贯认为借使通过
getPoints().push
来向多边形中添加点就足以了,求助了大神之后,发现原先那么些主意不但绕弯路而且还会冒出各式种种的题材,比如
getPoints 在此之前,一定要在多方形中已经有 points
才足以,不过在无数情状下,发轫化的 points
并倒霉设置,而且会导致代码很麻烦,直接通过 addPoint
方法,直接将点添加进多边形变量中,并且还会暗中同意将点通过直线的方式连接,也不用设置
segments,多喜人的1个函数。

还有正是因为 ht 暗许缩放大小是 20,而自作者那几个 德姆o
的间距又十分小,导致缩放到最大大巴线路图呈现也非常的小,所以笔者在 htconfig
中改变了 ht 的暗中同意 zoom马克斯 属性,记住,更改这几个值一定要在具有的 ht
调用在此以前,因为在 htconfig 中安装的值在后头定义都是不可改变的。

总的说来,那两日小编的脑细胞死了累累,也再一次生长了累累,人都以在不断提高的嘛~

1 赞 1 收藏
评论

图片 5

设计

数量准备好之后,正是选择的安排性了。首先,对组件进行三遍拆分:

结语

图片 6

花了三个礼拜的时间成功了类别的完整的重构,从这年来的 commit
记录可以见到三月份发狂 commit
了壹波,首假使首先个周三消费了二日的日子修改了很多代码,被百般 InfoCard的气象切换搞了很久,前面正是对准质量做了某个优化。进程很悲伤,1度困惑本身的
coding 能力。可是最终照旧有以下感悟:

终极二个冷笑话:

妙龄问禅师:“请问大师,笔者写的次序为什么一直不得到预期的出口?”
禅师答到:“年轻人,那是因为你的程序只会按您怎么写的实施,不会按您怎么想的实践啊……”

源代码地址,欢迎 star 或者 pr。

 

1 赞 收藏
评论

图片 7

异步

export default function asyncInfoCard (importComp) { class InfoCard
extends React.Component {    constructor(props) { super(props);
this.state = { component: null }; } asyncComponentDidMount() { const {
default: component } = await importComp(); this.setState({ component:
component })    }  } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default function asyncInfoCard (importComp) {
  class InfoCard extends React.Component {
   constructor(props) {
      super(props);
      this.state = {
        component: null
      };
    }
    
    asyncComponentDidMount() {
      const { default: component } = await importComp();
      this.setState({
        component: component
      })
   }
 }
}
 

如此那般咱们就贯彻了将同台组件改造成二个异步加载的零部件,那样就无需一下子加载全部的零部件。那样我们就能够在
Map 中使用异步的点子来开始展览零部件的加载:

import asyncInfoCard from ‘./InfoCard’ const InfoCard = asyncInfoCard(()
=> import(‘./InfoCard’)

1
2
3
import asyncInfoCard from ‘./InfoCard’
const InfoCard = asyncInfoCard(() => import(‘./InfoCard’)
 

经过上线之后的习性分析,lighthouse 质量评分一下子就上涨到了 80
多分,评释那样的精益求精要么相比灵通的。其它二个值得一提的点正是首屏,因为历史由来,整张图
svg 瓜月素的岗位都以定死的,及横坐标和纵坐标都已经是概念好的,而 svg
被定为在在那之中。在运动端加载时,展现的便是左侧的空域区域,所以给用户1种程序未加载完成的错觉。此前的版本的做法就是由此scroll 来达成滚动条的轮转,将视图的难题移动到中等地点。此次的想法是经过
transform 来实现:

.svg { transform: translate(-100px, -300px) }

1
2
3
.svg {
transform: translate(-100px, -300px)
}

如此实现了全部 svg 图地点的偏移,使用 lighthouse 举办解析,品质分降到了
70
多分。继续思量有没有别的的不2诀窍,后来笔者想在最左上上角定义1个箭头动画。

img src=”right_arrow.png” alt=”right arrow” title=”right arrow”
class=”right-arrow”/>

1
img src="right_arrow.png" alt="right arrow" title="right arrow" class="right-arrow"/>

.right-arrow { animation: moveright 3s linear infinite; } @keyframs
moveright { 0% { transform: translateX(2rem); } 50% { transform:
translateX(3rem); } 100% { transform: translateX(5rem); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.right-arrow {
  animation: moveright 3s linear infinite;
}
@keyframs moveright {
  0% {
    transform: translateX(2rem);
  }
  50% {
    transform: translateX(3rem);
  }
  100% {
    transform: translateX(5rem);
  }
}

图片 8

诸如此类大家就足以创立三个巡回向右移动的卡通片,提醒用户向右滑动。计划之后察觉质量分立马降到
0,索性也就吐弃了这几个做法。最终来时间控制制接纳
transform: translateX(-200px) translateY(-300px); ,因为这么经过 css三的品质能够在某些移动设备上还能运用 GPU 加快,并且 translateX
不会唤起页面的重绘可能重排,只会促成图层重组,最小幸免对品质的震慑。

pwa重构北京大巴线路图

2018/03/28 · JavaScript
· PWA

初稿出处:
Neal   

在此之前一向有在保卫安全3个巴黎地铁线路图的 pwa,最要害的性情正是 “offline
first”。可是出于代码都以因而原生的 js
去完成,以前本身都不是很喜欢去用框架,不想有所任何框架的偏好。不过到后期随着代码量的加码,代码的确变得混乱不堪,拓展新职能也变得越发困难。因而,花了靠近八个礼拜的时候对于利用进行了2次完整的重构。网址访问地址:https://neal1991.github.io/subway-shanghai

组件结构

将全部地图知道成三个 Map 组件,再将其分成 四 个小零件:

图片 9

那是多个大约的零件划分,里面只怕包蕴越来越多的别的成分,比如 InfoCard 就有
InfoCard => TimeSheet => TimesheetTable 那样的嵌套。

零件通讯和气象管理

本地开发的最大的难点应该就是那1块的内容了。本来出于组件的层级并不算特别复杂,所以自个儿并不打算上
Redux
那系列型的大局状态管理库。首要组件之间的通讯便是老爹和儿子通讯和兄弟组件通讯。父子组件通讯相比简单,父组件的
state 即为子组件的
props,能够透过那几个完结老爹和儿子组件通讯。兄弟组件略为复杂性,兄弟组件通过共享父组件的景况来展开通讯。即便那样的场景,笔者点击站点,希望能够弹出音信提醒窗,那就是Station 组件和 InfoCard 组件之间的通讯,通过 Map 组件来进展共享。点击
Station 组件触发事件,通过回调更新 Map 组件状态的翻新,同时也兑现了
InfoCard组件的创新。同时为了促成,点击任何区域就足以关闭消息提醒窗,大家对 Map
组件举办监听,监听事件的冒泡来达成急速的关闭,当然为了防止某些不须求的冒泡,还亟需在有的事件处理中截留事件冒泡。

图片 10

InfoCard 是无与伦比复杂的一个零部件,因为中间富含了少数个
icon,以及气象音信的切换,同时需求贯彻切换分歧的站点的时候能够更新消息提示窗。需求注意音信提醒窗信息初次点击音信的初阶化,以及切换不相同icon
时分别展现分化的音讯,比如卫生间新闻仍然出入口消息,以及对此时刻表,切换不相同的路线的时候更新对应的时刻表。那些境况的转会,需求值得注意。别的值得1题的点正是,在切换不一样站点的时候的处境,假使小编正在看某些站点的盥洗室新闻的时候,笔者点击其余多个站点,那时候弹出的新闻提醒窗应该是时刻表音讯可能卫生间信息吗?笔者的挑选照旧卫生间消息,作者对此这一景况举办了保全,那样的用户体验从逻辑上来讲如同更佳。具体实现的代码细节就不11表达了,里面肯能包蕴更多的底细,欢迎使用体验。

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图