三先热力表格图

数据产品之热力表格图开发详解

原型如图


常规显示
点击文字后显示弹框

经分析,表格左侧和底部标题都为维度,文章数量及对应文章标题为数值部分,所以需要两个维度,两个数值。为了容易控制,打算用div+table的方式来渲染该图。

html部分

  <div  ref="chart" :style="chartStyle" style="height: auto; padding: 10px 0;font-size:1rem"> 
    <ul class="legendbox"><li v-for="(legend,i) in legendList" :key="legend"><span :style="{background:legendColor[i%23]}"></span>{{legend}}</li></ul>
    <section class="hotbox" style="max-height:100%; overflow:auto;">
        <table class="hotTable" style="font-size:12px">
            <thead>
                <tr><th>{{legendTitle}}</th><th :colspan="hotData.hotFoot.length" align="center">{{hotData.hotTitle}}</th></tr>
            </thead>
            <tfoot>
                <tr>
                    <td>{{footTitle}}</td><td v-for="item in hotData.hotFoot" :key="item">{{item}}</td>
                </tr>
            </tfoot>
            <tbody>
                <tr v-for="(legend,i) in legendList" :key="legend">
                    <td :style="{borderColor:legendColor[i%23]}">{{legend}}</td>
                    <template  v-for="(col,index) in hotData.hotList[i]">
                      <td :key="index" :style="{borderColor:col.value == '-'?'transparent':legendColor[i%23], background:col.value == '-'? 'rgba(239,239,239,0.4)':toRGB(legendColor[i%23]).replace('rgb', 'rgba').replace(')', ',.4)'),cursor:col.value == '-'?'default':'pointer'}" 
                          :class="(col.category == hotActive.category && col.project == hotActive.project)?'yuansu-active':''"
                           :data-category="col.category"  :data-project="col.project"
                           @click="overShow(col.category,col.project)"
                          >
                            <div class="area" v-if="col.value != '-'"> {{col.value}}</div>   
                            <div class="hot-tooltip" v-if="col.value != '-'">
                                <div class="hot-tooltip-close" @click="outHide($event)"></div>
                                <div class="hot-tooltip-conbox">
                                    <div class="hot-tooltip-title">{{col.project}} {{col.category}}</div>
                                    <!-- <div class="hot-tooltip-content">{{col.name}}:{{col.value}}</div> -->
                                </div>
                                <ul class="hot-tooltip-tipbox" v-if="col.tips && col.tips.data">
                                    <li v-for="(tip,k) in col.tips.data" :key="tip.count">
                                        <a :href="tip.url" target="_blank">{{k+1}}.{{tip.title}}</a><span>{{tip.count}}</span>
                                    </li>
                                </ul>
                            </div>                    
                      </td>                          
                    </template>
                </tr>
            </tbody>
        </table>
    </section>
  </div>

css部分

