图片热区阴影遮罩 area_shadow

临近年末,项目也少了,闲来无事回顾了一下以前的项目,顺便也学习一下前端,作为一个后端开发人员,以前也写过一些jsp,现在前后端分离了,咱也来前端瞧瞧,凑凑热闹 O(∩_∩)O哈哈~。
回顾了一下以前的一个项目,有一个需求 显示一个电子报,点击电子报的某一个板块,显示该板块的详细内容,然而当时并没有采用canvas来绘制阴影,导致只能显示一些矩形的阴影 有些多边形的阴影并没有很好的显示出来,所以尝试了一下使用canvas来绘制我们图片热区 map_area 中的rect circle poly,尝试的结果如下
阴影示例图片
尽管前端知识有些缺乏,代码写的有些丑陋,我还是把它丢出来让大家来瞧瞧,希望大家多多指正,我好把它改一改。封装了一个vue

hotspot-shadow.vue

<template>
  <div class="wrapper" style="position: relative">
    <div>
      <img
        :src="imgUrl"
        usemap="#netmap"
        :alt="imgAlt"
        :height="imgHeight + 'px'"
        :width="imgWidth + 'px'"
        ref="img"
      />
      <map name="netmap" id="netmap">
        <area
          v-for="(area, index) in areas"
          :key="index"
          :shape="area.type"
          :coords="area.coord"
          :title="area.dhref"
          alt=""
          @mouseover="showShadow($event)"
        />
      </map>
    </div>
    <div
      style="
        position: absolute;
        top: 0;
        left: 0;
        display: none;
        cursor: pointer;
      "
      id="shadowDiv"
    >
      <canvas
        :width="canvasWidth"
        :height="canvasHeight"
        id="myCanvas"
        @mouseout="hiddenDiv"
        @mousemove="jugeInShadow($event)"
        @click="openHref($event)"
      >
        您的浏览器不支持 HTML5 canvas 标签。
      </canvas>
    </div>
  </div>
</template>

