生活随笔
收集整理的这篇文章主要介绍了
小程序之基于canvas绘制高铁线路图
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
前几天@天下雪 给了我一张高铁的路线图,问我能不能用canvas画出来,所以我就试了试,我的思路可能比较复杂;如果有更简单的思路可以留言回复;
关注微信公众号,获取源码和教程
下面说一下我的实现思路:
1、首先是每个站点圆角矩形的绘制,一开始想着用canvas把圆角矩形绘制出来,但发现小程序暂时还没有绘制圆角的arcTo方法,所以用canvas绘制就相对比较麻烦,最后为了方便决定用图片代替;
2、将整个路线图分为四个小图片,(1)站点圆角矩形(2)站点之间的直连线(3)站点之间右侧弯曲连线(4)站点之间左侧弯曲连线;
3、通过观察分析,将绘制过程分为两步,(1)奇数行圆角矩形、连线的绘制点x坐标是从左至右递增,y坐标值是行数乘以某个固定值(2)偶数行圆角矩形、连线的绘制点x坐标是从左至右递减,y坐标值是行数乘以某个固定值
4、奇数行,偶数行的圆角矩形的下标index+1是3的倍数的话,奇数行当前下标右侧绘制右弯曲连线图片,偶数行当前下标左侧绘制左弯曲连线图片;
5、整个canvas绘制区域在不同手机上的适配
6、具体的一些细节请参照代码注释
7、开发工具上使用drawImage重复绘制同一张图片只显示第一次绘制的位置,暂时不知道什么原因,所以请在真机上测试;
8、有什么不足之处,望大家多多指点!感激!
wxml代码:
<!--pages/Gline/index.wxml--> <viewclass="g-title">(G23)选择出发站点<textclass="chooseStation">{{chooseStation}}</text></view> <canvasbindtouchstart="touchS"canvas-id="map"style='width:{{canvWidth}}rpx;height:{{canvHeight}}px;background-color:#eee'/>
wxss代码:
/* pages/Gline/index.wxss */
page{ background-color: #eeeeee }
.g-title{font-size: 36rpx;font-weight: 600;color: #768da4;padding: 36rpx 0;padding-left: 20rpx; background-color: #fff}
.chooseStation{color: #32b16c}
js代码:
[javascript] view plaincopy
js代码: Page({ data:{ canvWidth:750, canvHeight:750, stations:['北京南','天津南','济南西','泰安','滕州东','徐州东','南京南','镇江南','苏州北','上海虹桥','北京南','天津南','济南西','泰安','滕州东','徐州东','南京南','镇江南','苏州北','上海虹桥','北京南','天津南','济南西','泰安','滕州东','徐州东','南京南','镇江南','苏州北','上海虹桥'], chooseStation:'', prevChooseIdx:null, }, onLoad:function(options){ const ctx = wx.createCanvasContext('map'); this.ctx = ctx; this.column = 3; this.offsetTop = 30; this.rect={ img_b:'/images/rect-b.png', img_g:'/images/rect-g.png', height:32, width:68 } this.line = { img:'/images/line.png', height:6, width:30 }, this.bendLine = { img_l:'/images/line_l.png', img_r:'/images/line_r.png', height:70, width:20 }, this.rectArr=[]; this.oddRowIndexArr=[]; this.evenRowIndexArr=[]; this.initMap(); }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, adaptiveScreenSize:function(o){ let ww = this.data.winWidth; let zoom = ww/375; this.setData({zoom:zoom}); let rectW = o.width*zoom; let rectH = o.height*zoom; o.width = rectW; o.height = rectH; }, initMap:function(){ const that = this; wx.getSystemInfo({ success: function(res){ const ww = res.windowWidth; const pr = res.pixelRatio; that.setData({ winWidth:ww,pixelRatio:pr}); that.drawMap(); } }) }, drawTxtAtPos:function(idx){ const rectArr = this.rectArr; const w = this.rect.width; const h = this.rect.height; let txt = this.data.stations[idx]; let len = txt.length; let fontSize = len>3?12:14; let x = rectArr[idx].x; let y = rectArr[idx].y; let txt_x = Math.floor((w - len*fontSize)/2)+x; let txt_y = Math.floor(h/2+fontSize/2)+y-2; this.ctx.setFontSize(fontSize); this.ctx.setFillStyle('#ffffff') this.ctx.fillText(txt, txt_x, txt_y); }, initRect:function(idx){ const rectArr = this.rectArr; let x = rectArr[idx].x; let y = rectArr[idx].y; this.ctx.drawImage(this.rect.img_b,x, y, this.rect.width, this.rect.height); }, initCanvHeight:function(){ let len = this.data.stations.length; let pr = this.data.pixelRatio; let z = this.data.zoom; let row = Math.ceil(len/this.column); let h = 0; if(row <= 1){ console.log(this.rect.height); h = (this.offsetTop*2 + this.rect.height)*2; }else{ h = this.offsetTop*2+(row-1)*(this.bendLine.height-this.line.height)+this.rect.height; } this.setData({canvHeight:h}); }, drawLine:function(){ const rectArr = this.rectArr; let x=0,y=0; if(rectArr.length==2){ x = rectArr[0].x+this.rect.width; y = rectArr[0].y+Math.floor((this.rect.height-this.line.height)/2); this.ctx.drawImage(this.line.img, x, y, this.line.width, this.line.height); }else{ const odd = this.oddRowIndexArr; const even = this.evenRowIndexArr; if(odd.length>0){ for(let i=0;i<odd.length;i++){ if((odd+1)!=rectArr.length){ x = rectArr[odd].x+this.rect.width; y = rectArr[odd].y+Math.floor((this.rect.height-this.line.height)/2); if((odd+1)%this.column!=0){ this.ctx.drawImage(this.line.img, x, y, this.line.width, this.line.height); }else{ this.ctx.drawImage(this.bendLine.img_r, x, y, this.bendLine.width, this.bendLine.height); } } } } if(even.length>0){ for(let i=0;i<even.length;i++){ if((even+1)!=rectArr.length){ y = rectArr[even].y+Math.floor((this.rect.height-this.line.height)/2); if((even+1)%this.column!=0){ x = rectArr[even].x-this.line.width; this.ctx.drawImage(this.line.img, x, y, this.line.width, this.line.height); }else{ x = rectArr[even].x-this.bendLine.width; this.ctx.drawImage(this.bendLine.img_l, x, y, this.bendLine.width, this.bendLine.height); } } } } } }, drawMap:function(){ this.adaptiveScreenSize(this.rect); this.adaptiveScreenSize(this.line); this.adaptiveScreenSize(this.bendLine); this.initCanvHeight(); this.createRectTopPoints(); const rectArr = this.rectArr; for(let i=0;i<rectArr.length;i++){ this.initRect(i); this.drawTxtAtPos(i); } this.ctx.draw(true); this.drawLine(); this.ctx.draw(true); }, getDisXArr:function(){ let arr = []; let ww = this.data.winWidth; let disX = Math.floor((ww-(this.column*this.rect.width+(this.column-1)*this.line.width))/2); for(let i=0;i<this.column;i++){ let x = disX+i%this.column*(this.rect.width+this.line.width); arr = x; } return arr; }, createRectTopPoints:function(){ let rectArr = []; let disXArr = this.getDisXArr(); let disXArrRev = this.getDisXArr().reverse(); let disY = this.offsetTop; let len = this.data.stations.length; let row = Math.ceil(len/this.column); let n=0,x=0,y=0; for(let j = 1;j<=row;j++){ for(let i=0;i<this.column;i++){ ++n; if(n<=len){ if(j%2!=0){ this.oddRowIndexArr.push(n-1); x = disXArr; }else{ this.evenRowIndexArr.push(n-1); x = disXArrRev; } y = disY + (j-1)*(this.bendLine.height-this.line.height); this.rectArr[n-1] = {x:x,y:y}; } } } }, pointInRectPolygon : function (point, vs) { let x = point[0], y = point[1],inside = false; for (let i = 0, j = vs.length - 1; i < vs.length; j = i++) { let xi = vs[0], yi = vs[1]; let xj = vs[j][0], yj = vs[j][1]; let intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); if (intersect) inside = !inside; } return inside; }, getRectPolygon:function(x,y,w,h){ let vs = new Array() ; vs[0] = [x,y]; vs[1] = [x+w,y]; vs[2] = [x+w,y+h]; vs[3] = [x,y+h]; return vs; } , chooseStation:function(currIdx){ let txt = this.data.stations[currIdx]; let prevIdx = this.data.prevChooseIdx; if(prevIdx!=null){ let x = this.rectArr[prevIdx].x; let y = this.rectArr[prevIdx].y; this.ctx.drawImage(this.rect.img_b,x, y, this.rect.width, this.rect.height); this.drawTxtAtPos(prevIdx); } let x = this.rectArr[currIdx].x; let y = this.rectArr[currIdx].y; this.ctx.drawImage(this.rect.img_g,x, y, this.rect.width, this.rect.height); this.drawTxtAtPos(currIdx); this.ctx.draw(true); this.setData({chooseStation:txt,prevChooseIdx:currIdx}); }, touchS:function(e){ console.log(e); let touch = e.changedTouches; if(touch.length==1){ let tapPoint = [touch[0].x,touch[0].y]; let rectArr = this.rectArr; for(let i=0;i<rectArr.length;i++){ let vs = this.getRectPolygon(rectArr.x,rectArr.y,this.rect.width,this.rect.height); let inside = this.pointInRectPolygon(tapPoint,vs); if(inside){ this.chooseStation(i); break; } } } } })
真机测试图:
wxapp-Gline.zip
转载于http://www.wxapp-union.com/article-1419-1.html
总结
以上是生活随笔为你收集整理的小程序之基于canvas绘制高铁线路图的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。