echarts relationship call highlight example dispatchAction and the problems encountered

as the picture shows

insert image description here

<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>

ok too much the key is to watch this

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

problems encountered

What problem did you encounter? I clicked on the corresponding entity but highlighted others

problem causes

The index of switchHigh corresponds to the wrong one. Click Wang Er to pass the index of Wang Er

Solution

Because the list on the right of me filters out the physical phones, companies, and addresses of people in the list on the left, and then switchHigh transmits the index of the left list, which is wrong. The index corresponding to the list of graph data should be transmitted.

Because the order of people and objects in the data of the chartList array passed to the map is messy, but I extracted all the people and gave it to the left.

So I processed the chartList array and put the people in the front and the things in the back

 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]

solved

I just record this question to explain where the index of switchHigh comes from

Guess you like

Origin blog.csdn.net/weixin_44582045/article/details/129809773