<script>
export default {
  components: {},
  props: {
    /**
      说明如下:
      openType:热区连接内容打开方式,window.open() 中的name,  值可以是blank(新窗口打开) 或者 self(替换当前页面),其他值也没做限制
      shadowColor: 阴影部分的颜色 默认为粉色 不透明度 0.5 当然你也可以改
      imgUrl:热区图片的地址 本地图片传参需要加一个 require("./1.jpg")
      imgAlt: 图片的文本替换内容
      imgHeight:图片的高宽(注意这个值与 area 中的coord 值息息相关,如果变了则coord的值也要变)想做一个缩放参数的,由于没有时间就不做了
      imgWeight:图片的高宽(注意这个值与 area 中的coord 值息息相关)  
      areas 是个数组 每个元素是一个对象格式如下
          {
            type:"rect" | "circle" | "poly"
            coord:"100,100,200,200"
            href:"www.baidu.com" //这里是一个链接  window.open 打开该链接 
          }
     */
    openType: {
      type: String,
      default: "blank",
    },
    shadowColor: {
      type: String,
      default: "rgba(255,220,220,0.5)",
    },
    imgUrl: {
      type: String,
      default: "",
    },
    imgAlt: {
      type: String,
      default: "",
    },
    imgHeight: {
      type: String,
      default: 800,
    },
    imgWidth: {
      type: String,
      default: 550,
    },
    areas: {
      type: Array,
      default() {
        return [];
      },
    },
  },
  created() {
    if (this.imgWidth !== 550) {
      this.widthRate = (this.imgWidth / 550).toFixed(2);
    }
    if (this.imgHeight !== 800) {
      this.heightRate = (this.imgHeight / 800).toFixed(2);
    }

    this.areas.forEach((item) => {
      if (item.type == "poly" || item.type == "rect") {
        let coordinate = item.coord.split(",");
        let coord = "";
        for (let i = 0; i < coordinate.length; i++) {
          if (i % 2 == 0) {
            coordinate[i] *= this.widthRate;
          } else {
            coordinate[i] *= this.heightRate;
          }
          coord += coordinate[i] + ",";
        }
        coord = coord.substr(0, coord.length - 1);
        item.coord = coord;
      } else if (item.type == "circle") {
        let coordinate = item.coord.split(",");
        coordinate[0] *= this.widthRate;
        coordinate[1] *= this.heightRate;
        coordinate[2] *= this.widthRate;
        item.coord = coordinate[0] + "," + coordinate[2] + "," + coordinate[2];
      }
    });
    this.canvasWidth *= this.widthRate;
    this.canvasHeight *= this.heightRate;
  },
  mounted() {
    this.relativePosX = this.$refs.img.getBoundingClientRect().x;
    this.relativePosY = this.$refs.img.getBoundingClientRect().y;
  },
  data() {
    return {
      relativePosX: 0,
      relativePosY: 0,
      heightRate: 1,
      widthRate: 1,
      // canvas画布的宽度
      canvasWidth: 400,
      // canvas画布的高度
      canvasHeight: 200,
      // 所在阴影的链接 每次移动到阴影上都会修改
      shadowHref: "",
    };
  },
  methods: {
    hiddenDiv() {
      // 移出 遮罩的div 则隐藏遮罩的div
      let e = document.getElementById("shadowDiv");
      e.style.display = "none";
    },
    openHref(event) {
      // 在阴影中点击打开链接
      let e = document.getElementById("shadowDiv");
      let c = document.getElementById("myCanvas");
      let ctx = c.getContext("2d");
      let xmin = e.style.left.replace("px", "");
      let ymin = e.style.top.replace("px", "");
      // 通过 canvas的isPointInPath 来判断点击的位置  是在绘制的图形上  而不只是在canvas的画布上
      if (
        ctx.isPointInPath(
          event.pageX - this.relativePosX - xmin,
          event.pageY - this.relativePosY - ymin
        )
      ) {
        //在则打开新链接
        // 这里可以再 设置一个方法 通过父组件来操作,这里就不再多说
        //window.open(this.shadowHref, "_" + this.openType);
        let content = "";
        this.$axios.get(this.shadowHref).then((res) => {
          this.$emit("changeContent", res.data);
        });
      }
    },
    jugeInShadow(event) {
      // 如果在canvas 的画布上移动,但是当你移除所绘制的图形(阴影) 则也判定离开
      let e = document.getElementById("shadowDiv");
      let xmin = e.style.left.replace("px", "");
      let ymin = e.style.top.replace("px", "");
      let c = document.getElementById("myCanvas");
      let ctx = c.getContext("2d");
      // 通过 canvas的isPointInPath 来判断点击的位置  是在绘制的图形上  而不只是在canvas的画布上
      if (
        !ctx.isPointInPath(
          event.pageX - this.relativePosX - xmin,
          event.pageY - this.relativePosY - ymin
        )
      ) {
        // 在多边形内
        let e = document.getElementById("shadowDiv");
        e.style.display = "none";
      }
    },
    showShadow(event) {
      // 阴影显示
      let e = event.currentTarget;
      let type = e.shape;
      let coords = e.coords.split(",");
      let c = document.getElementById("myCanvas");
      let ctx = c.getContext("2d");
      ctx.clearRect(0, 0, c.width, c.height);

      this.shadowHref = e.title;
      let shadowDiv = document.getElementById("shadowDiv");
      shadowDiv.style.display = "block";

      if ("rect" == type) {
        // area 是矩形 绘制 canvas 并遮罩该矩形
        // 计算画布的宽高
        this.canvasHeight = coords[3] - coords[1];
        this.canvasWidth = coords[2] - coords[0];
        c.width = this.canvasWidth;
        c.height = this.canvasHeight;
        // 矩形 直接使用 画布的宽高作为矩形的宽高
        ctx.rect(0, 0, c.width, c.height);

        // 设置阴影的div 的相对位置
        shadowDiv.style.top = coords[1] + "px";
        shadowDiv.style.left = coords[0] + "px";
      }
      if ("circle" == type) {
        // 计算canvas的宽高即为 直径
        this.canvasHeight = 2 * coords[2];
        this.canvasWidth = 2 * coords[2];
        ctx.beginPath();
        // 绘制圆形
        ctx.arc(coords[2], coords[2], coords[2], 0, 2 * Math.PI);
        ctx.closePath();

        // 设置阴影的div 的相对位置
        shadowDiv.style.top = coords[1] - coords[2] + "px";
        shadowDiv.style.left = coords[0] - coords[2] + "px";
      }
      if ("poly" == type) {
        //将coords 转化为坐标点
        // 取出最大的
        let vs = [];
        // 获取 多边形中 横坐标纵坐标的 最大最小值
        let xmax = coords[0];
        let xmin = coords[0];
        let ymax = coords[1];
        let ymin = coords[1];
        for (var temp = 0; temp < coords.length; temp += 2) {
          vs.unshift([coords[temp], coords[temp + 1]]);
          xmax = xmax > coords[temp] ? xmax : coords[temp];
          xmin = xmin > coords[temp] ? coords[temp] : xmin;
          ymax = ymax > coords[temp + 1] ? ymax : coords[temp + 1];
          ymin = ymin > coords[temp + 1] ? coords[temp + 1] : ymin;
        }
        // 计算 画布的高度
        c.height = ymax - ymin;
        // 计算 画布的宽度
        c.width = xmax - xmin;
        // 绘制多边形
        ctx.beginPath();
        ctx.moveTo(vs[0][0] - xmin, vs[0][1] - ymin);
        for (var m = 1; m < vs.length; m++) {
          ctx.lineTo(vs[m][0] - xmin, vs[m][1] - ymin);
        }
        ctx.closePath();
        // 设置阴影的div 的相对位置
        shadowDiv.style.top = ymin + "px";
        shadowDiv.style.left = xmin + "px";
      }
      // 根据 设置的阴影颜色来设置矩形的填充色
      ctx.fillStyle = this.shadowColor;
      ctx.fill();
    },
  },
};
</script>



把父组件调用的代码也贴一下 咱就结束了

<template>
  <div>
    <hotspotShadow
      shadowColor="rgba(0,100,200,0.5)"
      :openType="openType"
      :imgUrl="imgUrl"
      :areas="areas"
    ></hotspotShadow>
  </div>
</template>
<script >
import hotspotShadow from "./hotspot-shadow.vue";
export default {
  components: {
    hotspotShadow,
  },
  data() {
    return {
      openType: "self",
      imgUrl: require("../../assets/3.jpg"),
      areas: [
        {
          type: "circle",
          coord: "260,60,70",
          href: "http://www.baidu.com",
        },
        {
          type: "rect",
          coord: "23,145,393,345",
          href: "http://www.baidu.com",
        },
        {
          type: "rect",
          coord: "400,145,522,383",
          href: "http://www.baidu.com",
        },
        {
          type: "rect",
          coord: "23,345,393,532",
          href: "http://www.baidu.com",
        },
        {
          type: "rect",
          coord: "400,401,522,630",
          href: "http://www.baidu.com",
        },
        {
          type: "poly",
          coord: "23,535,393,535,393,630,522,636,522,765,23,765",
          href: "http://www.newlixon.com",
        },
      ],
    };
  },
};
</script>
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值