三先热力表格图

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

原型如图


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

经分析,表格左侧和底部标题都为维度,文章数量及对应文章标题为数值部分,所以需要两个维度,两个数值。为了容易控制,打算用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()
        },
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351

推荐阅读更多精彩内容