vue3实现活跃度(热力图)

14 篇文章 1 订阅
5 篇文章 0 订阅

在项目开发中遇到一个需求,制作一个展示一年信息的活跃度图,也就是热力图,如图:

 1.制作右上角的方格标识

<a-row>
    <a-col :span="1" :offset="19">
        <div style="height: 13px;"></div>
        <div>少</div>
    </a-col>
    <a-col :span="2">
      <div>
        <ul class="graph" style="border: 0;grid-template-rows: repeat(1, 15px)">
          <li :data-level="level0"  class="li-day"></li>
          <li :data-level="level1"  class="li-day"></li>
          <li :data-level="level2"  class="li-day"></li>
          <li :data-level="level3"  class="li-day"></li>
        </ul>
      </div>
    </a-col>
    <a-col :span="1">
      <div style="height: 13px;"></div>
      <div>多</div>
    </a-col>
</a-row>

2.制作热力图

<div class="container-card">
    <a-row>
      <a-col :span="2">
        <ul style="list-style: none;margin: 20px 0px 5px 0px;line-height: 15px">
          <li style="font-size: 13px">周日</li>
          <li>&nbsp;</li>
          <li>&nbsp;</li>
          <li style="font-size: 13px">周三</li>
          <li>&nbsp;</li>
          <li>&nbsp;</li>
          <li style="font-size: 13px">周六</li>
        </ul>
      </a-col>
      <a-col :span="22">
        <ul class="graph">
          <!-- 热力图左边的空格,去年的今天以前的日期不显示,没有格子 -->  
          <li v-for="n in today" style="background-color: white;list-style: none;margin: 1.5px;">&nbsp;</li>

          <a-popover class="item"
                     placement="top" v-for="(item, index) in infos" :key="index" >
            <template #content>
              {{item.year + '-' + item.month + '-' + item.date}}
            </template>
            <li :data-level="item.level"  class="li-day" ></li>
          </a-popover>
        </ul>
        <ul class="months">
          <!-- 热力图下面的月份 -->
          <li class="li-month" v-for="(item,index) in monthBar" :key="index">{{item}}</li>
        </ul><br>
      </a-col>
    </a-row> 
</div>

3.热力图需要的数据

const state = reactive({
    infos: [],  //存放365天每一天的数据(year,month,date,状态数量,isToday标记)
    current: {  //存放今天的年月日
      year: "",
      month: "",
      date: "",
    },
    level0: 0,     //等级1
    level1: 1,     //等级2
    level2: 2,     //等级3
    level3: 3,     //等级4
    today: 0,
    monthBar: ["", "", "", "", "", "", "", "", "","",
        "", "", "", "", "", "", "", "", "","",
        "", "", "", "", "", "", "", "", "","",
        "", "", "", "", "", "", "", "", "","",
        "", "", "", "", "", "", "", "", "","",
        "","",
    ],
})

4.判断传回的数值对应的等级

const judgeLevel = function (num){
  if (num === 0){
     return "0"
  }
  if (num>0&&num<=100){
    return "1"
  }
  if (num>100&&num<=200){
    return "2"
  }
  if (num>200&&num<=300){
    return "3"
  }
}

5.渲染数据(先渲染出来365天的空数据,然后判断遍历的天数是否为后端传回的数据中的天数,如果是,则替换掉原来的空数据。因为这里用到了字符串的截取,1-9月和10-12月截取的位置不一样,所以判断两次)

 const activeNumber = function (){
    let d = new Date();                    //

    let day = d.getDay();           //获取今天所在星期,以进行后续计算    5
    let today = d.getDate();        //获取今天的日数                   3
    // console.log(day)

    state.today = day

    state.current.year = d.getFullYear();   //初始化今日的年月日    2022
    state.current.month = d.getMonth();     //   8
    state.current.date = d.getDate();

    const dataLists =[                  //模拟后端接收到的数据
      {day: '2021-10-20',number: 200},
      {day: "2022-9-20",number: 300},
      {day: "2022-9-21",number: 100},
      {day: '2022-8-10',number: 150},
      {day: "2022-9-2",number: 50},
      {day: "2022-9-23",number: 150},
    ]

    let info = {};         //用来存放某一天的数据对象(年月日、isToday、level)
    let month = "";        //后续计算某月第一天在哪一列用,表示第几月
    let weekOfMonth = ""   //后续计算某月第一天在哪一列用,表示第几列

    for (let i = 0; i < 365; i++) {
      d.setFullYear(state.current.year);  //每次循环要重置年月日为今天否则会以上次循环结尾的年月日计算而计算错误
      d.setMonth(state.current.month);
      d.setDate(state.current.date);
      d.setDate(today - 364 + i);

      info = {
        year: d.getFullYear(),
        month: d.getMonth() + 1,
        date: d.getDate(),
        number: 0,
        level: 0,
        isToday: false,
      };
      state.infos.push(info);      //渲染上365天的空数据

      for(let j = 0;j < dataLists.length;j++){
        //判断遍历到的天数是否和后端传回的数据对应(0-9月份)
        if (d.getMonth()+1 == dataLists[j].day.substr(5,1)&&d.getDate() == dataLists[j].day.substr(7,2)){
            state.infos[i] = {                      //每个格子(天)的info对象
              year: d.getFullYear(),      //年月日
              month: d.getMonth() + 1,
              date: d.getDate(),
              number: dataLists[j].number,    //今日的数据量
              level: judgeLevel(dataLists[j].number),  //今日数据量对应的等级
              isToday: false, //是否是今天
            };
        //判断遍历到的天数是否和后端传回的数据对应(10-12月份)
        }else if(d.getMonth()+1 == dataLists[j].day.substr(5,2)&&d.getDate() == dataLists[j].day.substr(8,2)){
            state.infos[i] = {                      //每个格子(天)的info对象
              year: d.getFullYear(),      //年月日
              month: d.getMonth() + 1,
              date: d.getDate(),
              number: dataLists[j].number,    //今日的数据量
              level: judgeLevel(dataLists[j].number),  //今日数据量对应的等级
              isToday: false, //是否是今天
           };
        }
      }

      // // 判断每月第一天在12列种的哪一列
      if (d.getDate() === 1) { //date为1的肯定是某月第一天
        month = d.getMonth() + 1  //获取这一天对应的月份(0-11,所以还要+1)
        weekOfMonth = parseInt((i + 1) / 7)  //这个月的第一天的index(84天的第几天)除以7获得所在列的index(12列的第几列),作为下面monthBar的index,并把原来空的内容用替换为xx月
        state.monthBar[weekOfMonth] = month + "月"
      }
    }
};

