echart悬浮窗可点击

91 阅读2分钟
//点击函数挂在window上
function myalert(val) {
  var obj = JSON.parse(val);
  console.log(12121, obj);
}
window.myalert = myalert;
//以下是tooltip配置,部分判断语句是本公司业务需要,可自行删除
  tooltip: {
        trigger: 'axis',
        triggerOn: 'click',//点击显示
        enterable: true,//可以进入
        formatter: function (params) {
          let returnData = '';
          if (params.length == 1) {
            returnData = params[0].name + ':' + params[0].value;
          } else {
            returnData = params[0].name + '</br>';
            for (let i = 0; i < params.length; i++) {
              if (params[i].seriesName === 'traceId') {
                continue;
              }
              let indexColor = params[i].color;
              returnData += '<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background:' + indexColor + '"></span>';
              returnData += params[i].seriesName + ':' + params[i].value + '</br>';
            }
          }
          /* avg/p99展示跳转链接 */
          if (params[0].seriesName === ('avgValue' || 'p99Value')) {
            const val = {
              name: params[params.length - 1].name,
              value: params[params.length - 1].value,
            };
            return (
              returnData +
              '<hr style="border:1 dashed #987cb9;" width="98%" size=5><div onclick="myalert(\'' +
              JSON.stringify(val).replace(/"/g, '&quot;') +
              '\')" style="color:#000;text-decoration: none" id="btn-tooltip">详情></div>'
            );
          } else {
            return returnData;
          }
        },
      },

封装了一个initCharts

如果需要点击折线点之后调接口再渲染浮层,上面的代码便行不通了,只能用echart提供的点击事件+js实现,一下代码通用性不高,仅提供思路

import moment from 'moment';
import api from '@/api/map';
import * as echarts from 'echarts';
class Option {
  tooltip = {
    trigger: 'axis',
    triggerOn: 'click',
    enterable: true,
    formatter: function (params) {
      let returnData = '';
      returnData = params[0].name + '</br>';
      for (let i = 0; i < params.length; i++) {
        let indexColor = params[i].color;
        returnData += '<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background:' + indexColor + '"></span>';
        returnData += params[i].seriesName + ':' + params[i].value + '</br>';
      }
      // }
      /* qpsValue不展示跳转链接
              或者没有traceId
             */
      const __tracrId__ = localStorage.getItem('__tracrId__');
      if (params[0].seriesName === 'qpsValue' || !__tracrId__) {
        return returnData;
      } else {
        const val = {
          name: params[params.length - 1].name,
          value: params[params.length - 1].value,
          //   type: x_list[0],
        };
        return returnData + '<hr style="border:1 dashed #987cb9;" width="98%" size=5><div οnclick="_myalert_(\'' + JSON.stringify(val).replace(/"/g, '&quot;') + '\')" style="color:#000;text-decoration: none" id="btn-tooltip">pinpoint></div>';
      }
    },
  };
  constructor(data, x_list) {
    this.colors = ['#00acc1', '#03a9f4', '#90caf9', '#4db6ac', '#00e676', '#ffab40', '#ca8622', '#3d5afe'];
    this.randomHexColor = () => {
      //随机生成十六进制颜色
      return '#' + ('00000' + ((Math.random() * 0x1000000) << 0).toString(16)).substr(-6);
    };
    return {
      //   color: this.colors.sort(() => Math.random() - 0.5),
      color: this.randomHexColor(),
      dataZoom: [
        {
          show: true,
          realtime: true,
          start: 0,
          end: 50,
        },
        {
          type: 'inside',
          realtime: true,
          start: 0,
          end: 50,
        },
      ],
      //   tooltip: this.tooltip,
      legend: {
        data: x_list,
      },
      xAxis: {
        type: 'category',
        data: data.map(item => moment(item.timestamp).format('YYYYY/MM/DD HH:mm:ss').slice(1)),
      },
      yAxis: {
        type: 'value',
      },
      series: x_list.map(name => {
        return {
          name: name,
          type: 'line',
          symbol: 'circle',
          symbolSize: 5, //设定实心点的大小
          data: data.map(item => item[name]),
        };
      }),
    };
  }
}
class Layer {
  constructor(point) {
    this.layer = null;
    this.traceId = '';
    this.setPosition(point);
    this.initLayerStyle = `
    width: 200px;
    height: 100px;
    position:absolute;top:${this._y - 50}px;
    left:${this._x - 100}px;
    background:#fff;
    box-shadow:0 0 5px #666;
    border-radius: 4px;
    padding:10px;
    color:#666`;
  }
  htmlContent() {
    return `
    <style>
    .layer-time-point{
        display:inline-block;
        margin-right:5px;
        border-radius:10px;
        width:9px;
        height:9px;
        background:${this.color}
    }
    .layer-key-value{
        margin:10px 0
    }
    .tracrId-none{
        display:none
    }
    .tracrId-link-style{
        text-decoration: underline;
        color:blue
    }
    .tracrId-link-style:hover{
        text-decoration: underline;
        color:blue
    }
    </style>
      <div><span class='layer-time-point' style="background:${this.color}"></span>${this.time}</div>
      <div class='layer-key-value'>${this.key}:${this.value}</div>
      <a class="${this.traceId ? 'tracrId-link-style' : 'tracrId-none'}"
         href="https://pinpoint.lx.netease.com/transactionDetail/${this.traceId}/0/${this.traceId.split('^')[0]}/-1"
         target="_blank">
       pinpoint
      </a>
  `;
  }
  setPosition(point) {
    this.time = point.name;
    this.key = point.seriesName;
    this.value = point.value;
    this.color = point.color;
    this._x = point.event.offsetX;
    this._y = point.event.offsetY;
  }
  move(point, traceId) {
    this.traceId = traceId;
    this.setPosition(point);
    this.layer.style.display = 'block';
    this.layer.style.top = this._y - 50 + 'px';
    this.layer.style.left = this._x - 100 + 'px';
    this.layer.innerHTML = this.htmlContent();
  }
  create(chartId, traceId) {
    this.traceId = traceId;
    const layer = document.createElement('div');
    console.log(this._x, this._y);
    layer.style.cssText = this.initLayerStyle;
    layer.innerHTML = this.htmlContent();
    this.layer = layer;
    layer.addEventListener('mouseleave', function () {
      this.style.display = 'none';
    });
    document.getElementById(chartId).appendChild(layer);
  }
}
export class InitCharts {
  constructor() {
    this.layerMap = {};
    this.nameMap = {
      qpsValue: 'qps',
      avgValue: 'avg',
      p99Value: 'p99',
      failedCount: 'failed',
      _4xxCount: '4xx',
      _5xxCount: '5xx',
    };
  }
  delObjectKey(obj, keys) {
    const copy = Object.assign({}, obj);
    for (let key in copy) {
      for (let item of keys) {
        if (item === key) {
          delete copy[key];
        }
      }
    }
    return copy;
  }
  /**
   * 初始化echart
   *
   * @param {string} selector 包含echart的容器
   * @param {Array} data 数据
   * @param {Array} chartsIds 展示的echart,对应data中的字段
   * @param {Object} queryTraceParams 查询traceId所需参数:上下游,时间等
   * @param {*} clickType 查询traceId所需参数:线段点击or节点点击
   */
  init(selector, data, chartsIds, queryTraceParams, clickType) {
    const chartBox = document.querySelector(selector);
    chartBox.innerHTML = '';
    for (let i = 0, len = chartsIds.length; i < len; i++) {
      const dom = document.createElement('div');
      dom.setAttribute('id', chartsIds[i]);
      dom.style.cssText = 'margin:10px 0;border: 1px solid #b0bec5;width: 680px;height: 200px; position: relative;';
      chartBox.appendChild(dom);
      const myChart = echarts.init(dom);
      const option = new Option(data, [chartsIds[i]]);
      myChart.setOption(option);
      /* 折线点击出layer */
      myChart.on('click', point => {
        const type = this.nameMap[point.seriesName];
        const params = this.delObjectKey(queryTraceParams, ['fromTime', 'toTime']);
        const time = moment(point.name).valueOf();
        const value = String(point.value);
        api.getTraceId({ ...params, time, value, type }, clickType).then(res => {
          const traceId = res?.data?.data || '';
          /* 有则移动,无则创建 */
          if (this.layerMap[chartsIds[i]]) {
            this.layerMap[chartsIds[i]].move(point, traceId);
            return;
          }
          this.layerMap[chartsIds[i]] = new Layer(point);
          this.layerMap[chartsIds[i]].create(chartsIds[i], traceId);
        });
      });
    }
  }
}