微信小程序实现图片热区链接

热区

热区就是在网页上进行了链接的一个区域

人民日报电子版的版面图片上,点击想要看的新闻,右侧就会出现该新闻的详细报道,我们点击的地方就是“热区”,在网页中可通过<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

有话要说