echarts 关系调用高亮示例 dispatchAction及其遇到的问题

如图所示

在这里插入图片描述

<template>
  <div class="Chart">
    <div class="main_box">
      <div class="diagram_box" v-if="activeChart === 'diagram'">
        <div class="drawer">
          <drawer
            :drawer.sync="drawer"
            :cusStyle="{ top: '10px'}"
            :drawerTop="{width:imgWidth,height:'5px'}"
            width="424px"
            oldLeft="-5px"
            :moveLeft="moveLeft"
            @handleClick="DrawerHandleClick"
          >
            <div class="main_box">
              <div class="content_box" v-for="(item,index) in labelList" :key="index" @click="clickLabel(index)"> // 点击左侧
                <div :class="['content',{
     
     'selected': item[0].isSelect}]">
                  <div class="icon">
                    <img :src="origin + iconObj[item[0].value]['icon_path']" alt="">
                  </div>
                  <div class="info_box">
                    <div v-for="(e,i) in item" :key="i">
                      <div class="info" v-if="!e.isIcon">
                        <div class="label">{
   
   {e.label + ':'}}</div>
                        <div class="value" v-if="e.label_en === 'avatar_url' || e.label_en === 'car_image'">
                          <el-image
                            :src="origin + e.value"
                            fit="cover"
                          >
                            <div slot="error" class="image-slot">
                              <img :src="errImg" />
                            </div>
                          </el-image>
                        </div>
                        <div class="value" v-else>{
   
   {e.value}}</div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
            <div class="total">
              <span>总数:</span>
              <span>{
   
   { labelList.length }}</span>
            </div>
          </drawer>
        </div>
        <Loading :isLoading.sync="isLoading">
          <Diagram
            ref="charts"
            v-if="chartList.length"
            :id="id"
            :bgColor="chartsBg"
            :chartList="chartList"
            @handleDbClick="handleDbClick"
            @updateData="updateData"
          />
          <div class="empty_div" v-else>
            <EmptyData />
          </div>
        </Loading>
      </div>
    </div>
  </div>
</template>

 // 点击左侧信息
clickLabel (index) {
 this.labelList.forEach(item => {
   item[0].isSelect = false
 })
 this.labelList[index][0].isSelect = true
 this.$refs.charts.switchHigh(index,1)
}
<template>
  <div :id="id" class="chart"></div>
</template>
<script>
import {
    
     colors} from './mock'
import {
    
     lightTheme, darkTheme } from "@/assets/js/variable";
import {
    
     mapState } from 'vuex';