6.CSS样式



.graph {
  display: grid;
  grid-template-columns: repeat(53, 15px);  /*竖向53列,21px宽*/
  grid-template-rows: repeat(7, 15px);     /*横向7列,21px宽*/
  padding-inline-start: 0px;
  grid-auto-flow: column;               /*生成7*53的格子后,设置为竖向排布*/
  margin: 20px 0px 5px 0px;
}

.months {
  display: grid;
  grid-template-columns: repeat(52, 15px);
  grid-template-rows: 21px;
  font-size: 8px;
  color: #aaa;
  padding-inline-start: 0px;
  margin: 5px 20px 5px 0px;
}

.li-month {
  display: inline-block;
}

.li-day {
  background-color: #eaeaea;
  list-style: none;             /*记得把list的圆点效果去掉*/
  margin: 1.5px;
  border-radius: 3px;
}

.li-day:hover {               /*添加hover强调效果*/
  box-shadow: 0px 0px 5px rgb(57, 120, 255);
}
.graph li[data-level="1"],.level1 {
  background-color: #d9ecff;
}

.graph li[data-level="2"],.level2 {
  background-color: #8cc5ff;
}

.graph li[data-level="3"],.level3 {
  background-color: #409eff;
}

src/views/activeNum.vue · 马飞祥/work1 - 码云 - 开源中国 (gitee.com)https://gitee.com/ma-feixiang/work1/blob/master/src/views/activeNum.vue

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要在Vue框架中实现天地图热力图,可以使用天地图的API和第三方的热力图插件。 首先,需要在Vue项目中引入天地图的API,可以通过在index.html中添加以下代码来引入: ```html <script src="http://api.tianditu.gov.cn/api?v=4.0&tk=yourkey"></script> ``` 其中,yourkey需要替换为你在天地图申请的API key。 接下来,可以使用第三方的热力图插件来实现热力图的功能,比如heatmap.js。可以通过npm安装heatmap.js: ```bash npm install heatmap.js ``` 然后,在Vue组件中引入heatmap.js并使用它来生成热力图。以下是一个简单的示例: ```html <template> <div id="map"></div> </template> <script> import heatmap from 'heatmap.js' export default { mounted() { // 创建地图 const map = new T.Map('map') map.centerAndZoom(new T.LngLat(116.4074, 39.9042), 10) // 加载热力图数据 const data = [ { lng: 116.4074, lat: 39.9042, count: 10 }, { lng: 116.3739, lat: 39.9236, count: 20 }, { lng: 116.3575, lat: 39.9119, count: 30 }, // ... ] // 将数据转换为热力图需要的格式 const points = data.map(item => ({ lnglat: new T.LngLat(item.lng, item.lat), count: item.count })) // 创建热力图 const heatmapInstance = heatmap.create({ container: document.getElementById('map'), radius: 20, maxOpacity: .5, data: points }) } } </script> ``` 在这个示例中,我们首先创建了一个地图实例,然后加载了热力图的数据。将数据转换为heatmap.js需要的格式后,我们创建了一个热力图实例,并将它渲染在地图上。 当然,这只是一个简单的示例,你可以根据实际需求来配置热力图的参数,比如半径、透明度等。同时,也可以根据天地图提供的API来添加其他的地图功能,比如地图控件、标注等。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值