前几天@天下雪 给了我一张高铁的路线图,问我能不能用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代码:

  1. <!--pages/Gline/index.wxml-->
  2. <viewclass="g-title">(G23)选择出发站点<textclass="chooseStation">{{chooseStation}}</text></view>
  3. <canvasbindtouchstart="touchS"canvas-id="map"style='width:{{canvWidth}}rpx;height:{{canvHeight}}px;background-color:#eee'/>

wxss代码:

  1. /* pages/Gline/index.wxss */
  2. page{ background-color: #eeeeee }
  3. .g-title{font-size: 36rpx;font-weight: 600;color: #768da4;padding: 36rpx 0;padding-left: 20rpx; background-color: #fff}
  4. .chooseStation{color: #32b16c}

js代码:

js代码:// pages/Gline/index.js
Page({data:{canvWidth:750,canvHeight:750,stations:['北京南','天津南','济南西','泰安','滕州东','徐州东','南京南','镇江南','苏州北','上海虹桥','北京南','天津南','济南西','泰安','滕州东','徐州东','南京南','镇江南','苏州北','上海虹桥','北京南','天津南','济南西','泰安','滕州东','徐州东','南京南','镇江南','苏州北','上海虹桥'],chooseStation:'',//页面显示选中的车站名字prevChooseIdx:null,//上一次选中车站的下标// stations:['北京南','天津南','济南西','泰安'],},onLoad:function(options){// 页面初始化 options为页面跳转所带来的参数// this.setData({canvHeight:502});const ctx = wx.createCanvasContext('map');//路线图绘制的画布上下文对象this.ctx = ctx;//将ctx对象绑定到当前页面中this.column = 3;//每行显示车站数量this.offsetTop = 30;//绘制起始坐标的top值,也就是距离canvas顶部的距离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=[];//记录奇数行的车站的下标数组,如[0,1,2,6,.....]this.evenRowIndexArr=[];//记录偶数行的车站的下标数组,如[3,4,5,9,.....]this.initMap();},onReady:function(){},onShow:function(){// 页面显示},onHide:function(){// 页面隐藏},onUnload:function(){// 页面关闭},//对不同设备下图片大小的适配adaptiveScreenSize:function(o){let ww = this.data.winWidth;let zoom = ww/375;//375这里是按iPhone6的宽度做等比缩放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});//将设备的信息存入data中,供后面使用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;//当站点文本文字超过3个字,将缩小字号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;//这里额外-2,文本才能更接近垂直居中this.ctx.setFontSize(fontSize);this.ctx.setFillStyle('#ffffff')this.ctx.fillText(txt, txt_x, txt_y);},//在下标为idx处绘制圆角矩形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);},//动态计算不同屏幕大小canvas的高度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){//首先当车站数量为2个的时候,只需绘制一条线段x = rectArr[0].x+this.rect.width;//计算绘制线段起始点的x坐标y = rectArr[0].y+Math.floor((this.rect.height-this.line.height)/2);//计算绘制线段起始点的y坐标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){//判断奇数行绘制点的下标如果不是3的整数倍将绘制一条直线,反之绘制右曲线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);}}}}//下面逻辑同奇数行的逻辑,不同的是绘制直线和弯曲线时x的坐标会有变化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();// setTimeout(()=>{const rectArr = this.rectArr; for(let i=0;i<rectArr.length;i++){this.initRect(i);this.drawTxtAtPos(i);}this.ctx.draw(true);// },500);this.drawLine();this.ctx.draw(true);},//计算后,每行的所有绘制点的起始坐标x值是一个固定数组//如:奇数行[10,20,30],偶数行:[30,20,10]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;},//根据给出的车站数量,将每个车站的绘制顶点计算出来存入数组rectArr中createRectTopPoints:function(){let rectArr = [];let disXArr = this.getDisXArr();let disXArrRev = this.getDisXArr().reverse();let disY = this.offsetTop;//绘制初始点距离canvas顶部的高度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);//console.log("奇数行:"+n);x = disXArr;}else{this.evenRowIndexArr.push(n-1);//console.log("偶数行:"+n);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;},//根据某个圆角矩形的绘制点和宽高,计算出圆角矩形4个顶点的坐标值//顺序为左上,右上,右下,左下,也就是顺时针方向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;} ,//点击车站调取的事件,事件中需要处理://1、需要获取到当前点击的车站文本//2、判断是否有过选取,如果之前有选取,需要将之前选取过的区块颜色改为默认色//3、改变当前区块的颜色//4、记录当前点击的下标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;//这里一定要用changedTouches,如果用touches,安卓机会有问题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绘制高铁线路图相关推荐

  1. 小程序之基于canvas绘制高铁线路图

    前几天@天下雪 给了我一张高铁的路线图,问我能不能用canvas画出来,所以我就试了试,我的思路可能比较复杂:如果有更简单的思路可以留言回复: 关注微信公众号,获取源码和教程 下面说一下我的实现思路: ...

  2. 在H5、微信小程序中使用canvas绘制二维码、分享海报

    在H5.微信小程序中使用canvas绘制二维码.分享海报 文章目录 在H5.微信小程序中使用canvas绘制二维码.分享海报 前言 一.canvas绘制二维码 1.H5中使用canvas 2.微信小程 ...

  3. 用微信小程序开发的Canvas绘制可配置的转盘抽奖

    使用https://github.com/givebest/GB-canvas-turntable代码移植过而来. 其它 微信小程序感觉是个半成品,代码移植过程比较繁琐麻烦.canvas API 部分 ...

  4. 微信小程序开发—(八)canvas绘制图形

    一.小知识 (1).API接口 (2).context 对象的方法列表 二.步骤 wxml中: <canvas canvas-id="myCanvas" class=&quo ...

  5. 微信小程序:wx-charts动态绘制折线图

    微信小程序:wx-charts动态绘制折线图 wx-charts是基于 Canvas的微信小程序主流图表工具,体积小易操作,支持多种图表的绘制,这里主要就动态绘制折线图做出详解,所谓动态,指的是表格的 ...

  6. 校园社团微信小程序,基于腾讯小程序云开发,后端完整代码包括社团通知,社团简介,社团福利,社团章程,社团招新,社团活动报名预约等

    功能介绍 校园社团小程序,前后端完整代码包括社团通知,社团简介,社团福利,社团章程,社团招新,社团活动报名预约等功能,采用腾讯提供的小程序云开发解决方案,无须服务器和域名 预约管理:开始/截止时间/人 ...

  7. 微信小程序之用canvas给微信头像加小红旗(canvas无法使用网络资源绘画)

    微信小程序之使用canvas给微信头像加小红旗 情境:新中国成立70周年,普天同庆.昨天看到朋友圈中被刷屏的@官方微信 给自己的头像加小红旗.服务器被卡爆,很多朋友说换头像不成功. 任务:打算自己写一 ...

  8. iKcamp出品|全网最新|微信小程序|基于最新版1.0开发者工具之初中级培训教程分享...

    ?? 微信小程序课程,面向所有具备前端基础知识的同学 ?? iKcamp官网:http://www.ikcamp.com 访问官网更快阅读全部免费分享课程:<iKcamp出品|全网最新|微信小程 ...

  9. 微信小程序毕业设计 基于微信图书馆借阅小程序系统开题报告功能参考

    微信小程序毕业设计 基于微信图书馆借阅小程序系统开题报告功能参考 下面是功能实现效果图:大家可以参考

最新文章

  1. ubuntu16.04 安装 eclipse
  2. django2.0集成xadmin0.6报错集锦
  3. 合并多个Word文档
  4. Java注解库_Java 注解详解
  5. git指定版本openwrt源码_[OpenWrt Wiki] LEDE源代码
  6. docker修改镜像的存储位置_Docker存储原理
  7. 2021阿里巴巴研发效能峰会来啦!
  8. 蓝桥杯 试题 基础练习 芯片测试——12行代码AC
  9. 剑指 Offer 43. 1~n 整数中 1 出现的次数(数位dp)
  10. Eclipse的详细安装步骤
  11. Java枚举(用Java普通类模拟枚举的实现原理及JDK枚举API使用示例)
  12. python 并行_python多进程并行代码实例
  13. cad与连接mySQL数据库,如何连接CAD与ACCESS数据库或excel表格?
  14. 16种系统测试方法概念+测试要点
  15. 常用制作钓鱼网站的工具
  16. 行星轨迹制作_用3ds max制作三维行星运动动画
  17. excel 删除重复项
  18. docker的使用及原理
  19. IDEA集成camunda-modeler
  20. android ogg转mp3,MP3提取转换器

热门文章

  1. 生活多快乐:笑死爹的程序段子
  2. 以太坊POA共识机制Clique源码分析 1
  3. 国外酷站设计:15个带给你灵感的作品集网站
  4. 计算机网络实验之Wireshark 实验
  5. 数据可视化系列-05数据分析报告
  6. java 各版本下载官方网站
  7. K-D Tree 算法详解及Python实现
  8. (转载)常见的程序员健康问题
  9. 从原来的系统中找回网络连接
  10. Unity 屏幕特效后期处理 OnRenderImage