// import { getEntityIcon } from '@/api/analysis'
// import { mapGetters } from 'vuex'
import * as echarts from 'echarts'
export default {
    
    
  name: 'Charts',
  props: {
    
    
    id: {
    
    
      type: String
    },
    chartList: {
    
    
      type: Array
    },
    bgColor: {
    
     // 图谱背景色
      type: String
    }
  },

  data () {
    
    
    return {
    
    
      myChart: null,
      seriesData: [],
      seriesLinks: [],
      seriesCategories: [],
      cerTypeObj: {
    
    
        attr_identity_card_type: '身份证',
        attr_passport_type: '护照',
        attr_hk_permit_type: '港澳通行证'
      },
      option: {
    
    }
      // iconObj: {}
    }
  },

  computed: {
    
    
    ...mapState('User', {
    
    
      theme: 'theme'
    }),
    ...mapState('Common', {
    
    
      iconObj: 'iconObj',
      usefulRelationTypeListMap: 'usefulRelationTypeListMap',
      usefulRelationTypeList: 'usefulRelationTypeList',
      dataTypeObj:'dataTypeObj'
    }),
    origin () {
    
    
      return window.location.origin + '/'
    }
  },

  watch: {
    
    
    chartList: {
    
    
      handler (val) {
    
    
        if (!val.length) return
        this.myChart && this.myChart.dispose()
        this.myChart = null
        this.formatData(val)
      },
      immediate: true, //关键
      deep: true
    },
    theme: {
    
    
      handler () {
    
    
        // console.log(this.myChart);
        if (this.myChart) {
    
    
          // console.log(this.option);
          // console.log('执行了');
          // this.myChart.setOption(this.option)
          this.formatData(this.chartList)
        }
      },
      immediate: true
    }
  },
  created () {
    
    
    // console.log(this.theme);
  },

  methods: {
    
    
    // 数据格式化
    formatData (list) {
    
    
      // 存在类别 赋值
      this.seriesCategories = this.formatCates(list[0])
      const sArr =
        list[1]?.map(_c => {
    
    
          return {
    
     source: _c.src + '', target: _c.dst + '', dataRelationShipName: this.dataTypeObj[_c.data_source], personRelationShipName: _c.relationship, ..._c }
        }) ?? []
      this.seriesLinks = sArr.filter((element, index, self) => {
    
    
        return self.findIndex(x => x.vid === element.vid) === index
      })
      // const typeImgsMapOBJ = { ...typeImgsMap }
      const nArr =
        list[0]?.map(_c => {
    
    
          if (_c.type !== 'entity_person') {
    
     // 给name赋值  默认在实体上显示
            _c.name = _c.main_prop_val
          }

          _c.category = this.seriesCategories.findIndex(
            ele => ele.name === this.usefulRelationTypeListMap[_c.type]
          )
          _c.symbolSize = 38
          // console.log(_c.type,this.iconObj[_c.type])
          _c.symbol = this.iconObj[_c.type]['icon_path'] ? 'image://' + this.origin + this.iconObj[_c.type]['icon_path'] : require(`@/assets/img/atlis-default.png`)

          _c.id = _c.vid
          return _c
        }) ?? []
      // 不可有重复name否则会报错
      this.seriesData = nArr.filter((element, index, self) => {
    
    
        return self.findIndex(x => x.vid === element.vid) === index
      })
      // this.seriesData = nArr

      this.$nextTick(() => {
    
    
        this.initCharts()
      })
    },

    // 处理显示类别为有数据的类别
    formatCates (list) {
    
    
      const nameList = list.map(_c => this.usefulRelationTypeListMap[_c.type])
      const uniqueArr = [...new Set(nameList)]
      // console.log(uniqueArr)
      // 将人员放在数组首项
      // const index = uniqueArr.findIndex(_c => _c === '人员')
      // if (index !== -1) {
    
    
      //   const personItem = uniqueArr.splice(index, 1)
      //   uniqueArr.unshift(personItem[0])
      // }

      return uniqueArr.map(_c => {
    
    
        return {
    
     name: _c }
      })
    },

    /**
     * 设置echarts配置项,重绘画布
     */
    initCharts () {
    
    
      const _this = this

      if (!this.myChart) {
    
    
        this.myChart = echarts.init(document.getElementById(this.id))

        this.myChart.off('legendselectchanged') //解决重复触发
        // this.myChart.off('click') //解决重复触发
        // this.myChart.getZr()?.off('click') //解决重复触发

        // this.myChart.on('click', params => {
    
    
        //   console.log(params);
        //   if (params.dataType === 'node') {
    
    
        //     this.$emit('handleClickNode', params.data)
        //   } else if (params.dataType === 'edge') {
    
    
        //     this.$emit('handleClickEdge', params.data)
        //   }
        // })
        // 双击事件
        this.myChart.on('dblClick', params => {
    
    
          // console.log('双击事件',params)
          this.$emit('handleDbClick', params.data)
        })
        // 点击
        this.myChart.on('click', params => {
    
    
          // if (!params.target) {
    
    
          //   this.$emit('handleClickOut')
          // }
          // console.log('单击事件',params)
          if (params.dataType === 'edge') {
    
    
            this.$emit('clickEdge', params)
          }
        })

        this.myChart.on('legendselectchanged', e => {
    
    
          const {
    
     selected } = e
          let {
    
     legend } = _this.myChart.getOption()
          for(let key in selected) {
    
    
            legend[0].data.forEach(item => {
    
    
              if (selected[key]) {
    
    
                if (item.name === key) {
    
    
                  item.itemStyle.opacity = 1
                  item.textStyle.opacity = 1
                }
              } else {
    
    
                if (item.name === key) {
    
    
                  item.itemStyle.opacity = 0.2
                  item.textStyle.opacity = 0.2
                }
              }
            })
          }
          const option = {
    
     ..._this.myChart.getOption(), legend }
          _this.myChart.setOption(option)
        })

        this.myChart.on('mousedown', e => {
    
    
          if (e.dataType === "edge") {
    
     return }
          let {
    
     tooltip } = _this.myChart.getOption()
          tooltip[0].trigger = 'none'
          const option = {
    
     ..._this.myChart.getOption(), tooltip }
          _this.myChart.setOption(option)
        })
        this.myChart.on('globalout', () => {
    
    
          let {
    
     tooltip } = _this.myChart.getOption()
          tooltip[0].trigger = 'item'
          const option = {
    
     ..._this.myChart.getOption(), tooltip }
          setTimeout(() => {
    
    
            _this.myChart.setOption(option)
          }, 20)
        })
        this.myChart.on('mouseup', () => {
    
    
          let {
    
     tooltip } = _this.myChart.getOption()
          tooltip[0].trigger = 'item'
          const option = {
    
     ..._this.myChart.getOption(), tooltip }
          setTimeout(() => {
    
    
            _this.myChart.setOption(option)
          }, 20)
        })
      }

      // 颜色不能写死,需要写变量对应
      let colorObj = this.theme === 'light' ? lightTheme : darkTheme

      // 指定图表的配置项和数据
      this.option = {
    
    
        backgroundColor: this.bgColor,
        // 提示框的配置
        tooltip: {
    
    
          // backgroundColor: 'rgba(40, 50, 71,.9)',
          backgroundColor: colorObj['--tooltip-bg-262D44-to-f6f8fd'],
          borderWidth: 0,
          enterable: true,
          position: 'right',
          hideDelay: 10,
          // transitionDuration:'2',
          textStyle: {
    
    
            //默认值,
            color: colorObj['--base-text-color-to-666666'], //默认值各异,
            fontSize: 16 //默认值,
          },
          padding: 10,
          formatter: params => {
    
    
            {
    
    
              // 关系线的提示
              if (params.dataType === 'edge') {
    
    
                // return params.data.dataRelationShipName
                return
              }

              if (params.data.type === 'entity_person' || params.data.type === 'entity_certificate') {
    
    
                const imgUrl = params.data.avatar_url
                  ? window.location.origin + '/' + params.data.avatar_url
                  : this.theme === 'light' ? require('@/assets/img/icon-morenHeader-light.png') : require('@/assets/img/icon-morenHeader.png')

                return `
                <div style="display:flex;color: ${
      
      colorObj['--base-text-color-to-999999']};">
                    <img style="height:90px;width:75px;" src="${
      
      imgUrl}"" />
                    <div style="margin-left:8px;">
                      <div style="display:flex">
                        <div style="font-size:14px;width:75px;">姓名:</div>
                        <div>
                          ${
      
      params.data.name || '--'}
                        </div>
                      </div>
                      <div style="display:flex">
                        <div style="font-size:14px;width:75px;">性别:</div>
                        <div>
                          ${
      
      this.getSex(params.data)}
                        </div>
                      </div>
                      <div style="display:flex">
                        <div style="font-size:14px;width:75px;">民族:</div>
                        <div>
                          ${
      
      params.data.nation || '--'}
                        </div>
                      </div>
                      <div style="display:flex">
                        <div style="font-size:14px;width:75px;">出生日期:</div>
                        <div>
                          ${
      
      this.getBirthday(params.data)}
                        </div>
                      </div>
                    </div>
                </div>
                <div style="margin-top:0px;color: ${
      
      colorObj['--base-text-color-to-999999']};">
                  <div>
                    <div style="display:flex">
                      <div style="width:75px;font-size:14px;">${
      
      this.getCerType(params.data)}</div>
                      <div>${
      
      params.data.cer_number || '--'}</div>
                    </div>
                  <div>
                  <div>
                    <span style="font-size:14px;">户籍地址:</span>
                    <span>${
      
      params.data.registered_address || '--'}</span>
                  </div>
                </div>
                `
              } else if (params.data.type === 'entity_mobile_phone') {
    
    
                return `
                  <div style="color: ${
      
      colorObj['--base-text-color-to-999999']}">
                    <span style="font-size:14px;">IMEI:</span>
                    <span>${
      
      params.data.imei || '--'}</span>
                  </div>
                `
              } else if (params.data.type === 'entity_phone_card') {
    
    
                return `
                  <div style="color: ${
      
      colorObj['--base-text-color-to-999999']}">
                    <span style="font-size:14px;">手机号:</span>
                    <span>${
      
      params.data.main_prop_val || '--'}</span>
                  </div>
                  <div style="color: ${
      
      colorObj['--base-text-color-to-999999']}">
                    <span style="font-size:14px;">IMSI:</span>
                    <span>${
      
      params.data.imsi || '--'}</span>
                  </div>
                `
              } else {
    
    
                let list = []
                for(let key in params.data) {
    
    
                  this.iconObj[params.data.type].fields.forEach(item => {
    
    
                    if (key === item.label_name_en && params.data[key]) {
    
    
                      if (key.indexOf('_image') !== -1) {
    
    
                        list.push({
    
    
                          label: item.label_name_cn,
                          value: params.data[key],
                          isImage: true
                        })
                      } else {
    
    
                        list.push({
    
    
                          label: item.label_name_cn,
                          value: params.data[key],
                          isImage: false
                        })
                      }
                    }
                  })
                }
                return `
                  <ul>
                      ${
      
      list.map(item => {
      
      
                        if (item.isImage) {
      
      
                          return `
                            <li style="color: ${ 
        colorObj['--base-text-color-to-999999']}">
                              <span style="font-size:14px;">${ 
        item.label + ':'}</span>
                              <img style="height:75px;width:100px;" src="${ 
        window.location.origin + '/' + item.value}" />
                            </li>
                          `
                        } else {
      
      
                          return `
                            <li style="color: ${ 
        colorObj['--base-text-color-to-999999']}">
                              <span style="font-size:14px;">${ 
        item.label + ':'}</span>
                              <span>${ 
        item.value || '--'}</span>
                            </li>
                          `
                        }
                }).join('')}
                  </ul>
                `
              }
            }
          }
        },
        // 类目color
        color: colors,
        // 类目数组
        legend: [
          {
    
    
            // data: [],
            data: this.chartList[0].map(_c => {
    
    
              return {
    
    
                name: this.iconObj[_c.type]['entity_name_cn'],
                icon: this.iconObj[_c.type]['icon_path'] ? 'image://' + this.origin + this.iconObj[_c.type]['icon_path'] : require(`@/assets/img/atlis-default.png`),
                itemStyle: {
    
    
                  opacity: 1
                },
                textStyle: {
    
    
                  opacity: 1
                }
              }
            }),
            x: 'right',
            y: 'bottom',
            itemWidth: 24,
            itemHeight: 24,
            textStyle: {
    
    
              // color: 'rgba(174, 189, 212,0.9)',
              color: colorObj['--base-text-color-to-666666'],
              fontSize: 12
            }
          }
        ],
        series: [
          {
    
    
            type: 'graph', // 类型:关系图
            top: '10%', // 图表距离容器顶部的距离
            // zoom: 1,
            layout: 'force', //图的布局,类型为力导图
            legendHoverLink: false, //是否启用图例 hover(悬停) 时的联动高亮。
            edgeSymbol: ['circle', 'arrow'],
            edgeSymbolSize: [2, 8], // 两端大小
            force: {
    
    
              edgeLength: 300, // 两个节点之间的距离
              repulsion: 1000, //节点之间的斥力因子值
              friction: 0.2, // 节点的移动速度 取值0~1
            },
            roam: true, //是否开启鼠标缩放和平移漫游。默认不开启。如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move'。设置成 true 为都开启
            draggable: true, //每个节点的拖拉
            // 关系线样式lineStyle
            lineStyle: {
    
    
              show: true,
              width: 1,
              // color: '#8799BF', //决定边的颜色是与起点相同还是与终点相同 可选'target'
              color: colorObj['--base-text-color-to-999999'], //决定边的颜色是与起点相同还是与终点相同 可选'target'
              // curveness: 0.1 // 边的曲度,支持从 0 到 1 的值,值越大曲度越大。
            },
            autoCurveness:true,
            //图形上的文本标签,可用于说明图形的一些数据信息
            label: {
    
    
              //标签的字体样式
              // color: '#c0d0e7', //字体颜色
              color: colorObj['--base-text-color-1'], //字体颜色
              fontStyle: 'normal', //文字字体的风格 'normal'标准 'italic'斜体 'oblique' 倾斜
              fontWeight: 'bolder', //'normal'标准'bold'粗的'bolder'更粗的'lighter'更细的或100 | 200 | 300 | 400...
              fontFamily: 'sans-serif', //文字的字体系列
              fontSize: 12, //字体大小
              show: true, //显示
              position: 'top', //相对于节点标签的位置,默认在节点中间
              //回调函数,你期望节点标签上显示什么
              formatter: function (params) {
    
    
                // 对手机号特殊处理,标签上优先取手机号,没有则依次取值
                if (params.data.type === 'entity_probe_phone') {
    
    
                  return params.data.phone || params.data.imei || params.data.imsi
                } else {
    
    
                  return params.name
                }
              }
            },
            edgeLabel: {
    
    
              position: 'middle', // 标签位置 线的中点
              show: true,
              fontSize: 12,
              color:  colorObj['--base-text-color-to-666666'],
              formatter: x => {
    
    
                if (x.data.relationship) {
    
    
                  return x.data.relationship + '(' + x.data.dataRelationShipName + x.data.rank + '次)'
                } else {
    
    
                  return (
                    this.getVertexName(x.data.dst.split('-')[0]) +
                    '(' +
                    x.data.dataRelationShipName + x.data.rank +
                    '次)' || ''
                  )
                }
              }
            },
            emphasis: {
    
    
              scale: true, //是否开启鼠标悬停节点的显示动画
              lineStyle: {
    
    
                width: 2
              },
              shadowColor: '#00FAE1',
              shadowOffsetX: 0,
              shadowOffsetY: 0,
              shadowBlur: 40,
              focus: 'adjacency'
            },
            symbolSize: 5, //节点大小
            categories: this.seriesCategories,
            links: this.seriesLinks,
            data: this.seriesData,
            cursor: 'pointer',
            nodeStyle: {
    
    
              brushType: 'both',
              borderColor: 'rgba(255,215,0,0.4)',
              borderWidth: 1
            }
          }
        ],
        // 动画更新变化时间
        animationDurationUpdate: 100, //数据更新动画的时长。[ default: 300 ]
        // animationDurationUpdate: 200, //数据更新动画的时长。[ default: 300 ]
        animationEasingUpdate: 'quinticInOut'  数据更新动画的缓动效果。[ default: cubicOut ]    "quinticInOut"
      }

      // 使用刚指定的配置项和数据显示图表。
      this.myChart.setOption(this.option,true)
      let model  = this.myChart.getModel().getSeriesByIndex(0).getData()._itemLayouts;
      this.$emit('updateData',model)
    },

    switchHigh (index, name) {
    
    
      // console.log(index,name)
      this.myChart.dispatchAction({
    
    
        type: 'highlight',
        seriesIndex: 0,
        dataIndex: index,
        name: name
      })
    },
    // 通过身份证获取性别
    getSex (data) {
    
    
      // console.log(data)
      // return data.gender
      if (data.gender === '' || data.gender == null) {
    
    
        if (data.cer_type === 'attr_identity_card_type') {
    
    
          if (parseInt(data.cer_number.substr(16, 1)) % 2 === 1) {
    
    
            return "男"
          } else {
    
    
            return "女"
          }
        } else {
    
    
          return '--'
        }
      } else {
    
    
        if (data.gender === 'female' || data.gender === '女') {
    
    
          return '女'
        } else if (data.gender === 'male' || data.gender === '男') {
    
    
          return '男'
        } else {
    
    
          // return '--'
          return data.gender
        }
      }
    },
    // 通过身份证号获取出生日期
    getBirthday (data) {
    
    
      if (data.birthday === '' || data.birthday == null) {
    
    
        if (data.cer_type === 'attr_identity_card_type') {
    
    
          return data.cer_number.substring(6, 10) + "/" + data.cer_number.substring(10, 12) + "/" + data.cer_number.substring(12, 14)
        } else {
    
    
          return '--'
        }
      } else {
    
    
        return data.birthday
      }
    },
    getCerType (data) {
    
    
      if (data.cer_type === 'attr_hk_permit_type') {
    
    
        return '港澳通行证:'
      } else if (data.cer_type === 'attr_passport_type') {
    
    
        return '护照:'
      } else if (data.cer_type === 'attr_identity_card_type') {
    
    
        return '身份证:'
      } else {
    
    
        return '未知证件:'
      }
    },
    getVertexName (data) {
    
    
      return this.iconObj[data]['entity_name_cn']
    }
  }
}
</script>
<style scoped>
.cusEchart-label {
    
    
  width: 500px;
}
</style>