.hotTable td,.hotTable th{min-width: 220px; height:60px; padding: 2px;}
.hotTable td{border-left: 2px solid; text-align: center; position: relative;}
.hotTable tfoot td{border-left: 2px solid transparent;}
.hot-tooltip{display:none; position: absolute;  bottom: 20px;
    -webkit-transform: translateX(-50%);
            transform: translateX(-50%);
    width: 300px;
    padding: 8px 10px;
    line-height: 24px;
    background: rgba(0,0,0,0.6);
    color: #fff;
    border-radius: 3px;
    text-align: center;
    font-style: normal;
    z-index: 999;
    .hot-tooltip-close{position: absolute;
        right: 10px;
        top: 10px;
        height: 16px;
        width: 16px;
        cursor: pointer;}
    .hot-tooltip-close::before{content: '';
        display: block;
        position: absolute;
        height: 1px;
        width: 100%;
        background: #fff;
        top: 50%;
        transform: rotate(45deg);}
    .hot-tooltip-close::after{
            content: '';
            display: block;
            position: absolute;
            height: 1px;
            width: 100%;
            background: #fff;
            top: 50%;
            transform: rotate(-45deg);
    }
    .hot-tooltip-conbox{display: flex; justify-content: space-around; border-bottom: 1px solid #8c8c8c;padding-bottom: 5px;
    .hot-tooltip-tipbox{margin-top:10px}
    .hot-tooltip-tipbox a:hover{text-decoration: underline;}
  }
.yuansu-active .hot-tooltip{display: block;}
//.hotTable td .area{width: 60px;}
.legendbox{width: 100%; display: flex; justify-content: flex-end; align-items: center; flex-wrap: wrap; overflow-y: auto; max-height: 40px;}
.legendbox li{font-size: 14px; height: 50px; line-height: 50px; padding-right: 10px;}
.legendbox li span{display: inline-block; width: 26px; height: 14px; border-radius: 3px; margin-right: 3px; vertical-align: middle;}

js部分

import {defaultColor,toRGB} from '@/utils/chart/base/color'
export default {
          data() {
              return {
                   hotData:{
                         hotTitle:'',
                         hotFoot:[],
                         hotList:[]
                   },
                   legendList:[],
                   legendTitle:'',
                   footTitle:'',
                   showActive:false,
                   hotActive:{category:'',project:''},
                   legendColor:[]
              }
        },
        mounted() {
           this.renderChart(this.data)
       },
       methods: {
            toRGB(color){
                return toRGB(color)
            },
        renderChart(data) {
            if (!this.$refs.chart) return
            if (data.length == 0) {
                if (!this.chart) {
                    return
                }      
            }
            let hotTitle = ''
            let hotList = []
            let hotFoot = []
            let seriesObj ={}
            let legendList = []  //左侧名称数组
            let tipsList = []  //有提示框的时候,提示框的数据
            const dimensions = this.schema.filter(schema => schema.asxAxis) //维度
            const dataSchema = this.schema.filter(schema => !schema.asxAxis) //数值
            this.legendTitle = (dimensions && dimensions.length>=2)?dimensions[1].detail.alias:''
            this.footTitle = (dimensions && dimensions.length>=1)?dimensions[0].detail.alias:''
            data.forEach((item, i) => {
                legendList.push(item[dimensions[1].name])
            })
            legendList = Array.from(new Set(legendList))
            dataSchema.forEach((schema, index) => {
                seriesObj[schema.name] = {
                    name: schema.label || schema.detail.alias,
                    term: schema.name,
                    projectList:[]}
            })
            
            data.forEach((item,index) =>{
              hotFoot.push(item[dimensions[0].name])
              hotList.push([])

              dataSchema.forEach((schema, i) => {
                legendList.forEach((lege, m) => {
                    var itlt = {
                        name:  schema.detail.alias,
                        project:lege,
                        category:  item[dimensions[0].name],
                        value: item[schema.name]
                    }
                    if(item[dimensions[1].name] == lege){
                        seriesObj[schema.name].projectList.push(itlt)
                    }                   
                    })
              })
      })
      let newHotList = Object.values(seriesObj);
      let newLegendList = []
      hotFoot = Array.from(new Set(hotFoot))
      let selectList = []
      if(this.dispose.barQuota == ''){
             hotTitle = newHotList[0].name;
             selectList = newHotList[0].projectList
      }else{
         newHotList.forEach((hot,i) => {
            if (this.dispose.barQuota !='' && hot.term == this.dispose.barQuota){
                hotTitle = hot.name;
                selectList = hot.projectList
            }
      })
      }
      if(this.dispose.chooseIndex){
        newHotList.forEach((hot,i) => {
            if (hot.term == this.dispose.chooseIndex){
                tipsList = hot.projectList
            }
        })        
      }
       legendList.forEach((lege, m) => {
           let newArr=[]
           selectList.forEach((item,n) => {               
                if(lege === item.project){
                    if(this.dispose.chooseIndex){
                        item['tips'] = JSON.parse(tipsList[n].value)
                    }
                   // console.log(item,'item')
                    newArr.push(item)
                }    
          })
            newLegendList.push(newArr) //首页将数据组装到newLegendList二维数组
        })
        
        let dataArr=[]
        let hotFoot1 = JSON.parse(JSON.stringify(hotFoot))
        newLegendList.forEach((item)=>{
           dataArr.push(hotFoot1)
        })

        let hotListArray = JSON.parse(JSON.stringify(dataArr))
        for(let i = 0; i< newLegendList.length;i++){   //使用两个for循环遍历矩阵
            for(let j = 0; j < hotFoot.length; j++){
             let flag = newLegendList[i].find((item) => {return item.category == hotFoot[j]})
             if(flag){
                 hotListArray[i][j] = { 
                     name:flag.name,
                     category: flag.category,   
                     project:flag.project,
                     value:flag.value,
                     tips:flag.tips? flag.tips:null
                     }
             }
             else{
                 hotListArray[i][j] = { 
                     name:newLegendList[i][0].name,
                     category: hotFoot[j],   
                     project:legendList[i],
                     value:'-'}
             }
            }
        }
      this.hotData.hotTitle = hotTitle
      this.hotData.hotFoot =  hotFoot
      this.hotData.hotList = hotListArray
      this.legendList =legendList
      this.legendColor = defaultColor
        },
        overShow(a,b){
            this.hotActive.category = a
            this.hotActive.project = b
        },
        outHide(e){
            let that = this;
            that.hotActive.category = '',
            that.hotActive.project = '',
            e.stopPropagation()
        },
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容