上回讲到将人民日报的首版图片显示出来,本次将实现点击新闻对应区域,阅读该新闻html
热区就是在网页上进行了连接的一个区域算法
在人民日报电子版的版面图片上,点击想要看的新闻,右侧就会出现该新闻的详细报道,咱们点击的地方就是“热区”,在网页中可经过<map></map>
标签实现此项功能,可是小程序中未提供相似功能的组件,要肿么办?小程序
俗话说:只要思想不滑坡,办法总比困难多this
虽然没有相似组件,但是咱们只要知道区域的范围就好啦,点击版面图片的某块区域时,判断触点是否在该区域内就好了。那么如何判断?url
如上所述,版面图片的热区信息包含在map标签内,正则匹配走起~
修改paper.js的onLoad方法为:code
onLoad: function (options) { var self = this; //获取系统宽高,并计算宽高比 .......... wx.request({ url: url, success: function (res) { var html = res.data; //正则式-匹配版面图片 var pagePicImgReg = /<img[^>]+src=(.*)\s+border=0\s+usemap=#pagepicmap[^>]*>/i; //正则式-匹配热区信息 var pagePicMapReg = /<map[^>]+name=pagepicmap[^>]*>.*<\/map>/i; //版面图片匹配结果 var pagePicImgMatch = html.match(pagePicImgReg); //热区信息匹配结果 var pagePicMapMatch = html.match(pagePicMapReg); //中间变量,存放map标签内容 var mapHtml = ""; //中间变量,存放img的src内容 var imgSrc = ""; pagePicMapMatch && (mapHtml = pagePicMapMatch[0]); pagePicImgMatch && (imgSrc = pagePicImgMatch[1].replace('../../..', imgUrl)); //正则式-匹配map标签里area信息,coords是区域定点信息,href是该区域所连接到的文章 var areaReg = /<area\s+coords="(.*?)"[^>]+href="(.*?)"[^>]*>/ig; var area; //存放该版面图片的area内容 var areaArray = [] while ((area = areaReg.exec(mapHtml)) != null) { areaArray.push({ "coords": area[1].split(",").map(self.computeCoords), "href": area[2] });//href为当前版面每条文章的连接 } //console.log("areaArray ", areaArray); self.setData({ paperInfo: [{ "imgSrc": imgSrc, "areaArray": areaArray}] }); } }) },
paper.js添加computeCoords方法: 因为响应的coords坐标信息对应的版面图片默认为400*571px的,因此不一样设备的coords要做等比例缩放xml
//计算适合该设备的coords大小 computeCoords: function (coord, index) { var self = this; var tmpCoord = parseInt(coord); if (index % 2 == 1) {//表明x坐标 tmpCoord = Math.ceil(tmpCoord * (400 / self.data.windowWidth)); } if (index % 2 == 0) {//表明y坐标 tmpCoord = Math.ceil(tmpCoord * (571 / self.data.windowHeight)); } return tmpCoord; },
知道了版面图片的热区状况,如何判断用户点击的是哪篇文章呢?
ray-crossing算法
1.简单来讲,该算法能够判断一点是否在给定的某个不规则封闭区域内。(幸运的是版面图片上画的热区是简单的封闭图形,且大可能是矩形)
该算法的大体思路是:过被判断的点(触点)做一条向右的射线,若射线与区域的边的交点为奇数,则认为该点在此区域内,若为偶数,则未在该区域内
对于边界点(区域顶点和边上的点),对于本应用来讲,用户点到边界的几率很小,是能够忽略的
2.实现:在paper.js中添加如下方法htm
//point为用户触点的坐标,coords为某个热区顶点状况 pointInRegin: function (point, coords) { //coords中每两个是一对坐标 var count = 0;//统计目标点向右画射线与多边形相交次数 var x = point[0];//用户触点x位置 var y = point[1];//用户触点y位置 var i = 0, j = 0;//j表明i的下一个坐标点 //coords中肯定一条直线的两点的坐标 var xi = 0; var yi = 0; var xj = 0; var yj = 0; for (i = 0, j = coords.length - 2; i < coords.length - 1; j = i, i = +2) { xi = coords[i]; yi = coords[i + 1]; xj = coords[j]; yj = coords[j + 1]; if (yi == yj) { continue; }//若是两点水平,则跳过 if (y < Math.min(yi, yj)||y > Math.max(yi, yj)) { continue; }//若是触点低于该线段或高于该线段,则跳过 if (x >= Math.max(xi, xj)) { continue; }//若是触点在该线段的右边,则跳过 //该触点与coords所肯定的区域有交叉,求该交叉点的x坐标的值 var intersection_x = (xj - xi) * (y - yi) / (yj - yi) + xi; if (x < intersection_x) { count++; }//若是交叉点在触点的右边,相交次数加1 } if (count % 2 == 0) { return false; }//在多边形外面或边上 if (count % 2 == 1) { return true; }//在多边形里面 },
paper.js添加肯定触点点击的新闻连接方法:事件
/** * 肯定触点的文章 * 返回文章的href * pagenum表明版面号(从1开始编号) */ getArticleHref: function (fingerx, fingery, pagenum) { var self = this; var currentPageAreas = self.data.paperInfo[pagenum - 1].areaArray; var aresLength = currentPageAreas.length; var i; var points = []; for (i = 0; i < aresLength; i++) { points = currentPageAreas[i].coords; if (self.pointInRegin([fingerx, fingery], points)) { console.log("找到href",currentPageAreas[i].href); return currentPageAreas[i].href; }else{console.log("未在当前coords内");} } }, /** * 点击跳转到相关文章 *记得在paper.wxml文件的img组件上绑定toArticle事件 */ toArticle: function (e) { var self = this; var fingerx = e.detail.x;//x,y表明距离其父文档左上角的距离 var fingery = e.detail.y; //获取触点所在的文章href,目前只有初版因此pagenum为1 var href = self.getArticleHref(fingerx, fingery, pagenum); if (href) { console.log("获取的文章连接为 ",href); }else{ console.log("未找到文章连接"); } },
按照上篇文章的方法,编译运行程序,点击版面图片上的任意一条新闻,查看控制台是否输出该文章的href图片