好吧 太多了 关键是看这个

switchHigh (index, name) {
    
    
  // console.log(index,name)
  this.myChart.dispatchAction({
    
    
    type: 'highlight',
    seriesIndex: 0,
    dataIndex: index,
    name: name // 感觉传这个name没什么用 注释都行  
  })
},

遇到的问题

遇到了什么问题呢 就是 点击对应的实体 但是高亮了别的 如图 点击了 王二 但是却高亮了手机

问题原因

switchHigh 的index对应错了 点击王二 就需要传王二的index

解决方法

因为我右边的列表 是过滤了关于人的实体 手机阿 公司阿 地址阿 都不在左边的列表里面 然后 switchHigh 传的就是左边列表的index 这样就错了 应该传图谱数据的列表对应的index

因为传给图谱的chartList数组的数据里面有人有物 顺序是乱的 但是我把人的全部提取出来给了左边

所以我就把chartList数组处理了下 把人的排在前面 物在后面

 let peopleList =  vertex.filter(item => item.type === 'entity_person')
 let thingList = vertex.filter(item => item.type !== 'entity_person')
 let newVertexList = peopleList.concat(thingList)
 this.chartList = [newVertexList, edge]

解决了

我只是记录这个问题 说明switchHigh 的index来自哪里

猜你喜欢

转载自blog.csdn.net/weixin_44582045/article/details/129809773