前言
上回讲到将人民日报的首版图片显示出来,本次将实现点击新闻对应区域,阅读该新闻
热区
热区就是在网页上进行了链接的一个区域
在人民日报电子版的版面图片上,点击想要看的新闻,右侧就会出现该新闻的详细报道,我们点击的地方就是“热区”,在网页中可通过<map></map>
标签实现此项功能,但是小程序中未提供类似功能的组件,要肿么办?
俗话说:只要思想不滑坡,办法总比困难多
虽然没有类似组件,可是我们只要知道区域的范围就好啦,点击版面图片的某块区域时,判断触点是否在该区域内就行了。那么如何判断?
代码实现
如上所述,版面图片的热区信息包含在map标签内,正则匹配走起~
修改paper.js的onLoad方法为:
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要作等比例缩放
//计算适合该设备的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中添加以下方法
//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