// @ts-nocheck
class WsLabel {
  constructor() {
    this.name = 'label';
    this.id = 'id';
    this.bg_color = '#fff';
    this.fore_color = '#ddd';
    this.location = 0;
    this.width = 1000;
  }
}
//this.area_x             //绘图区域 起始X
//this.area_y             //绘图区域 起始Y
//this.area_width         //绘图区域 宽度
//this.area_height        //绘图区域 高度
//this.spectrogram_y      //频谱区域 起始Y
//this.spectrogram_x      //频谱区域 起始X
//this.spectrogram_width  //频谱区域 宽度
//this.spectrogram_height //频谱区域 高度
//this.waterfall_y        //瀑布区域 起始Y
//this.waterfall_x        //瀑布区域 起始X
//this.waterfall_width    //瀑布区域 宽度
//this.waterfall_height   //瀑布区域 高度

//新增数据
waterfallwidget.prototype.addData = function (d, time) {
  if (this.willFitDbRange == true) {
    this.willFitDbRange = false;

    var max = Math.max(...d) + 10;
    var min = Math.min(...d) - 10;
    if (-200 > min) {
      min = -200;
    }
    if (0 < max) {
      max = 0;
    }
    this.changeDBRange(min, max, true);

    return;
  }

  this.drawWaterFall(d);
  this.drawAllSpectrogram(d);

  //时间
  if (time) {
    if (this.timeIndex > this.waterfall_height) {
      this.timeQueue.splice(this.timeQueue.length - this.time_span, this.time_span);
      this.timeIndex = this.timeIndex - this.time_span;
    }
    this.timeQueue.unshift(time);
    this.drawCoorTime();
    this.timeIndex++;
  }
};
waterfallwidget.prototype.addCompareCurLineData = function (d) {
  this.CompareCurLineBuff = d;
};
waterfallwidget.prototype.lastPeakMarker = false;
waterfallwidget.prototype.drawAllSpectrogram = function (bins) {
  var size = this.visual_MapLen; //bins.length;
  var top = this.spectrogram_y;
  var left = this.spectrogram_x;
  var width = this.spectrogram_width;
  var height = this.spectrogram_height;
  this.drawSpectrogrambg();
  this.drawAfterglow(bins, this.waveAfterglow_color);
  this._drawSpectrogram(bins, this.wave_color, peakMarkIndex);

  //峰值标注
  var peakMarkIndex = 0;
  if (this.showPeakMarker) {
    if (bins.length < 100) {
      console.log('waterfall len cannot < 100');
    }
    var band = this.max_db - this.min_db;

    var max = -10000;
    peakMarkIndex = 50;
    for (var i = 5; i < bins.length - 5; i++) {
      if (bins[i] > max) {
        max = bins[i];
        peakMarkIndex = i;
      }
    }

    //var max = Math.max(...bins);
    //peakMarkIndex = bins.indexOf(max);

    var markv = max;
    var marky = top + height - ((markv - this.min_db) / band) * height;
    var markx = left + width * (peakMarkIndex / bins.length);

    var markfre = this.getFreqByPoint(markx);
    var textfre = `${(markfre / 1000000).toFixed(6)} MHz`;
    var context = this.layer_info2.getContext();
    context.clearRect(0, 0, this.layer_info2.getWidth(), this.layer_info2.getHeight());
    context.beginPath();
    context.moveTo(markx - 3, marky - 15);
    context.lineTo(markx + 3, marky - 15);
    context.lineTo(markx, marky - 5);
    context.fillStyle = '#ff0000';
    context.fill();

    context.strokeStyle = this.fore_color;
    context.font = '13px serif';
    context.strokeText(textfre, markx + 5, marky - 15);
    context.strokeText(markv.toFixed(2) + ' dBm', markx + 5, marky - 1);
  }

  //最大保持
  if (this.showSpectrogramMax) {
    if (this.SpectrogramMaxBuff.length == 0 || this.SpectrogramMaxBuff.length != bins.length) {
      this.SpectrogramMaxBuff = new Array(bins.length);
      for (var i = 0; i < bins.length; i++) {
        this.SpectrogramMaxBuff[i] = bins[i];
      }
    } else {
      for (var i = 0; i < bins.length; i++) {
        this.SpectrogramMaxBuff[i] = Math.max(this.SpectrogramMaxBuff[i], bins[i]);
      }
    }
    this._drawSpectrogram(this.SpectrogramMaxBuff, this.wave_color_max);
  }

  //最小保持
  if (this.showSpectrogramMin) {
    if (this.SpectrogramMinBuff.length == 0 || this.SpectrogramMinBuff.length != bins.length) {
      this.SpectrogramMinBuff = new Array(bins.length);
      for (var i = 0; i < bins.length; i++) {
        this.SpectrogramMinBuff[i] = bins[i];
      }
    } else {
      for (var i = 0; i < bins.length; i++) {
        this.SpectrogramMinBuff[i] = Math.min(this.SpectrogramMinBuff[i], bins[i]);
      }
    }
    this._drawSpectrogram(this.SpectrogramMinBuff, this.wave_color_min);
  }

  //平均保持
  if (this.showSpectrogramAvg) {
    if (this.SpectrogramBuff.length >= this.SpectrogramBuffCount) {
      this.SpectrogramBuff.shift();
    }
    this.SpectrogramBuff.push(bins);
    var count = this.SpectrogramBuff.length;
    var len = this.SpectrogramBuff[0].length;
    var ls = new Array(len);
    var sum = 0;
    for (var i = 0; i < len; i++) {
      sum = 0;
      for (var j = 0; j < count; j++) {
        sum += this.SpectrogramBuff[j][i];
      }
      ls[i] = Math.round(sum / count);
    }
    this._drawSpectrogram(ls, this.wave_color_avg);
  }
  //Make功能
  if (this.showPeakMarker) {
    this.setShowMake(bins, this.layer_info3, 0);
    this.setShowMake(bins, this.layer_info4, 1);
    this.showInfoMakeDb();
    //this.setShowMake(bins, this.layer_info5, 2);
    //this.setShowMake(bins, this.layer_info6, 3);
    //this.setShowMake(bins, this.layer_info7, 4);
  }
  //显示对比频谱
  if (this.showCompareCurLine) {
    if (this.CompareCurLineBuff != null) {
      let _first = this.CompareCurLineBuff;
      this._drawSpectrogram(_first, this.wave_color_compare);
    }
  }

  this.layer_wf.getContext().drawImage(this.ctx_spec.canvas, 0, 0, size, height, left, top, width, height);
};
waterfallwidget.prototype.drawSpectrogrambg = function () {
  var size = this.visual_MapLen;
  var height = this.spectrogram_height;

  this.ctx_spec.fillStyle = this.bg_color;
  this.ctx_spec.fillRect(0, 0, size, height);
};

//余晖图
waterfallwidget.prototype.drawAfterglow = function (bins, color) {
  if (!this.afterglowBuff) {
    this.afterglowBuff = [];
  }
  if (this.delayAfterglow == 0) {
    this.afterglowBuff = [];
    return;
  }

  var delayTime = Math.min(this.delayAfterglow, 5000);

  var removeCount = 0;
  for (var i = 0; i < this.afterglowBuff.length; i++) {
    if (Date.now() - this.afterglowBuff[i].time.getTime() > delayTime) {
      removeCount++;
    }
  }
  for (var i = 0; i < removeCount; i++) {
    this.afterglowBuff.shift();
  }
  if (this.afterglowBuff.length > 0) {
    var alpaStep = 1 / (this.afterglowBuff.length + 1);

    for (var i = 0; i < this.afterglowBuff.length; i++) {
      this._drawSpectrogram(
        this.afterglowBuff[i].data,
        this.hexToRGBA(this.afterglowBuff[i].color, alpaStep * (i + 1)),
      );
    }
  }

  this.afterglowBuff.push({
    time: new Date(),
    data: bins,
    color: color,
  });
};
waterfallwidget.prototype._drawSpectrogram = function (bins, color) {
  this.ctx_spec.strokeStyle = color;
  var size = this.visual_MapLen;
  //var top = this.spectrogram_y;
  //var left = this.spectrogram_x;
  //var width = this.spectrogram_width;
  var height = this.spectrogram_height;
  if (height == 0) return;

  if (bins.length < 2) {
    return;
  }

  this.ctx_spec.beginPath();
  this.ctx_spec.moveTo(0, height - ((bins[0] - this.min_db) / band) * height);

  var band = this.max_db - this.min_db;
  var per = size / bins.length;
  for (var j = 0; j < bins.length - 1; j++) {
    var val = bins[j];
    var i = Math.floor(per * j);

    if (val < this.min_db) val = this.min_db;
    if (val > this.max_db) val = this.max_db;

    var y = 0;
    y = height - ((val - this.min_db) / band) * height;

    this.ctx_spec.lineTo(i, y);
  }

  this.ctx_spec.stroke();
};

/**
 * 十六进制颜色值转为带透明度的颜色
 * @param _color 十六进制颜色
 * @param _opacity 透明度
 * @returns {string} rgba
 */
waterfallwidget.prototype.hexToRGBA = function (_color, _opacity) {
  var sColor = _color.toLowerCase();
  //十六进制颜色值的正则表达式
  var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
  // 如果是16进制颜色
  if (sColor && reg.test(sColor)) {
    if (sColor.length === 4) {
      var sColorNew = '#';
      for (var i = 1; i < 4; i += 1) {
        sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
      }
      sColor = sColorNew;
    }
    //处理六位的颜色值
    var sColorChange = [];
    for (var i = 1; i < 7; i += 2) {
      sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2)));
    }
    return 'rgba(' + sColorChange.join(',') + ',' + _opacity + ')';
  }
  return sColor;
};

waterfallwidget.prototype.drawWaterFall = function (bins) {
  var size = this.visual_MapLen; // bins.length;
  var row = this.waterfall_height;
  var width = this.waterfall_width;
  if (row == 0) return;
  if (this.ctx_wf.canvas.width != size || this.ctx_wf.canvas.height != row) {
    this.ctx_wf.canvas.width = size;
    this.ctx_wf.canvas.height = row;
  }

  // Shift waterfall 1 row down
  this.ctx_wf.drawImage(this.ctx_wf.canvas, 0, 0, size, row - 1, 0, 1, size, row - 1);

  // Draw new line on waterfall canvas
  var imgData = this.rowToImageData(this.ctx_wf, bins);
  this.ctx_wf.putImageData(imgData, 0, 0);

  // Copy scaled FFT canvas to screen
  this.layer_wf
    .getContext()
    .drawImage(this.ctx_wf.canvas, 0, 0, size, row, this.waterfall_x, this.waterfall_y, width, row);
};
waterfallwidget.prototype.squeeze = function (value) {
  if (value < this.min_db) {
    value = this.min_db;
  } else if (value > this.max_db) {
    value = this.max_db;
  }
  value = value + Math.abs(this.min_db);

  //value= (value - this.min_db) / (this.max_db - this.min_db) * 200;
  //value = value * 200 / (this.max_db - this.min_db);
  value = Math.round(value);
  return value;
};
waterfallwidget.prototype.rowToImageData = function (c, bins) {
  var colors = this.color_map.getMapColors();
  var size = this.visual_MapLen;
  var imgData = c.createImageData(size, 1);

  var per = bins.length / size;
  if (per > 1) {
    for (var p = 0; p < size; p++) {
      var binStart = Math.floor(p * per);
      var binEnd = Math.min(Math.floor(p * per + per), bins.length - 1);
      var vals = [];
      for (var q = binStart; q < binEnd; q++) {
        vals.push(bins[q]);
      }

      var cindex = this.squeeze(Math.max(...vals));

      if (cindex > Math.abs(this.min_db) || 0) {
        console.log(cindex + '-' + colors.length);
        return imgData;
      }
      var color = colors[cindex];

      var i = p * 4;
      if (color) {
        imgData.data[i + 0] = color[0];
        imgData.data[i + 1] = color[1];
        imgData.data[i + 2] = color[2];
        imgData.data[i + 3] = 255;
      }
    }
  } else {
    per = size / bins.length;
    for (var j = 0; j < bins.length; j++) {
      var i = Math.floor(j * per) * 4;
      var cindex = this.squeeze(bins[j]);
      if (cindex > Math.abs(this.min_db) || 0) {
        console.log(cindex + '-' + colors.length);
        return imgData;
      }
      var color = colors[cindex];
      if (color) {
        for (var m = 0; m < Math.ceil(per); m++) {
          imgData.data[i + m * 4 + 0] = color[0];
          imgData.data[i + m * 4 + 1] = color[1];
          imgData.data[i + m * 4 + 2] = color[2];
          imgData.data[i + m * 4 + 3] = 255;
        }
      }
    }
  }

  //var per = size / bins.length;
  //for (var j = 0; j < bins.length; j++) {
  //    var i = Math.floor(j * per)*4;
  //    var cindex = this.squeeze(bins[j]);
  //    if (cindex > Math.abs(this.min_db) || 0) console.log(cindex + "-" + colors.length);
  //    var color = colors[cindex];
  //    if (color) {
  //        imgData.data[i + 0] = color[0];
  //        imgData.data[i + 1] = color[1];
  //        imgData.data[i + 2] = color[2];
  //        imgData.data[i + 3] = 255;
  //    }
  //}

  return imgData;
};

waterfallwidget.prototype.fitDbRange = function () {
  this.willFitDbRange = true;
};

waterfallwidget.prototype.changeDBRange = function (min_db, max_db, force = false) {
  min_db = Math.max(-200, min_db);
  max_db = Math.min(0, max_db);
  if (this.min_db != min_db || this.max_db != max_db || force == true) {
    this.min_db = min_db;
    this.max_db = max_db;

    this.drawCoor();

    this.color_map.setDbRange(max_db - min_db);

    //this.drawMap();
    //this.drawRuler();
    this.setColorMapGravity(Math.round(this.min_db + (this.max_db - this.min_db) * 0.31415926), this.showRuler);

    this.drawCarryLine();

    this.fireGravityEvent();
  }
};

waterfallwidget.prototype.drawCoor = function () {
  var layer = this.layer_coor;
  layer.destroyChildren();
  layer.add(
    new Konva.Rect({
      x: 0,
      y: 0,
      width: layer.getWidth(),
      height: layer.getHeight(),
      fill: this.bg_color,
      listening: false,
    }),
  );

  layer.add(
    new Konva.Rect({
      x: this.margin_left,
      y: this.margin_top,
      width: this.getwf_CtWidth(),
      height: this.getwf_CtHeight(),
      stroke: this.fore_color,
      //fill:this.bg_color,
      strokeWidth: 1,
      listening: false,
    }),
  );
  layer.add(
    new Konva.Line({
      points: [this.waterfall_x, this.waterfall_y - 1, this.waterfall_x + this.waterfall_width, this.waterfall_y - 1],
      stroke: this.fore_color,
      strokeWidth: 1,
      listening: false,
    }),
  );

  var spanSpec = this.spectrogram_height / this.db_counter;
  var span = this.waterfall_height / this.db_counter;
  var spanValue = Math.round((this.max_db - this.min_db) / this.db_counter);
  for (var i = 0; i < this.db_counter; i += 1) {
    if (i < this.db_counter) {
      if (this.spectrogram_height > 0) {
        layer.add(
          new Konva.Text({
            x: 0,
            y: this.spectrogram_y + spanSpec * i - 5,
            text: this.max_db - i * spanValue ? this.max_db - i * spanValue : '0',
            fontSize: 11,
            fontFamily: 'Calibri',
            fill: this.fore_color,
            width: this.margin_left - 30,
            align: 'right',
            listening: false,
          }),
        );
      }

      if (this.waterfall_height > 0) {
        layer.add(
          new Konva.Line({
            points: [
              this.margin_left - 28,
              this.spectrogram_y + spanSpec * i,
              this.margin_left - 23,
              this.spectrogram_y + spanSpec * i,
            ],
            stroke: this.fore_color,
            strokeWidth: 1,
            listening: false,
          }),
        );
      }
    }

    /////////////////////////////////

    layer.add(
      new Konva.Text({
        x: 0,
        y: this.waterfall_y + span * i - 5,
        text: this.max_db - i * spanValue ? this.max_db - i * spanValue : '0',
        fontSize: 11,
        fontFamily: 'Calibri',
        fill: this.fore_color,
        width: this.margin_left - 30,
        align: 'right',
        listening: false,
      }),
    );
    layer.add(
      new Konva.Line({
        points: [
          this.margin_left - 28,
          this.waterfall_y + span * i,
          this.margin_left - 23,
          this.waterfall_y + span * i,
        ],
        stroke: this.fore_color,
        strokeWidth: 1,
        listening: false,
      }),
    );
  }

  layer.draw();
};

waterfallwidget.prototype.drawCoorTime = function () {
  if (this.timeQueue.length == 0) return;

  var layer = this.layer_coor;
  var arrtext = layer.find('.time-text');
  var arrline = layer.find('.time-line');
  for (var i = 0; i < arrtext.length; i++) {
    arrtext[i].destroy();
  }
  for (var i = 0; i < arrline.length; i++) {
    arrline[i].destroy();
  }

  var timeY = this.waterfall_y;
  var timeValue = '';
  var cIndex = this.timeIndex;
  var timeX = this.stage.getWidth() - this.margin_right + 1;

  while (cIndex > 0) {
    timeY = cIndex + this.waterfall_y;
    timeValue = this.timeQueue[cIndex];
    cIndex -= this.time_span;

    layer.add(
      new Konva.Text({
        x: timeX + 8,
        y: timeY - 5,
        text: timeValue,
        fontSize: 11,
        fontFamily: 'Calibri',
        fill: this.fore_color,
        width: 100,
        align: 'left',
        listening: false,
        name: 'time-text',
      }),
    );
    layer.add(
      new Konva.Line({
        points: [timeX, timeY, timeX + 5, timeY],
        stroke: this.fore_color,
        strokeWidth: 1,
        listening: false,
        name: 'time-line',
      }),
    );
  }

  //var lines = 1000 / this.time_out;
  //var zoom = Math.floor(20 / lines);

  //while (timeY < this.getwf_CtHeight() + this.margin_top) {
  //    layer.add(
  //        new Konva.Text({
  //            x: timeX + 8,
  //            y: timeY - 5,
  //            text: (timeValue) + ' s',
  //            fontSize: 11,
  //            fontFamily: 'Calibri',
  //            fill: this.fore_color,
  //            width: 100,
  //            align: 'left',
  //            listening: false,
  //        })
  //    );

  //    layer.add(
  //        new Konva.Line({
  //            points: [timeX, timeY, timeX + 5, timeY],
  //            stroke: this.fore_color,
  //            strokeWidth: 1,
  //            listening: false,
  //        })
  //    );
  //    timeValue += zoom;
  //    timeY += zoom * lines;
  //}
  layer.draw();
};

waterfallwidget.prototype.drawCoorFreq = function () {
  var layer = this.layer_coorFreq;
  layer.destroyChildren();
  layer.removeChildren();

  var count = this.zoomOption;

  var freSpan = this.getwf_CtWidth() / count;
  var freValueSpan = Math.round((this.freq_end - this.freq_start) / count);

  var fre_y = this.margin_top;
  if (this.coorFreqType == 1) {
    fre_y = this.waterfall_y;
  }
  var msFreSpan = freSpan / 10;
  var msFreValueSpan = freValueSpan / 10;
  for (var i = 0; i < count + 1; i++) {
    var v = this.freq_start + i * freValueSpan;
    var dim = 'Hz';
    if (v >= 1000000000) {
      v = v / 1000000000;
      dim = 'G';
    } else if (v >= 1000000) {
      v = v / 1000000;
      dim = 'M';
    } else if (v >= 1000) {
      v = v / 1000;
      dim = 'K';
    }
    if (count <= 8) {
      v = v.toFixed(3);
    } else {
      v = v.toFixed(3);
    }

    layer.add(
      new Konva.Text({
        x: this.margin_left + i * freSpan - 12,
        y: fre_y - 12,
        text: v + ' ' + dim,
        fontSize: 11,
        fontFamily: 'Calibri',
        fill: this.fore_color,
        width: 100,
        align: 'left',
        listening: false,
      }),
    );

    layer.add(
      new Konva.Line({
        points: [this.margin_left + i * freSpan, fre_y - 22, this.margin_left + i * freSpan, fre_y - 13],
        stroke: this.fore_color,
        strokeWidth: 1,
        listening: false,
      }),
    );
    if (this.show_msFreq && i != count) {
      for (var j = 0; j < 9; j++) {
        var msX = Math.round(this.margin_left + i * freSpan + (j + 1) * msFreSpan);
        layer.add(
          new Konva.Line({
            points: [msX, fre_y - 20, msX, fre_y - 15],
            stroke: this.fore_color,
            strokeWidth: 1,
            listening: false,
          }),
        );

        if (count == 1) {
          var msv = this.freq_start + i * freValueSpan + (j + 1) * msFreValueSpan;
          var dimms = 'Hz';
          if (msv >= 1000000000) {
            msv = msv / 1000000000;
            dimms = 'G';
          } else if (msv >= 1000000) {
            msv = msv / 1000000;
            dimms = 'M';
          } else if (msv >= 1000) {
            msv = msv / 1000;
            dimms = 'K';
          }

          msv = msv.toFixed(3);
          layer.add(
            new Konva.Text({
              x: msX - 12,
              y: fre_y - 12,
              text: msv + ' ' + dimms,
              fontSize: 11,
              fontFamily: 'Calibri',
              fill: this.fore_color,
              width: 100,
              align: 'left',
              listening: false,
            }),
          );
        }
      }
    }
  }

  layer.batchDraw();
};

waterfallwidget.prototype.setZoomCenter = function (freq, force = true) {
  if (this.freq_start < freq && this.freq_end > freq && force == false) {
    return;
  }

  var range = this.freq_end - this.freq_start;
  var nstart = freq - range / 2;
  var nend = freq + range / 2;
  if (nstart < this.min_freq || nend > this.max_freq) {
    return;
  }
  this.setFreqZoom(nstart, nend);
};

waterfallwidget.prototype.drawCoorFreqWheel = function () {
  var layer = this.layer_coorFreqWeel;
  //双击频点居中
  layer.on('dblclick', (e) => {
    var x = e.evt.offsetX;
    var freq = this.getFreqByPoint(x);
    this.setZoomCenter(freq);
  });

  if (this.allowRunMode == 1) {
    this.drawCoorFreqWheel_RT();
  } else if (this.allowRunMode == 0) {
    this.drawCoorFreqWheel_Slide();
  }

  //左侧增益动作
  var wheelRect = new Konva.Rect({
    x: 0,
    y: 0,
    width: this.margin_left - 20,
    height: this.stage.getHeight(),
    fill: 'transparent', //
    name: 'wheelReactDbCt',
  });

  wheelRect.on('wheel', (evt) => {
    var min_db = this.min_db;
    var max_db = this.max_db;

    if (evt.evt.wheelDelta > 0) {
      if (this.max_db - this.min_db > 30) {
        min_db += 5;
        max_db -= 5;
      } else {
        return;
      }
    } else {
      min_db -= 5;
      max_db += 5;
    }
    this.changeDBRange(min_db, max_db);

    evt.evt.preventDefault();
    evt.evt.stopPropagation();

    return false;
  });

  wheelRect.on('mousedown', (e) => {
    if (e.evt.button === 2) {
      return;
    } else if (e.evt.button === 0) {
      //buttonLR = 'left';
    }

    var span = this.waterfall_height / this.db_counter;
    var distanceY = e.evt.offsetY;
    var oDbMin = this.min_db;
    var oDbMax = this.max_db;

    if (distanceY < this.waterfall_y) {
      span = this.spectrogram_height / this.db_counter;
    }

    this.stage.on('mousemove', (e) => {
      var yy = e.evt.offsetY - distanceY;
      var change = Math.floor(yy / span) * 10;

      var desMin = oDbMin + change;
      var desMax = oDbMax + change;

      var min_db = Math.max(-200, desMin);
      var max_db = Math.min(0, desMax);

      this.changeDBRange(min_db, max_db);
    });
    this.stage.on('mouseup', (e) => {
      this.stage.off('mousemove');
      this.stage.off('mouseup');
    });
  });
  //增益区域鼠标移入鼠标图标变化
  wheelRect.on('mouseover', (e) => {
    this.stage.container().style.cursor = 'pointer';
  });
  wheelRect.on('mouseout', (e) => {
    this.stage.container().style.cursor = 'default';
  });
  //增益动作结束

  layer.add(wheelRect);
  layer.batchDraw();
};
//鼠标操作层 实时模式
waterfallwidget.prototype.drawCoorFreqWheel_RT = function () {
  var _self = this;
  var layer = this.layer_coorFreqWeel;
  layer.destroyChildren();
  layer.removeChildren();

  var wheelRect = new Konva.Rect({
    x: this.area_x,
    y: this.area_y - 20,
    width: this.area_width,
    height: this.area_height + 20,
    fill: 'transparent',
    name: 'wheelReact',
  });
  var buttonLR;

  wheelRect.on('mousedown', function (e) {
    var distanceX = e.evt.offsetX;
    var distanceY = e.evt.offsetY;
    _self.hideContextMenu();
    if (e.evt.button === 2) {
      buttonLR = 'right';
      _self.adj_show = true;
      //
    } else if (e.evt.button === 0) {
      buttonLR = 'left';
    }
    var o_start = _self.freq_start;

    _self.stage.on('mousemove', async function (e) {
      //只有鼠标左键移动
      if (buttonLR === 'left') {
        _self.drawCoverRect(distanceX, distanceY, e.evt.offsetX, e.evt.offsetY);
      } else if (buttonLR === 'right') {
        if (e.evt.offsetX - distanceX > 0) {
          if (this.isUHF) {
            _self.adj_end = _self.getFreqByPoint(e.evt.offsetX);
            _self.drawAdjLocation();
          }
        }
      }
    });
    _self.stage.on('mouseup', async function (e) {
      _self.clearCoverLayer();
      if (buttonLR === 'left') {
        if (_self.disableZoom != true) {
          var dx = e.evt.offsetX;
          var dy = e.evt.offsetY;
          if (Math.abs(dx - distanceX) < 10) {
          } else if (dx > distanceX) {
            var freqStart = _self.getFreqByPoint(distanceX);
            var freqend = _self.getFreqByPoint(e.evt.offsetX);
            if (freqend - freqStart < 1000) {
              var selectBw = 1000 / 2;
              var selectCenter = Math.round(freqStart + (freqend - freqStart) / 2);
              freqStart = Math.max(selectCenter - selectBw, _self.min_freq);
              freqend = Math.min(selectCenter + selectBw, _self.max_freq);
            }
            _self.setFreqZoomUp(freqStart, freqend);
          } else {
            _self.setFreqZoomDown();
          }
        }
        if (e.evt.altKey) {
          //频率信息标注
          var x = e.evt.offsetX;
          var y = e.evt.offsetY;
          var freq = _self.getFreqByPoint(x);
          if (_self.wfFreqPointLable) {
            _self.AddFreqPointLable(freq);
            return;
          }
        }
      } else if (buttonLR === 'right') {
        var dx = e.evt.offsetX;
        var dy = e.evt.offsetY;
        //右键点击
        if (Math.abs(dx - distanceX) < 10) {
          _self.setAdjCenter(_self.getFreqByPoint(distanceX), true);
        }
      }

      buttonLR = null;
      _self.stage.off('mousemove');
      _self.stage.off('mouseup');
    });
  });

  wheelRect.on('mouseenter', (enter) => {
    wheelRect.on('mousemove', async function (move) {
      //显示悬浮信息
      var freq = _self.getFreqByPoint(move.evt.offsetX);
      var db = _self.getDbByPoint(move.evt.offsetY);
      var text = `${(freq / 1000000).toFixed(6)} MHz`;
      if (db) {
        text = text + `\r\n${db} dBm`;
      }
      _self.showInfo(
        {
          x: move.evt.offsetX,
          y: move.evt.offsetY,
          text: text,
        },
        true,
      );
    });
    wheelRect.on('mouseleave', async function (leave) {
      wheelRect.off('mouseleave');
      wheelRect.off('mousemove');
      _self.hideInfo();
    });
  });
  this.drawWheelZoom(wheelRect);

  layer.add(wheelRect);
  layer.batchDraw();
};
//鼠标操作层 侦察模式
waterfallwidget.prototype.drawCoorFreqWheel_Slide = function () {
  var _self = this;
  var layer = this.layer_coorFreqWeel;
  layer.destroyChildren();
  layer.removeChildren();

  var wheelRect = new Konva.Rect({
    x: this.area_x,
    y: this.area_y - 20,
    width: this.area_width,
    height: this.area_height + 20,
    fill: 'transparent',
    name: 'wheelReact',
  });
  var buttonLR;

  //放大缩小菜单等
  wheelRect.on('mousedown', function (e) {
    var distanceX = e.evt.offsetX;
    var distanceY = e.evt.offsetY;

    _self.hideContextMenu();
    if (e.evt.button === 2) {
      buttonLR = 'right';
      _self.adj_show = true;
      _self.adj_start = _self.getFreqByPoint(distanceX);
    } else if (e.evt.button === 0) {
      buttonLR = 'left';
    } else if (e.evt.button === 1) {
      buttonLR = 'center';
    }
    //var o_start = _self.freq_start;
    //多级频点标注功能
    if (e.evt.buttons == 1) {
      if (e.evt.ctrlKey) {
        if (_self.MakeShow.length >= 2) {
          _self.MakeShow.splice(0, 1);
        }
        var freq = _self.getFreqByPoint(e.evt.offsetX);
        _self.MakeShow[_self.MakeShow.length] = freq;
        for (var i = 0; i < _self.MakeShow.length; i++) {
          for (var j = i + 1; j < _self.MakeShow.length; j++) {
            if (_self.MakeShow[i] == _self.MakeShow[j]) {
              _self.MakeShow.splice(j, 1);
              j--;
            }
          }
        }
      } else if (e.evt.altKey) {
        //频率信息标注
        var x = e.evt.offsetX;
        var y = e.evt.offsetY;
        var freq = _self.getFreqByPoint(x);
        if (_self.wfFreqPointLable) {
          _self.AddFreqPointLable(freq);
          return;
        }
      }
    }
    if (e.evt.buttons == 2) {
      if (e.evt.ctrlKey) {
        _self.MakeShow.splice(0, _self.MakeShow.length);
      }
    }
    //多级频点标注功能
    _self.stage.on('mousemove', async function (e) {
      //只有鼠标左键移动
      if (buttonLR === 'left') {
        _self.drawCoverRect(distanceX, distanceY, e.evt.offsetX, e.evt.offsetY);
      } else if (buttonLR === 'right') {
        if (_self.adj_show) {
          _self.setCtrFc(_self.adj_start + (_self.adj_end - _self.adj_start) / 2);
          _self.adj_end = _self.getFreqByPoint(e.evt.offsetX);
          _self.drawAdjLocation();
        }
      }
    });
    _self.stage.on('mouseup', async function (e) {
      _self.clearCoverLayer();
      if (buttonLR === 'left') {
        var dx = e.evt.offsetX;
        var dy = e.evt.offsetY;
        if (Math.abs(dx - distanceX) < 10) {
        } else if (dx > distanceX) {
          var freqStart = _self.getFreqByPoint(distanceX);
          var freqend = _self.getFreqByPoint(e.evt.offsetX);
          if (freqend - freqStart < 2000) {
            var selectBw = 2000 / 2;
            var selectCenter = Math.round(freqStart + (freqend - freqStart) / 2);
            freqStart = Math.max(selectCenter - selectBw, _self.min_freq);
            freqend = Math.min(selectCenter + selectBw, _self.max_freq);
          }

          _self.setFreqZoomUp(freqStart, freqend);
        } else {
          _self.setFreqZoomDown();
        }
      } else if (buttonLR === 'right') {
        var dx = e.evt.offsetX;
        var dy = e.evt.offsetY;
        //右键点击
        if (Math.abs(dx - distanceX) < 10) {
          if (_self.adj_show) {
            _self.adj_show = false;
            _self.drawAdjLocation();
          }
        } else {
          if (_self.adj_end - _self.adj_start > 1) {
            _self.setCtrBw(_self.adj_end - _self.adj_start);
          }

          _self.setParamsToHistory({
            fc: _self.currentFc,
            bw: _self.currentBw,
          });
          if (_self.isUHF) {
            _self.onAutomaticAdjustment();
            _self.gather_show = true;
            _self.drawGather();
          }
        }
      } else if (buttonLR === 'center') {
        var dx = e.evt.offsetX;
        var dy = e.evt.offsetY;

        if (_self.CarryLineMode == 1) {
          var currectX = _self.getFreqByPoint(dx);
          var currentY = _self.getDbByPoint(dy);
          if (currectX && currentY) {
            var arr = [];
            var bk = false;
            if (dx < 65) {
              //点的特别左边直接取消
              bk = true;
            } else {
              for (var i = 0; i < _self.CarryLineList.length; i += 2) {
                var xx = _self.CarryLineList[i];
                var yy = _self.CarryLineList[i + 1];
                if (xx < currectX) {
                  arr.push(xx);
                  arr.push(yy);
                } else {
                  bk = true;
                  break;
                }
              }
            }

            if (!bk) {
              arr.push(currectX);
              arr.push(currentY);
            }
            _self.setCarryLineList(arr);
          }
        }
      }

      buttonLR = null;
      _self.stage.off('mousemove');
      _self.stage.off('mouseup');
    });
  });

  //显示信息
  wheelRect.on('mouseenter', (enter) => {
    wheelRect.on('mousemove', async function (move) {
      if (!_self.adj_show) {
        var freq = _self.getFreqByPoint(move.evt.offsetX);
        var db = _self.getDbByPoint(move.evt.offsetY);
        var text = `${(freq / 1000000).toFixed(6)} MHz`;
        if (db) {
          text = text + `\r\n${db} dBm`;
        }
        _self.showInfo(
          {
            x: move.evt.offsetX,
            y: move.evt.offsetY,
            text: text,
          },
          true,
        );
      }
      // 修改为悬浮在款选带宽内才显示提示
      //else if (_self.alwaysShowAdj) {
      //    _self.showAdjInfo(_self.adj_x, _self.adj_y);
      //}
    });
    wheelRect.on('mouseleave', async function (leave) {
      wheelRect.off('mouseleave');
      wheelRect.off('mousemove');
      _self.hideInfo();
    });
  });

  this.drawWheelZoom(wheelRect);

  layer.add(wheelRect);
  layer.batchDraw();
};

waterfallwidget.prototype.adj_x = 65;
waterfallwidget.prototype.adj_y = 25;
waterfallwidget.prototype.alwaysShowAdj = true;

//添加滚轮放大动作
waterfallwidget.prototype.drawWheelZoom = function (wheelRect) {
  var _self = this;
  wheelRect.on('wheel', (evt) => {
    if (_self.disableZoom) {
      return;
    }

    var scale = Math.exp((-evt.evt.wheelDelta * 1.0) / 200);
    var freq = this.getFreqByPoint(evt.evt.offsetX);

    //var range = this.freq_end - this.freq_start;
    //var nrange = range * scale;

    var start = freq - (freq - this.freq_start) * scale;
    var end = freq + (this.freq_end - freq) * scale;

    this.throttleSetFreqZoomUp(start, end, false);

    evt.evt.preventDefault();
    evt.evt.stopPropagation();
    return false;
  });
};

//底部滚动条
waterfallwidget.prototype.drawBottomScroll = function () {
  var bottom_scroll_height = 15;
  var layer = this.layer_botscroll;
  layer.destroyChildren();
  layer.removeChildren();

  this._debounceSetStart = _.debounce(() => {
    var x = thunk.x() - this.area_x;
    var freq = this.min_freq + (this.max_freq - this.min_freq) * (x / this.area_width);
    var freqend = freq + (this.freq_end - this.freq_start);
    this.setFreqZoom(freq, freqend);
  }, 100);

  layer.add(
    new Konva.Rect({
      x: this.area_x,
      y: this.area_y + this.area_height - bottom_scroll_height,
      width: this.area_width,
      height: bottom_scroll_height,
      fill: '#fff',
      opacity: 0.9,
      visible: false,
      name: 'bottom-scroll-bg',
    }),
  );
  var thunk = new Konva.Rect({
    x: this.area_x,
    y: this.area_y + this.area_height - bottom_scroll_height,
    width: 1,
    height: bottom_scroll_height,
    fill: '#524E63',
    opacity: 0.7,
    visible: false,
    name: 'bottom-scroll-thunk',
    //draggable: true,
    //dragBoundFunc: (pos) => {
    //    var xx = pos.x;
    //    if (pos.x < this.area_x) {
    //        xx = this.area_x;
    //    }
    //    else if (pos.x + thunk.width() > this.area_x + this.area_width) {
    //        xx = this.area_x + this.area_width - thunk.width();
    //    }
    //    return {
    //        x: xx,
    //        y: this.area_y + this.area_height - bottom_scroll_height,
    //    }
    //}
  });
  thunk.on('mouseenter', (enter) => {
    thunk.opacity(0.9);
    document.body.style.cursor = 'pointer';
    layer.draw();
  });

  thunk.on('mouseout', (enter) => {
    thunk.opacity(0.6);
    document.body.style.cursor = 'default';
    layer.draw();
  });
  thunk.on('mousedown', (e) => {
    var ox = e.evt.offsetX;
    var ol = thunk.x();

    this.stage.on('contentMousemove', (ee) => {
      var xx = ol + (ee.evt.offsetX - ox);
      if (xx < this.area_x) {
        xx = this.area_x;
      } else if (xx + thunk.width() > this.area_x + this.area_width) {
        xx = this.area_x + this.area_width - thunk.width();
      }

      thunk.x(xx);
      layer.draw();
      this._debounceSetStart();
    });
    this.stage.on('mouseup', (ee) => {
      this.stage.off('contentMousemove');
      this.stage.off('mouseup');
    });
  });
  //thunk.on('dragend', () => {
  //    var x = thunk.x() - this.area_x;
  //    var freq = this.min_freq+(this.max_freq - this.min_freq) * (x / this.area_width);
  //    var freqend = freq + (this.freq_end - this.freq_start);
  //    this.setFreqZoom(freq , freqend);
  //});

  layer.add(thunk);
  layer.batchDraw();
};

waterfallwidget.prototype.drawBottomScrollLocal = function () {
  var range = this.max_freq - this.min_freq;
  var x = ((this.freq_start - this.min_freq) / range) * this.area_width;
  var x2 = ((this.freq_end - this.min_freq) / range) * this.area_width;
  var width = x2 - x;

  if (width < 10) {
    width = 10;
  }

  var thunk = this.layer_botscroll.find('.bottom-scroll-thunk');
  thunk.width(width);
  thunk.x(this.area_x + x);

  if (Math.abs(this.freq_start - this.min_freq) < 0.1 && Math.abs(this.freq_end - this.max_freq) < 0.1) {
    thunk.hide();
    this.layer_botscroll.find('.bottom-scroll-bg').hide();
  } else {
    thunk.show();
    this.layer_botscroll.find('.bottom-scroll-bg').show();
  }

  this.layer_botscroll.draw();
};

waterfallwidget.prototype.clearCoverLayer = function () {
  var layer = this.layer_cover;
  layer.destroyChildren();
  layer.removeChildren();
  layer.batchDraw();
};
waterfallwidget.prototype.drawCoverRect = function (sx, sy, dx, dy) {
  var layer = this.layer_cover;
  layer.destroyChildren();
  layer.removeChildren();

  var x = sx > dx ? dx : sx;
  var y = sy > dy ? dy : sy;
  var x1 = sx > dx ? sx : dx;
  var y1 = sy > dy ? sy : dy;

  var minx = this.area_x;
  var maxx = this.area_x + this.area_width;
  var miny = this.area_y;
  var maxy = this.area_y + this.area_height;

  x = Math.min(x, maxx);
  x = Math.max(x, minx);
  x1 = Math.min(x1, maxx);
  x1 = Math.max(x1, minx);
  y = Math.min(y, maxy);
  y = Math.max(y, miny);
  y1 = Math.min(y1, maxy);
  y1 = Math.max(y1, miny);

  layer.add(
    new Konva.Rect({
      x: x,
      y: y,
      width: x1 - x,
      height: y1 - y,
      fill: '#fff',
      opacity: 0.3,
      name: 'cover-react',
    }),
  );

  layer.batchDraw();
};

//瞬时带宽
waterfallwidget.prototype.setInstant = function (start, end) {
  this.instant_start = start;
  this.instant_end = end;
  this.drawInstant();
};
waterfallwidget.prototype.clearInstant = function () {
  this.instant_start = 0;
  this.instant_end = 0;
  this.drawInstant();
};
waterfallwidget.prototype.openInstant = function () {
  this.instant_show = true;
  this.drawInstant();
};
waterfallwidget.prototype.closeInstant = function () {
  this.instant_show = false;
  this.drawInstant();
};
waterfallwidget.prototype.drawInstant = function () {
  var layer = this.layer_instant;
  layer.destroyChildren();
  layer.removeChildren();
  layer.draw();
  if (!this.instant_show) return;
  if (!this.instant_start && !this.instant_end) return;

  var start = this.getPointByFreq(this.instant_start);
  var end = this.getPointByFreq(this.instant_end);

  if (end < this.area_x) return;
  if (start > this.area_x + this.area_width) return;

  var width = end - start;
  if (start < this.area_x) start = this.area_x;
  if (width > this.area_x + this.area_width - start) width = this.area_x + this.area_width - start;

  //console.log(start + "-" + width);

  layer.add(
    new Konva.Rect({
      x: start,
      y: this.area_y,
      width: width,
      height: this.area_height,
      fill: this.instant_color,
      opacity: 0.05,
      name: 'cover-react',
    }),
  );

  layer.batchDraw();
};

waterfallwidget.prototype.setChanel = function (start, end) {
  //console.log("setchanel " + start + "-" + end);
  this.chanel_start = start;
  this.chanel_end = end;
  this.drawChanel();
};
waterfallwidget.prototype.clearChanel = function () {
  this.chanel_start = 0;
  this.chanel_end = 0;
  this.drawChanel();
};
waterfallwidget.prototype.openChanel = function () {
  this.chanel_show = true;
  this.drawChanel();
};
waterfallwidget.prototype.closeChanel = function () {
  this.chanel_show = false;
  this.drawChanel();
};
waterfallwidget.prototype.drawChanel = function () {
  var layer = this.layer_chanel;
  layer.destroyChildren();
  layer.removeChildren();
  layer.draw();
  //if (this.showFreqLable) {
  //    var context = this.layer_info6.getContext();
  //    context.clearRect(0, 0, this.layer_info6.getWidth(), this.layer_info6.getHeight());
  //}
  if (!this.chanel_show) return;
  if (!this.chanel_start && !this.chanel_end) return;

  var start = this.getPointByFreq(this.chanel_start);
  var end = this.getPointByFreq(this.chanel_end);

  if (end < this.area_x) return;
  if (start > this.area_x + this.area_width) return;

  var width = end - start;
  if (start < this.area_x) start = this.area_x;
  if (width > this.area_x + this.area_width - start) width = this.area_x + this.area_width - start;

  if (width < 2) {
    width = 2;
  }

  layer.add(
    new Konva.Rect({
      x: start,
      y: this.area_y,
      width: width,
      height: this.area_height,
      fill: this.chanel_color,
      opacity: 0.3,
      name: 'cover-react',
    }),
  );

  layer.batchDraw();
  //显示频率标签
  //if (this.showFreqLable) {
  //    let markfre = (start + end) / 2;
  //    var freq = this.getFreqByPoint(markfre);
  //    var textfre = `${(freq / 1000000).toFixed(6)} MHz`;
  //    context.strokeStyle = this.fore_color;
  //    context.font = "13px serif";
  //    context.strokeText(textfre, end + 5, this.area_y + 30);
  //}
};

//标尺
waterfallwidget.prototype.drawMap = function () {
  if (this.waterfall_height == 0) return;

  var _self = this;
  var layer = this.layer_map;
  layer.destroyChildren();
  layer.removeChildren();

  var rect = new Konva.Rect({
    x: this.margin_left - 15,
    y: this.waterfall_y,
    width: 10,
    height: this.waterfall_height,
    fill: 'transparent',
    //stroke: this.fore_color,
  });
  rect.on('click', function () {
    if (_self.showRuler) {
      _self.showRuler = false;
      _self.layer_mapRuler.findOne('.map_ruler').hide();
    } else {
      _self.showRuler = true;
      _self.layer_mapRuler.findOne('.map_ruler').show();
    }
    _self.layer_mapRuler.batchDraw();
    _self.fireGravityEvent();
  });
  layer.add(rect);
  layer.draw();

  this.drawMapColor();
};
waterfallwidget.prototype.drawMapColor = function () {
  if (this.waterfall_height == 0) return;
  var cx = this.layer_map.getContext();
  cx.clearRect(0, 0, this.layer_map.width, this.layer_map.height);

  var nwidth = this.getDrawWHByPixelRatio(10);
  var nheight = this.getDrawWHByPixelRatio(this.waterfall_height);

  var imgData = cx.createImageData(nwidth, nheight);

  this.color_map.count = nheight; //this.waterfall_height;
  var colors = this.color_map.getColors();
  var colors_len = colors.length;
  if (colors_len != 0) {
    for (var i = 0; i < imgData.data.length; i += 4) {
      var cindex = colors_len - parseInt(i / 4 / nwidth) - 1;
      var color = colors[cindex];
      imgData.data[i + 0] = color[0];
      imgData.data[i + 1] = color[1];
      imgData.data[i + 2] = color[2];
      imgData.data[i + 3] = 255;
    }
  }
  var nx = this.getDrawWHByPixelRatio(this.margin_left - 15);
  var ny = this.getDrawWHByPixelRatio(this.waterfall_y);
  cx.putImageData(imgData, nx, ny);
};
waterfallwidget.prototype.drawRuler = function () {
  if (this.waterfall_height == 0) return;

  var _self = this;
  var layer = this.layer_mapRuler;
  layer.destroyChildren();
  layer.removeChildren();
  var group = new Konva.Group({
    x: this.margin_left - 15,
    y: this.waterfall_y + (1 - _self.getGravityPerByLocation()) * _self.waterfall_height,
    rotation: 0,
    draggable: true,
    dragBoundFunc: function (pos) {
      var newY = pos.y;
      if (newY < _self.waterfall_y) {
        newY = _self.waterfall_y;
      } else if (newY > _self.waterfall_y + _self.waterfall_height) {
        newY = _self.waterfall_y + _self.waterfall_height;
      }

      return {
        x: this.getAbsolutePosition().x,
        y: newY,
      };
    },
    shadowOffsetX: 10,
    shadowOffsetY: 15,
    shadowBlur: 40,
    opacity: 0.8,
    visible: _self.showRuler,
    name: 'map_ruler',
  });
  var lastY = -1;
  group.on('dragmove', function (e) {
    var ny = e.target.y() - _self.waterfall_y;
    var nvalue = 1 - ny / _self.waterfall_height;
    var ndb = _self.min_db + (_self.max_db - _self.min_db) * nvalue;
    _self.gravity_location = ndb;

    if (ny != lastY) {
      lastY = ny;
      _self.color_map.gravity_value = nvalue;
      if (_self.color_map.gravity) {
        _self.drawMapColor();
      }
    }
    _self.fireGravityEvent();
  });
  group.add(
    new Konva.Rect({
      x: 60,
      y: -20,
      width: 80,
      height: 20,
      fill: this.fore_color,
      stroke: this.fore_color,
      strokeWidth: 1,
      cornerRadius: 3,
    }),
  );
  group.add(
    new Konva.Text({
      x: 70,
      y: -15,
      text: 'Gravity',
      fontSize: 12,
      fontFamily: 'Calibri',
      fill: this.bg_color,
    }),
  );

  var checked = new Konva.Rect({
    x: 120,
    y: -17,
    width: 15,
    height: 15,
    fill: this.bg_color,
  });

  group.add(
    new Konva.Line({
      points: [0, 0, 60, 0],
      stroke: this.fore_color,
      strokeWidth: 1,
      lineCap: 'round',
      lineJoin: 'round',
    }),
  );

  checked.on('click', function () {
    if (_self.color_map.gravity) {
      layer.findOne('.check_ico').hide();
      _self.color_map.gravity = false;
    } else {
      layer.findOne('.check_ico').show();
      _self.color_map.gravity = true;
    }
    _self.drawMapColor();
    layer.batchDraw();
    _self.fireGravityEvent();
  });
  group.add(checked);

  //2021-09-10 梁海祥 (瀑布色尺坐标位置地布遮挡问题，坐标整体上移)
  var checkico = new Konva.Line({
    points: [123, -10, 128, -5, 133, -15],
    stroke: this.fore_color,
    strokeWidth: 2,
    lineCap: 'round',
    lineJoin: 'round',
    name: 'check_ico',
    visible: _self.color_map.gravity,
  });
  group.add(checkico);

  layer.add(group);
  layer.batchDraw();
};
waterfallwidget.prototype.setColorMapGravity = function (val, enable) {
  if (this.gravity_location !== val || this.color_map.gravity !== enable) {
    this.gravity_location = val;
    this.showRuler = enable;
    this.color_map.gravity_value = this.getGravityPerByLocation();
    this.color_map.gravity = enable;
    this.drawMap();
    this.drawRuler();
  }
};
waterfallwidget.prototype.fireGravityEvent = function () {
  this.fire('gravity-ruler-change', {
    gravityData: {
      enable: this.showRuler,
      checked: this.color_map.gravity,
      val: this.gravity_location,
      min_db: this.min_db,
      max_db: this.max_db,
    },
  });
};
//根据重力尺值得到百分比位置
waterfallwidget.prototype.getGravityPerByLocation = function () {
  if (this.gravity_location == 0) {
    return 0;
  }
  if (this.gravity_location <= this.min_db) {
    return 1;
  } else if (this.gravity_location >= this.max_db) {
    return 0;
  }

  return (this.min_db - this.gravity_location) / (this.min_db - this.max_db);
};

//2021.05.07 西部需求拖动更改频谱窗口大小，李伟添加；

waterfallwidget.prototype.split_draw = function () {
  var _self = this;
  var layer = this.layer_split;
  if (!layer) {
    return;
  }
  layer.destroyChildren();
  layer.removeChildren();
  var leftLine = new Konva.Rect({
    x: 0,
    y: 100,
    width: this.area_x,
    height: 10,
    fill: this.adj_color,
    name: 'SplitLine',
  });
  if (this.allowRunMode == 0) {
    leftLine.on('mouseenter', (e) => {
      if (this.adj_disabled == true) return;
      _self.stage.container().style.cursor = 'e-resize';
    });
    leftLine.on('mouseleave', (e) => {
      if (this.adj_disabled == true) return;
      _self.stage.container().style.cursor = 'default';
    });
    leftLine.on('mousedown', (e) => {
      if (this.adj_disabled == true) return;
      var oevent = e.evt;
      var distanceX = oevent.clientX - leftLine.x();
      _self.showAdjInfo(e.evt.offsetX, e.evt.offsetY);

      _self.stage.on('contentMousemove', function (e) {
        var freq = _self.getFreqByPoint(e.evt.offsetX);
        if (freq < _self.adj_end) {
          _self.adj_start = freq;
          _self.drawAdjLocation();
        }

        _self.showAdjInfo(e.evt.offsetX, e.evt.offsetY);
      });
      _self.stage.on('mouseup', function (e) {
        _self.stage.off('contentMousemove');
        _self.stage.off('mouseup');
        _self.hideInfo();

        _self.fire('adj-manu-change', { start: _self.adj_start, end: _self.adj_end });
      });
    });
  }

  /*
    var rightLine = new Konva.Rect({
        x: 0,
        y: this.area_y,
        width: this.adj_lineWidth,
        height: this.area_height,
        fill: this.adj_color,
        name: 'rightLine',
    });
    if (this.allowRunMode == 0) {
        rightLine.on('mouseenter', e => {
            if (this.adj_disabled == true) return;
            _self.stage.container().style.cursor = 'e-resize';
        });
        rightLine.on('mouseleave', e => {
            if (this.adj_disabled == true) return;
            _self.stage.container().style.cursor = 'default';
        });
        rightLine.on('mousedown', e => {
            if (this.adj_disabled == true) return;
            var oevent = e.evt;
            var distanceX = oevent.clientX - rightLine.x();
            _self.showAdjInfo(e.evt.offsetX, e.evt.offsetY);
            _self.stage.on('contentMousemove', function (e) {
                var freq = _self.getFreqByPoint(e.evt.offsetX);
                if (freq > _self.adj_start) {
                    _self.adj_end = freq;
                    _self.drawAdjLocation();
                }
                _self.showAdjInfo(e.evt.offsetX, e.evt.offsetY);
            });
            _self.stage.on('mouseup', function (e) {
                _self.stage.off('contentMousemove');
                _self.stage.off('mouseup');
                _self.hideInfo();

                _self.fire("adj-manu-change", { start: _self.adj_start, end: _self.adj_end });
            });
        });
    }


    var rect = new Konva.Rect({
        x: 0,
        y: this.area_y,
        width: 0,
        height: this.area_height,
        fill: this.adj_color,
        opacity: 0.1,
        name: 'rect'
    });
    if (this.allowRunMode == 0) {
        rect.on("mousedown", function (e) {
            if (e.evt.button === 2) {
                //显示右键菜单
                _self.showContextMenu(e.evt.clientX, e.evt.clientY);
            }
            else {
                _self.hideContextMenu();
            }

        })
    }


    //layer.add(rect);
    //layer.add(leftLine);
    //layer.add(rightLine);
    */
  var group = new Konva.Group({
    x: 0,
    y: 0,
  });
  //group.add(rect);
  group.add(leftLine);
  //group.add(rightLine);

  //实时模式可拖动
  if (this.allowRunMode == 1) {
    group.on('mouseenter', (e) => {
      if (this.adj_disabled == true) return;

      _self.stage.container().style.cursor = 'e-resize';
      var oevent = e.evt;
      var distanceX = oevent.clientX - rightLine.x();
      _self.showAdjInfo(e.evt.offsetX, e.evt.offsetY);
      _self.stage.on('contentMousemove', function (e) {
        _self.showAdjInfo(e.evt.offsetX, e.evt.offsetY);
      });
      group.on('mouseleave', function (e) {
        _self.stage.container().style.cursor = 'default';
        _self.stage.off('contentMousemove');
        group.off('mouseleave');
        _self.hideInfo();
      });
    });

    group.on('mousedown', (e) => {
      if (this.adj_disabled == true) return;

      if (e.evt.button !== 0) return;
      var distanceX = e.evt.clientX;
      //_self.showAdjInfo(e.evt.offsetX, e.evt.offsetY);
      var freq = _self.getAdjCenter();
      var ncenter = 0;
      _self.stage.on('mousemove', function (e) {
        var xx = e.evt.clientX - distanceX;
        var change = _self.getFreqBySpanPoint(xx);
        ncenter = freq + change;
        _self.setAdjCenter(ncenter, false);
      });
      _self.stage.on('mouseup', function (e) {
        _self.setAdjCenter(ncenter, true);
        _self.stage.off('mousemove');
        _self.stage.off('mouseup');
        _self.hideInfo();
        console.log('off');
      });
    });
  } else if (this.allowRunMode == 0) {
    //非实时模式可穿透放大缩小
    var buttonLR = null;
    /*
        rect.on('mousedown', function (e) {
            var distanceX = e.evt.offsetX;
            var distanceY = e.evt.offsetY;
            if (e.evt.button === 0) {
                buttonLR = 'left';
            }

            _self.stage.on('mousemove', async function (e) {
                //只有鼠标左键移动
                if (buttonLR === 'left') {
                    _self.drawCoverRect(distanceX, distanceY, e.evt.offsetX, e.evt.offsetY);
                }
            });
            _self.stage.on('mouseup', async function (e) {
                _self.clearCoverLayer();
                if (buttonLR === "left") {
                    var dx = e.evt.offsetX;
                    var dy = e.evt.offsetY;
                    if (Math.abs(dx - distanceX) < 10) {

                    }
                    else if (dx > distanceX) {
                        var freqStart = _self.getFreqByPoint(distanceX);
                        var freqend = _self.getFreqByPoint(e.evt.offsetX);
                        if (freqend - freqStart < 10000) {
                            var selectBw = 10000 / 2
                            var selectCenter = Math.round(freqStart + (freqend - freqStart) / 2);
                            freqStart = Math.max(selectCenter - selectBw, _self.min_freq);
                            freqend = Math.min(selectCenter + selectBw, _self.max_freq);
                        }


                        _self.setFreqZoomUp(freqStart, freqend);
                    }
                    else {
                        _self.setFreqZoomDown();
                    }
                }


                buttonLR = null;
                _self.stage.off('mousemove');
                _self.stage.off('mouseup');

            });
        });
        */
  }

  layer.add(group);

  _self.split_drawLocation();
};
waterfallwidget.prototype.split_show = function () {
  this.split_show = true;
  this.split_drawLocation();
};
waterfallwidget.prototype.split_hidden = function () {
  this.split_show = false;
  this.split_drawLocation();
};
waterfallwidget.prototype.split_enable = function () {
  this.split_disabled = false;
};
waterfallwidget.prototype.split_disable = function () {
  this.split_disabled = true;
};

waterfallwidget.prototype.split_drawLocation = function () {
  if (!this.layer_split) {
    return;
  }
  var layer = this.layer_split;

  var leftLine = layer.findOne('.leftLine');
  var rightLine = layer.findOne('.rightLine');
  var rect = layer.findOne('.rect');
  if (!leftLine || !rightLine || !rect) {
    return;
  }

  leftLine.visible(this.split_show);
  rightLine.visible(this.split_show);
  rect.visible(this.split_show);

  if (this.split_show) {
    var left = this.getPointByFreq(this.adj_start);
    var right = this.getPointByFreq(this.adj_end);
    var lineWidth = this.adj_lineWidth;

    leftLine.x(left - lineWidth);
    rightLine.x(right);

    rect.x(left);
    rect.width(right - left + lineWidth);
  }

  layer.batchDraw();
};
//2021.05.07 西部需求拖动更改频谱窗口大小，李伟添加 end；

waterfallwidget.prototype.showAdjInfo = function (x, y) {
  this.showInfo({
    x: x,
    y: y,
    text: `中心：${((this.adj_start + (this.adj_end - this.adj_start) / 2) / 1000000).toFixed(3)}MHz\r\n起始：${(this.adj_start / 1000000).toFixed(3)} MHz\r\n结束：${(this.adj_end / 1000000).toFixed(3)} MHz\r\n带宽：${((this.adj_end - this.adj_start) / 1000).toFixed(3)} kHz`,
  });
};
waterfallwidget.prototype.toHzStr = function (v, d = -1, dw = 'Hz') {
  if (!v) return '';
  if (v >= 1000000000) {
    if (d != -1) {
      v = (v / 1000000000).toFixed(d) + ' G' + dw;
    } else {
      v = (v / 1000000000).toFixed(9) + ' G' + dw;
    }
  } else if (v >= 1000000) {
    if (d != -1) {
      v = (v / 1000000).toFixed(d) + ' M' + dw;
    } else {
      v = (v / 1000000).toFixed(6) + ' M' + dw;
    }
  } else if (v >= 1000) {
    if (d != -1) {
      v = (v / 1000).toFixed(d) + ' K' + dw;
    } else {
      v = (v / 1000).toFixed(3) + ' K' + dw;
    }
  } else {
    v = v.toFixed(0) + dw;
  }
  return v;
};
waterfallwidget.prototype.setCtrBw = function (bw, reConn = true, fftmodel = 0) {
  bw = +bw;
  var panelBwText = $('#text_bw');
  if (reConn && bw == this.currentBw) {
    panelBwText.val(this.toHzStr(bw));
    return;
  }
  if (!Number.isFinite(bw)) {
    bootbox.erro('带宽格式不正确');
    panelBwText.val(this.toHzStr(this.currentBw));
    return;
  }
  if (bw < 1) {
    bootbox.erro('带宽不能小于1kHz');
    panelBwText.val(this.toHzStr(this.currentBw));
    return;
  }
  //这里判断currentFc>0是因为在初始化时带宽参数优先初始化
  if (this.currentFc > 0 && this.isAdjCenterInRange(this.currentFc, bw) == false) {
    if (fftmodel == 0) {
      //全景频谱才弹出提示,控守频谱时不管
      bootbox.erro('带宽超出扫频范围');
    }
    panelBwText.val(this.toHzStr(this.currentBw));
    return;
  }
  this.currentBw = bw;
  panelBwText.val(bw);
};
waterfallwidget.prototype.setCtrFc = function (fc, reConn = true) {
  var panelFcText = $('#panel-text-freq');
  if (reConn && fc == this.currentFc) {
    panelFcText.val(this.toHzStr(fc));
    return;
  }
  if (isNaN(fc)) {
    panelFcText.val(this.toHzStr(this.currentFc));
    return;
  }
  if (!Number.isFinite(fc)) {
    bootbox.erro('中心频率格式不正确');
    panelFcText.val(this.toHzStr(this.currentFc));
    return;
  }
  this.currentFc = fc;
  panelFcText.val(this.toHzStr(fc));
};
waterfallwidget.prototype.setParamsToHistory = function (dto) {
  dto = Object.assign(
    {
      fc: 0,
      bw: 0,
      fs: 0,
      pdem: 0,
      sys: 0,
    },
    dto,
  );
  localStorage.setItem('fc', dto.fc);
  localStorage.setItem('bw', dto.bw);
};

waterfallwidget.prototype.drawAdj = function () {
  var _self = this;
  var layer = this.layer_adj;
  layer.destroyChildren();
  layer.removeChildren();

  var yStart = this.margin_top - 45;
  var leftLine = new Konva.Rect({
    x: 0,
    y: this.area_y,
    width: this.adj_lineWidth,
    height: this.area_height,
    fill: this.adj_color,
    name: 'leftLine',
  });
  if (this.allowRunMode == 0) {
    leftLine.on('mouseenter', (e) => {
      if (this.adj_disabled == true) return;
      _self.stage.container().style.cursor = 'e-resize';
    });
    leftLine.on('mouseleave', (e) => {
      if (this.adj_disabled == true) return;
      _self.stage.container().style.cursor = 'default';
    });
    leftLine.on('mousedown', (e) => {
      if (this.adj_disabled == true) return;
      var oevent = e.evt;
      var distanceX = oevent.clientX - leftLine.x();
      _self.alwaysShowAdj || _self.showAdjInfo(e.evt.offsetX, e.evt.offsetY);
      _self.stage.on('contentMousemove', function (e) {
        var freq = _self.getFreqByPoint(e.evt.offsetX);
        if (freq < _self.adj_end) {
          _self.adj_start = freq;
          _self.drawAdjLocation();
        }
        _self.alwaysShowAdj || _self.showAdjInfo(e.evt.offsetX, e.evt.offsetY);
      });
      _self.stage.on('mouseup', function (e) {
        _self.stage.off('contentMousemove');
        _self.stage.off('mouseup');
        _self.alwaysShowAdj || _self.hideInfo();

        _self.fire('adj-manu-change', { start: _self.adj_start, end: _self.adj_end });
      });
    });
  }

  var rightLine = new Konva.Rect({
    x: 0,
    y: this.area_y,
    width: this.adj_lineWidth,
    height: this.area_height,
    fill: this.adj_color,
    name: 'rightLine',
  });

  var centerLine = new Konva.Rect({
    x: 0,
    y: this.area_y,
    width: this.adj_lineWidth,
    height: this.area_height,
    fill: this.adjcenter_color,
    name: 'centerLine',
  });

  if (this.allowRunMode == 0) {
    rightLine.on('mouseenter', (e) => {
      if (this.adj_disabled == true) return;
      _self.stage.container().style.cursor = 'e-resize';
    });
    rightLine.on('mouseleave', (e) => {
      if (this.adj_disabled == true) return;
      _self.stage.container().style.cursor = 'default';
    });
    rightLine.on('mousedown', (e) => {
      if (this.adj_disabled == true) return;
      var oevent = e.evt;
      var distanceX = oevent.clientX - rightLine.x();
      _self.alwaysShowAdj || _self.showAdjInfo(e.evt.offsetX, e.evt.offsetY);
      _self.stage.on('contentMousemove', function (e) {
        var freq = _self.getFreqByPoint(e.evt.offsetX);
        if (freq > _self.adj_start) {
          _self.adj_end = freq;
          _self.drawAdjLocation();
        }
        _self.alwaysShowAdj || _self.showAdjInfo(e.evt.offsetX, e.evt.offsetY);
      });
      _self.stage.on('mouseup', function (e) {
        _self.stage.off('contentMousemove');
        _self.stage.off('mouseup');
        _self.alwaysShowAdj || _self.hideInfo();
        _self.fire('adj-manu-change', { start: _self.adj_start, end: _self.adj_end });
      });
    });
  }
  var rect = new Konva.Rect({
    x: 0,
    y: this.area_y,
    width: 0,
    height: this.area_height,
    fill: this.adj_color,
    opacity: 0.1,
    name: 'rect',
  });
  if (this.allowRunMode == 0) {
    rect
      .on('mouseenter', (e) => {
        if (this.adj_disabled == true) return;
        _self.alwaysShowAdj && _self.showAdjInfo(_self.adj_x, _self.adj_y);
      })
      .on('mouseleave', (e) => {
        _self.hideInfo();
      });

    rect.on('mousedown', function (e) {
      if (e.evt.button === 2) {
        //显示右键菜单
        _self.showContextMenu(e.evt.clientX, e.evt.clientY);
      } else {
        _self.hideContextMenu();
      }
    });
  }

  //layer.add(rect);
  //layer.add(leftLine);
  //layer.add(rightLine);
  var group = new Konva.Group({
    x: 0,
    y: 0,
  });
  group.add(rect);
  group.add(leftLine);
  group.add(rightLine);
  if (this.allowRunMode == 1) {
    group.add(centerLine);
  }

  //实时模式可拖动
  if (this.allowRunMode == 1) {
    group.on('mouseenter', (e) => {
      if (this.adj_disabled == true) return;

      _self.stage.container().style.cursor = 'e-resize';
      var oevent = e.evt;
      var distanceX = oevent.clientX - rightLine.x();
      _self.showAdjInfo(e.evt.offsetX, e.evt.offsetY);
      _self.stage.on('contentMousemove', function (e) {
        _self.showAdjInfo(e.evt.offsetX, e.evt.offsetY);
      });
      group.on('mouseleave', function (e) {
        _self.stage.container().style.cursor = 'default';
        _self.stage.off('contentMousemove');
        group.off('mouseleave');
        _self.hideInfo();
      });
    });

    group.on('mousedown', (e) => {
      if (this.adj_disabled == true) return;

      if (e.evt.button !== 0) return;
      var distanceX = e.evt.clientX;
      //_self.showAdjInfo(e.evt.offsetX, e.evt.offsetY);
      var freq = _self.getAdjCenter();
      var ncenter = 0;
      _self.stage.on('mousemove', function (e) {
        var xx = e.evt.clientX - distanceX;
        var change = _self.getFreqBySpanPoint(xx);
        ncenter = freq + change;
        _self.setAdjCenter(ncenter, false);
      });
      _self.stage.on('mouseup', function (e) {
        _self.setAdjCenter(ncenter, true);
        _self.stage.off('mousemove');
        _self.stage.off('mouseup');
        _self.hideInfo();
      });
    });
  } else if (this.allowRunMode == 0) {
    //非实时模式可穿透放大缩小
    var buttonLR = null;
    rect.on('mousedown', function (e) {
      var distanceX = e.evt.offsetX;
      var distanceY = e.evt.offsetY;
      if (e.evt.button === 0) {
        buttonLR = 'left';
      }

      _self.stage.on('mousemove', async function (e) {
        //只有鼠标左键移动
        if (buttonLR === 'left') {
          _self.drawCoverRect(distanceX, distanceY, e.evt.offsetX, e.evt.offsetY);
        }
      });
      _self.stage.on('mouseup', async function (e) {
        _self.clearCoverLayer();
        if (buttonLR === 'left') {
          var dx = e.evt.offsetX;
          var dy = e.evt.offsetY;
          if (Math.abs(dx - distanceX) < 10) {
          } else if (dx > distanceX) {
            var freqStart = _self.getFreqByPoint(distanceX);
            var freqend = _self.getFreqByPoint(e.evt.offsetX);
            if (freqend - freqStart < 10000) {
              var selectBw = 10000 / 2;
              var selectCenter = Math.round(freqStart + (freqend - freqStart) / 2);
              freqStart = Math.max(selectCenter - selectBw, _self.min_freq);
              freqend = Math.min(selectCenter + selectBw, _self.max_freq);
            }

            _self.setFreqZoomUp(freqStart, freqend);
          } else {
            _self.setFreqZoomDown();
          }
        }

        buttonLR = null;
        _self.stage.off('mousemove');
        _self.stage.off('mouseup');
      });
    });
  }

  layer.add(group);

  _self.drawAdjLocation();
};
waterfallwidget.prototype.showAdj = function () {
  this.adj_show = true;
  this.drawAdjLocation();
};
waterfallwidget.prototype.hiddenAdj = function () {
  this.adj_show = false;
  this.gather_show = false;
  this.drawGatherLocation();
  this.drawAdjLocation();
};
waterfallwidget.prototype.enableAdj = function () {
  this.adj_disabled = false;
};
waterfallwidget.prototype.disableAdj = function () {
  this.adj_disabled = true;
};

waterfallwidget.prototype.drawAdjLocation = function () {
  var layer = this.layer_adj;

  var leftLine = layer.findOne('.leftLine');
  var rightLine = layer.findOne('.rightLine');
  var centerLine = layer.findOne('.centerLine');

  var rect = layer.findOne('.rect');
  if (!leftLine || !rightLine || !rect) {
    return;
  }
  if (this.adj_start > this.adj_end) {
    this.adj_end = this.adj_start;
  }
  leftLine.visible(this.adj_show);
  rightLine.visible(this.adj_show);
  rect.visible(this.adj_show);

  if (this.adj_show) {
    var left = this.getPointByFreq(this.adj_start);
    var right = this.getPointByFreq(this.adj_end);
    var lineWidth = this.adj_lineWidth;
    leftLine.x(left - lineWidth);
    rightLine.x(right);

    if (centerLine) {
      if (this.adj_lineType == 0 || !this.adj_lineType) {
        //cener
        centerLine.x((right + left) / 2 - lineWidth / 2);
      } else if (this.adj_lineType == 1) {
        //LSB
        centerLine.x(right);
      } else if (this.adj_lineType == 2) {
        //USB
        centerLine.x(left - lineWidth);
      }
    }

    this.allowRunMode == 0 && this.alwaysShowAdj && this.showAdjInfo(this.adj_x, this.adj_y);

    rect.x(left);
    rect.width(right - left + lineWidth);
  }

  layer.batchDraw();
};
waterfallwidget.prototype.getAdjCenter = function () {
  var freq = this.adj_start + (this.adj_end - this.adj_start) / 2;

  if (this.adj_lineType == 1) {
    freq = this.adj_end;
  } else if (this.adj_lineType == 2) {
    freq = this.adj_start;
  }
  return freq;
};
waterfallwidget.prototype.getCDBAdjCenter = function () {
  var freq = this.min_freq + (this.max_freq - this.min_freq) / 2;

  if (this.adj_lineType == 1) {
    freq = this.max_freq;
  } else if (this.adj_lineType == 2) {
    freq = this.min_freq;
  }
  return freq;
};
waterfallwidget.prototype.getAdjBw = function () {
  return this.adj_end - this.adj_start;
};
waterfallwidget.prototype.setAdjCenter = function (freq, fireEvent = false) {
  var adjbw = this.getAdjBw();
  var adjcenter = freq;

  if (fireEvent) {
    //修正adjcenter
    if (this.adj_step > 0) {
      adjcenter = Math.round(adjcenter / this.adj_step) * this.adj_step;
    }
  }

  if (this.validataAdj(adjcenter, adjbw, this.adj_lineType) == false) {
    return { result: false, message: '频点超出范围' };
  }

  this.setAdjLeftRight(adjcenter, adjbw, this.adj_lineType);

  if (fireEvent) {
    this.fire('pointer-change', { fc: adjcenter });
  }
  this.drawAdjLocation();
  return { result: true };
};
waterfallwidget.prototype.isAdjCenterInRange = function (freq, bw) {
  var _self = this;
  var adjbw = Math.min(bw, _self.adj_maxbw);

  var adjcenter = freq;
  var left = adjcenter - adjbw / 2;
  var right = adjcenter + adjbw / 2;
  console.log(
    'freq=' +
      freq +
      '_____bw=' +
      bw +
      '___adjbw=' +
      adjbw +
      '____self.adj_maxbw=' +
      _self.adj_maxbw +
      '__left=' +
      left +
      '__right=' +
      right +
      '__this.min_freq=' +
      this.min_freq +
      '___this.max_freq=' +
      this.max_freq,
  );

  if (left < this.min_freq || left > this.max_freq || right < this.min_freq || right > this.max_freq) {
    return false;
  }
  return true;
};
waterfallwidget.prototype.setAdjBand = function (bw) {
  var _self = this;
  var point = this.getAdjCenter();
  var adjbw = Math.min(bw, _self.adj_maxbw);
  if (this.validataAdj(point, adjbw, this.adj_lineType) == false) {
    return { result: false, message: '频点超出范围' };
  }
  this.setAdjLeftRight(point, adjbw, this.adj_lineType);

  this.drawAdjLocation();
  return { result: true };
};
//0正常 1 LSB  2 USB
waterfallwidget.prototype.setAdjPointType = function (adjlinetype = 0) {
  var bw = this.adj_end - this.adj_start;
  var point = this.adj_start + bw / 2;

  if (this.validataAdj(point, bw, adjlinetype) == false) {
    return { result: false, message: '频点超出范围' };
  }

  this.adj_lineType = adjlinetype;

  this.drawAdjLocation();

  return { result: true };
};
waterfallwidget.prototype.validataAdj = function (pointer, bw, type) {
  var arr = this.getAdjLeftRight(pointer, bw, type);
  var left = arr[0];
  var right = arr[1];

  if (left < this.min_freq || left > this.max_freq || right < this.min_freq || right > this.max_freq) {
    return false;
  } else {
    return true;
  }
};
waterfallwidget.prototype.getAdjLeftRight = function (pointer, bw, type) {
  var left = pointer - bw / 2;
  var right = pointer + bw / 2;
  if (type == 2) {
    left = pointer;
    right = pointer + bw;
  } else if (type == 1) {
    right = pointer;
    left = pointer - bw;
  }
  return [left, right];
};
waterfallwidget.prototype.setAdjLeftRight = function (pointer, bw, type) {
  var arr = this.getAdjLeftRight(pointer, bw, type);
  var left = arr[0];
  var right = arr[1];
  this.adj_start = left;
  this.adj_end = right;
};

waterfallwidget.prototype.drawGather = function () {
  var _self = this;
  var layer = this.layer_gather;
  layer.destroyChildren();
  layer.removeChildren();
  _self.gather_fc = this.adj_start + (this.adj_end - this.adj_start) / 2;
  var leftLine = new Konva.Rect({
    x: 0,
    y: this.area_y,
    width: this.adj_lineWidth,
    height: this.area_height,
    fill: '#F37570',
    name: 'leftLine',
  });
  var rightLine = new Konva.Rect({
    x: 0,
    y: this.area_y,
    width: this.adj_lineWidth,
    height: this.area_height,
    fill: '#F37570',
    name: 'rightLine',
  });
  var rect = new Konva.Rect({
    x: 0,
    y: this.area_y,
    width: 0,
    height: this.area_height,
    fill: '#F37570',
    opacity: 0.1,
    name: 'rect',
  });
  var group = new Konva.Group({
    x: 0,
    y: 0,
  });
  group.add(rect);
  group.add(leftLine);
  group.add(rightLine);
  layer.add(group);
};
waterfallwidget.prototype.drawGatherLocation = function () {
  var layer = this.layer_gather;
  var _self = this;
  var leftLine = layer.findOne('.leftLine');
  var rightLine = layer.findOne('.rightLine');

  var rect = layer.findOne('.rect');
  if (!leftLine || !rightLine) {
    return;
  }

  leftLine.visible(this.gather_show);
  rightLine.visible(this.gather_show);
  rect.visible(this.gather_show);
  if (this.gather_show) {
    var left = this.getPointByFreq(this.gather_fc + _self.gather_bw / 2);
    var right = this.getPointByFreq(this.gather_fc - _self.gather_bw / 2);
    var lineWidth = this.adj_lineWidth;
    leftLine.x(left - lineWidth);
    rightLine.x(right);
    rect.x(left);
    rect.width(right - left + lineWidth);
  }
  layer.batchDraw();
};
waterfallwidget.prototype.setGatherBwFc = function (bw, fc) {
  var _self = this;
  _self.gather_show = true;
  _self.gather_bw = bw;
  _self.gather_fc = fc;
  _self.drawGatherLocation();
};
waterfallwidget.prototype.hiddenGather = function () {
  this.gather_show = false;
  _self.drawGatherLocation();
};
/*像素单位转css单位,该函数返回当前浏览器缩放比例所影响的 x y width height 的绘图位置
仅适用putImageData getImageData等函数*/
waterfallwidget.prototype.getDrawWHByPixelRatio = function (xory) {
  if (xory == 0) return 0;
  if (!xory) return xory;
  var ret = Math.ceil(window.devicePixelRatio * xory);
  //console.log(`xory=${xory} ratio=${window.devicePixelRatio} ret=${ret}`);
  return ret;
};

waterfallwidget.prototype.getwf_CtWidth = function () {
  return this.stage.getWidth() - this.margin_left - this.margin_right;
};
waterfallwidget.prototype.getwf_CtHeight = function () {
  return this.stage.getHeight() - this.margin_top - this.margin_bottom;
};

waterfallwidget.prototype.setFreqZoomDown = function () {
  if (this.zoomQueue.length > 0) {
    var d = this.zoomQueue.shift();

    this.setFreqZoom(d.start, d.end);

    return true;
  } else {
    this.setFreqZoom(this.min_freq, this.max_freq);
  }
};
waterfallwidget.prototype.setFreqZoomUp = function (start, end, record = true) {
  //if (this.allowRunMode == 1 && this.adj_show && end - start < this.getAdjBw() * 1.5) {
  //    return false;
  //}
  if (record) {
    this.zoomQueue.unshift({ start: this.freq_start, end: this.freq_end });
  }
  this.setFreqZoom(start, end);

  return true;
};
waterfallwidget.prototype.setFreqZoom = function (start, end) {
  if (!start && !end) {
    start = this.min_freq;
    end = this.max_freq;
  }
  //if (this.adj_show) {
  //    var adjBand = this.getAdjBw();
  //    if (end - start < adjBand * 1.5) {
  //        var adjCenter = this.getAdjCenter();
  //        var nstart = adjCenter - adjBand * 0.8;
  //        var nend = adjCenter + adjBand * 0.8;
  //        start = nstart;
  //        end = nend;
  //    }
  //}

  setTimeout(() => {
    this.SpectrogramBuff = [];
    this.SpectrogramMinBuff = [];
    this.SpectrogramMaxBuff = [];
    this.CompareCurLineBuff = null;
    this.afterglowBuff = [];
  }, 200);

  this.changeStart(start, end, true); //o_zoom >= 0代表不是第一次显示
  this.drawInstant();
  this.drawAdjLocation();
  this.drawGatherLocation();
  this.drawChanel();

  this.drawCarryLine();
  this.drawFreqPointLables();
  return true;
};

waterfallwidget.prototype.clearSpectrogram = function () {
  setTimeout(() => {
    this.SpectrogramBuff = [];
    this.SpectrogramMinBuff = [];
    this.SpectrogramMaxBuff = [];
    this.CompareCurLineBuff = null;
    this.afterglowBuff = [];
  }, 200);
};

waterfallwidget.prototype.changeStart = async function (start, end, reDrawLabel = true) {
  var lastStart = this.freq_start;
  var lastEnd = this.freq_end;

  var changeUi = true;

  if (start < this.min_freq) start = this.min_freq;
  if (end > this.max_freq) end = this.max_freq;

  this.freq_start = Math.floor(start);
  this.freq_end = Math.floor(end);

  if (lastStart !== this.freq_start || lastEnd !== this.freq_end) {
    if (changeUi) {
      this.drawCoorFreq();
      //this.drawAdjLocation();
      this.drawBottomScrollLocal();

      this.drawWFOffset(lastStart, lastEnd);

      //await this.drawWfBuff();
    }
    if (reDrawLabel) {
      // var ret = await $.post('/setting/getIsShowLabelMasker'); // 注释掉接口请求
      this.darwLabel(true); // 使用模拟数据 true
      this.drawWhiteList();
      this.zoomChange();
    }
    return true;
  } else {
    return false;
  }
};
//将当前的画布做缩放重新绘制
waterfallwidget.prototype.drawWFOffset = function (lastStart, lastEnd) {
  var size = this.visual_MapLen;
  var row = this.waterfall_height;
  if (row == 0) return;

  var newStart = this.getPointByFreq(lastStart, true);
  var newWidth = size;
  if (lastEnd) {
    var newEnd = this.getPointByFreq(lastEnd, true);
    newWidth = Math.round(newEnd - newStart);
  }

  if (this.ctx_wf.canvas.width != size || this.ctx_wf.canvas.height != row) {
    this.ctx_wf.canvas.width = size;
    this.ctx_wf.canvas.height = row;
  }

  // Copy scaled FFT canvas to screen
  var width = this.waterfall_width;
  var height = this.waterfall_height;

  var temp = document.createElement('canvas');
  temp.height = row;
  temp.width = size;
  var ctx_temp = temp.getContext('2d');
  ctx_temp.drawImage(this.ctx_wf.canvas, 0, 0, size, row - 1, 0, 0, size, row - 1);

  this.ctx_wf.fillRect(0, 0, size, row);

  this.ctx_wf.drawImage(ctx_temp.canvas, 0, 0, size, row - 1, newStart, 0, newWidth, row - 1);

  this.layer_wf
    .getContext()
    .drawImage(this.ctx_wf.canvas, 0, 0, size, row, this.waterfall_x, this.waterfall_y, width, height);
};

waterfallwidget.prototype.drawWfBuff = async function () {
  //console.log("drawWfBuff");

  if (this.fucFFTBuff) {
    var buff = await this.fucFFTBuff(
      this.freq_start,
      this.freq_end,
      this.waterfall_height,
      this.unitBuffId,
      this.fftModelId,
    );
    if (buff) {
      if (buff.length == 0) return;

      var colors = this.color_map.getMapColors();
      var size = this.visual_MapLen;
      var imgData = this.ctx_wf.createImageData(size, buff.length);

      //var spectrumBuff = null;
      for (var row = 0; row < buff.length; row++) {
        var bins = buff[row];
        var per = bins.length / size;
        var rowImgIndex = size * row * 4;

        if (per > 1) {
          var binVal = 0;
          for (var p = 0; p < size; p++) {
            var binStart = Math.floor(p * per);
            var binEnd = Math.min(Math.floor(p * per + per), bins.length - 1);

            if (binEnd - binStart <= 1) {
              binVal = bins[binStart];
            } else {
              var vals = [];
              for (var q = binStart; q < binEnd; q++) {
                vals.push(bins[q]);
              }
              binVal = Math.max(...vals);
            }
            //解决雪花问题  太小最后反而变为0导致
            if (binVal >= 200) {
              for (var qq = binStart; qq < Math.min(binStart + 10, bins.length); qq++) {
                if (bins[qq] < 200 && bins[qq] > 10) {
                  binVal = bins[qq];
                }
              }
            }

            var cindex = this.squeeze(binVal - 200);
            if (cindex > Math.abs(this.min_db) || 0) {
              console.log(cindex + '-' + colors.length);
              return imgData;
            }
            var color = colors[cindex];

            var i = p * 4;
            if (color) {
              imgData.data[rowImgIndex + i + 0] = color[0];
              imgData.data[rowImgIndex + i + 1] = color[1];
              imgData.data[rowImgIndex + i + 2] = color[2];
              imgData.data[rowImgIndex + i + 3] = 255;
            }
          }
        } else {
          per = size / bins.length;
          for (var j = 0; j < bins.length; j++) {
            var i = Math.floor(j * per) * 4;
            var cindex = this.squeeze(bins[j] - 200);
            if (cindex > Math.abs(this.min_db) || 0) {
              console.log(cindex + '-' + colors.length);
              return imgData;
            }

            var color = colors[cindex];
            if (color) {
              for (var m = 0; m < Math.ceil(per); m++) {
                imgData.data[rowImgIndex + i + m * 4 + 0] = color[0];
                imgData.data[rowImgIndex + i + m * 4 + 1] = color[1];
                imgData.data[rowImgIndex + i + m * 4 + 2] = color[2];
                imgData.data[rowImgIndex + i + m * 4 + 3] = 255;
              }
            }
          }
        }
      }

      this.ctx_wf.putImageData(imgData, 0, 0);
      // Copy scaled FFT canvas to screen
      this.layer_wf
        .getContext()
        .drawImage(
          this.ctx_wf.canvas,
          0,
          0,
          size,
          this.waterfall_height,
          this.waterfall_x,
          this.waterfall_y,
          this.waterfall_width,
          this.waterfall_height,
        );

      //if (spectrumBuff) {
      //    this.drawAllSpectrogram(spectrumBuff);
      //}
    }
  }
};
//标签
waterfallwidget.prototype.darwLabel = async function (status) {
  if (!this.options.label_manager) return; //this.unitBuffId

  var start = this.freq_start;
  var end = this.freq_end;

  var layer = this.layer_label;
  layer.destroyChildren();
  layer.removeChildren();
  var _self = this;
  var rowCount = 2;
  var rowHeight = 12;
  var opaNormal = 0.5;
  var opaSelected = 0.9;
  var opaLine = 0.5;

  var row = 0;
  var rowStart = this.spectrogram_y + 1;

  var labels = await this.options.label_manager.load(start, end);
  if (!status) {
    labels = [];
  }
  for (var i = 0; i < labels.length; i++) {
    var label = labels[i];

    var text = new Konva.Text({
      x: 2,
      y: 2,
      text: label.name,
      fontSize: 10,
      fill: '#B3BAC5', //label.fore_color
    });
    var rect = new Konva.Rect({
      x: 0,
      y: 0,
      fill: label.bg_color, //'#686A78',
      width: text.width() > 0 ? text.width() + 4 : 0,
      height: text.height() > 0 ? text.height() + 4 : 0,
      cornerRadius: 0,
      //stroke: label.bg_color,
      strokeWidth: 0,
      name: 'rect',
    });

    var bw = label.bw;
    var bwWidth = this.getWidthByBw(bw);
    var line = new Konva.Rect({
      x: 0,
      y: 0,
      fill: label.bg_color, //'#B3BAC5',
      width: bwWidth,
      height: this.area_height,
      cornerRadius: 0,
      name: 'line',
      opacity: opaLine,
    });

    var group = new Konva.Group({
      x: _self.getPointByFreq(label.location - bw / 2),
      y: rowStart, //+ row * rowHeight,
      opacity: opaNormal,
    });

    group.label = label;

    group.add(line);
    //group.add(rect);//信号标签标题
    //group.add(text);

    layer.add(group);

    if (this.currentLabel && label.id === this.currentLabel.label.id) {
      group.opacity = opaNormal;
    }
    row++;
    if (row > rowCount - 1) {
      row = 0;
    }
  }
  layer.batchDraw();

  layer.find('Group').on('click', (evt) => {
    var current = evt.currentTarget.label;

    this.label_manager.onclick(current);
  });

  layer.find('Group').on('mouseenter', (evt) => {
    evt.currentTarget.opacity(opaSelected);
    layer.draw();

    evt.currentTarget.on('mouseleave', (evt2) => {
      var label = evt2.currentTarget.label;

      if (!this.currentLabel || this.currentLabel.label.id !== label.id) {
        evt2.currentTarget.opacity(opaNormal);
      }
      evt2.currentTarget.off('mouseleave');

      layer.draw();
    });

    //鼠标滚动放大缩小
    evt.currentTarget.on('wheel', (evt) => {
      if (_self.disableZoom) {
        return;
      }

      var scale = Math.exp((-evt.evt.wheelDelta * 1.0) / 200);
      var freq = this.getFreqByPoint(evt.evt.offsetX);

      //var range = this.freq_end - this.freq_start;
      //var nrange = range * scale;

      var start = freq - (freq - this.freq_start) * scale;
      var end = freq + (this.freq_end - freq) * scale;

      this.throttleSetFreqZoomUp(start, end, false);

      evt.evt.preventDefault();
      evt.evt.stopPropagation();
      return false;
    });

    //鼠标左键
    var buttonLR;

    //放大缩小菜单等
    evt.currentTarget.on('mousedown', function (e) {
      var distanceX = e.evt.offsetX;
      var distanceY = e.evt.offsetY;

      _self.hideContextMenu();
      if (e.evt.button === 2) {
        buttonLR = 'right';
        _self.adj_show = true;
        _self.adj_start = _self.getFreqByPoint(distanceX);
      } else if (e.evt.button === 0) {
        buttonLR = 'left';
      }
      _self.stage.on('mousemove', async function (e) {
        //只有鼠标右键键移动
        if (buttonLR === 'right') {
          if (_self.adj_show && e.evt.offsetX - distanceX > 0) {
            _self.adj_end = _self.getFreqByPoint(e.evt.offsetX);
            _self.drawAdjLocation();
          }
          //_self.stage.off('mouseup');
        }
      });
      _self.stage.on('mouseup', async function (e) {
        _self.clearCoverLayer();
        if (buttonLR === 'right') {
          var dx = e.evt.offsetX;
          var dy = e.evt.offsetY;
          if (!_self.adj_show || e.evt.offsetX - distanceX <= 0) {
            //_self.showLabelsMenu(e);//信号标签右键菜单
          }

          //右键点击
          if (Math.abs(dx - distanceX) < 10) {
            if (_self.adj_show) {
              _self.adj_show = false;
              _self.drawAdjLocation();
            }
          }
        }
        buttonLR = null;
        _self.stage.off('mousemove');
        _self.stage.off('mouseup');
      });
    });
  });

  //layer.find('Group').on('click', evt => {

  //    //_self._setAdjPointer(evt.currentTarget.label.location, true);

  //    //移除以往
  //    if (this.currentLabel && this.currentLabel.label.id !== evt.currentTarget.label.id) {
  //        //判断是因为有可能因为缩放原因,虽然保留引用但是实际已消失了
  //        //if (this.currentLabel.findOne('.rect')) {
  //        //    this.currentLabel.findOne('.rect').stroke(this.currentLabel.label.bg_color);
  //        //    this.currentLabel.findOne('.line').fill(this.currentLabel.label.bg_color);
  //        //}
  //        this.currentLabel.attrs.opacity = 0.4;
  //    }
  //    evt.currentTarget.attrs.opacity = 0.8;
  //    //evt.currentTarget.findOne('.rect').stroke(this.fore_color);
  //    //evt.currentTarget.findOne('.line').fill(this.fore_color);
  //    layer.draw();
  //    if (!this.currentLabel || this.currentLabel.label.id !== evt.currentTarget.label.id) {
  //        _self.fire('label-change', evt.currentTarget.label);
  //    }

  //    this.currentLabel = evt.currentTarget;

  //});
};

waterfallwidget.prototype.getDbByPoint = function (point) {
  if (point > this.spectrogram_y + this.spectrogram_height) {
    return null;
  }
  var perPoint = (this.max_db - this.min_db) / this.spectrogram_height;

  var db = Number(this.max_db - (point - this.spectrogram_y) * perPoint);

  return Math.floor(db);
};
waterfallwidget.prototype.getPointByDb = function (db) {
  var perPoint = (this.max_db - this.min_db) / this.spectrogram_height;

  var h = (this.max_db - db) / perPoint;

  var point = Number(this.spectrogram_y + h);

  return Math.floor(point);
};

waterfallwidget.prototype.getPointByFreq = function (freq, visual) {
  if (visual) {
    var perPoint = (this.freq_end - this.freq_start) / this.visual_MapLen;
    var point = (freq - this.freq_start) / perPoint;
    return point;
  } else {
    var per = (this.freq_end - this.freq_start) / this.waterfall_width;
    var pointr = (freq - this.freq_start) / per;
    return this.margin_left + pointr + 1;
  }
};
waterfallwidget.prototype.getFreqByPoint = function (point) {
  var perPoint = (this.freq_end - this.freq_start) / this.waterfall_width;
  var freq = Number(this.freq_start + (point - this.margin_left - 1) * perPoint);
  freq = Math.min(freq, this.freq_end);
  freq = Math.max(freq, this.freq_start);
  return Math.floor(freq);
};
waterfallwidget.prototype.getFreqBySpanPoint = function (span) {
  var perPoint = (this.freq_end - this.freq_start) / this.waterfall_width;
  return Math.floor(perPoint * span);
};

waterfallwidget.prototype.getWidthByBw = function (bw, visual) {
  if (visual) {
    var perPoint = (this.freq_end - this.freq_start) / this.visual_MapLen;
    var point = bw / perPoint;
    return point;
  } else {
    var per = (this.freq_end - this.freq_start) / this.waterfall_width;
    var pointr = bw / per;
    return pointr + 1;
  }
};

waterfallwidget.prototype.getFreqByPointInZoom = function (point) {
  var count = this.zoomOption[this.freq_zoom].count;
  var per = this.zoomPer;
  var perPoint = (count * per) / this.waterfall_width;

  return perPoint * point;
};
waterfallwidget.prototype.getPointByBand = function (hz) {
  //200p --4000hz
  //return hz / (4000*1.0/200);

  //按真实比例来算
  var count = this.zoomOption[this.freq_zoom].count;
  var per = this.zoomPer;
  var perPoint = (count * per) / this.waterfall_width;

  return (hz * 0.001) / perPoint;
};
waterfallwidget.prototype.getBandByPoint = function (p) {
  //200p --4000hz
  return p * ((4000 * 1.0) / 200);
};

waterfallwidget.prototype._showInfo = function (opt) {
  if (this.info_Position < 0) return;

  var layer = this.layer_info;
  var textInfo = (opt && opt.text) || 'message';
  var x = (opt && opt.x) || 0;
  var y = (opt && opt.y) || 0;
  var centerp = (opt && opt.centerp) || false;
  var textcolor = (opt && opt.textcolor) || this.info_Position == 0 ? this.bg_color : this.fore_color;
  var bgcolor = (opt && opt.bgcolor) || this.info_Position == 0 ? this.fore_color : this.bg_color;

  var text = new Konva.Text({
    x: 10,
    y: 10,
    text: textInfo,
    fontSize: 13,
    fill: textcolor,
  });
  var rect = new Konva.Rect({
    x: 0,
    y: 0,
    fill: bgcolor,
    width: text.width() + 20,
    height: text.height() + 20,
    cornerRadius: 5,
    shadowColor: this.bg_color,
    shadowBlur: 10,
    shadowOffset: [10, 10],
    shadowOpacity: 0.2,
    stroke: this.bg_color,
    strokeWidth: 2,
  });
  var group = new Konva.Group({
    x: 0,
    y: 0,
  });

  group.add(rect);
  group.add(text);

  if (x == 0 && y == 0) {
    x = this.stage.getWidth() / 2 - rect.getWidth() / 2;
    y = this.stage.getHeight() / 2 - rect.getHeight() / 2;
  } else if (centerp) {
    x = x - rect.width() / 2;
  }

  group.x(x);
  group.y(y);
  layer.add(group);

  layer.draw();
};
waterfallwidget.prototype.showInfoAuto = function (opt) {
  var delay = (opt && opt.delay) || 1000;
  var _self = this;
  _self.hideInfo();
  _self.showInfo(opt);

  _self.infoTimeout = setTimeout(function () {
    _self.hideInfo();
  }, delay);
};
waterfallwidget.prototype.hideInfo = function () {
  var layer = this.layer_info;
  var layer5 = this.layer_info5;
  if (this.infoTimeout) {
    clearTimeout(this.infoTimeout);
    this.infoTimeout = null;
  }
  layer.destroyChildren();
  layer.removeChildren();
  layer.draw();
};
waterfallwidget.prototype.showInfo = function (opt, canSetting = false) {
  if (this.infoTimeout) {
    clearTimeout(this.infoTimeout);
    this.infoTimeout = null;
  }
  var _self = this;
  var layer = this.layer_info;
  var message = (opt && opt.text) || 'message';
  var x = (opt && opt.x) || 0;
  var y = (opt && opt.y) || 0;
  var curX = x;
  var curY = y;
  if (canSetting && this.info_Position == 1) {
    x = this.container.clientWidth - this.margin_right - 140;
    y = this.margin_top + 2;
    opt.x = x;
    opt.y = y;
  }

  var centerp = (opt && opt.centerp) || false;

  var text = layer.findOne('Text');

  if (!text) {
    _self._showInfo(opt);
  } else {
    var rect = layer.findOne('Rect');
    var group = layer.findOne('Group');
    text.text(message);
    rect.width(text.width() + 20);
    rect.height(text.height() + 20);

    if (x == 0 && y == 0) {
      x = this.stage.getWidth() / 2 - rect.getWidth() / 2;
      y = this.stage.getHeight() / 2 - rect.getHeight() / 2;
    } else if (centerp) {
      x = x - rect.width() / 2;
    }
    group.x(x);
    group.y(y);

    if (this.showCurLine) {
      var linex = layer.findOne('.linex');
      if (linex) {
        linex.remove();
      }
      var liney = layer.findOne('.liney');
      if (liney) {
        liney.remove();
      }
      linex = new Konva.Line({
        points: [this.waterfall_x, curY, this.waterfall_x + this.waterfall_width, curY],
        stroke: this.fore_color,
        strokeWidth: 1,
        listening: false,
        name: 'linex',
      });
      liney = new Konva.Line({
        points: [curX, this.margin_top, curX, this.stage.getHeight() - this.margin_bottom],
        stroke: this.fore_color,
        strokeWidth: 1,
        listening: false,
        name: 'liney',
      });

      layer.add(linex);
      layer.add(liney);
    }

    layer.draw();
  }
};

waterfallwidget.prototype.showInfoMakeDb = function () {
  if (this.infoTimeout) {
    clearTimeout(this.infoTimeout);
    this.infoTimeout = null;
  }
  var layer5 = this.layer_info5;
  //Mak频差 和 电平差动态改变 所属参数不能为空值
  if (this.MakeShow != null && this.MakeShow.length == 2) {
    var text1 = layer5.findOne('Text');
    var info =
      '频差：' +
      Math.ceil(Math.abs(this.MakeShow[0] - this.MakeShow[1]) / 1000000) +
      'MHz\n电平差:' +
      Math.abs(this.MakeDb - this.MakeDb1) +
      'dBm';
    if (!text1) {
      ////Mak频差 和 电平差 模型初始化
      if (this.MakeShow != null && this.MakeShow.length == 2) {
        var layer5 = this.layer_info5;
        var text1 = new Konva.Text({
          x: 10,
          y: 10,
          text: info,
          fontSize: 13,
          fill: this.info_Position == 0 ? this.bg_color : this.fore_color,
        });
        var rect1 = new Konva.Rect({
          x: 0,
          y: 0,
          fill: this.info_Position == 0 ? this.fore_color : this.bg_color,
          width: text1.width() + 20,
          height: text1.height() + 20,
          cornerRadius: 5,
          shadowColor: this.bg_color,
          shadowBlur: 10,
          shadowOffset: [10, 10],
          shadowOpacity: 0.2,
          stroke: this.bg_color,
          strokeWidth: 2,
        });
        var group1 = new Konva.Group({
          x: 0,
          y: 0,
        });

        group1.add(rect1);
        group1.add(text1);
        group1.x(70);
        group1.y(22);
        layer5.add(group1);
        layer5.draw();
      }
    } else {
      var rect1 = layer5.findOne('Rect');
      var group1 = layer5.findOne('Group');
      rect1.width(text1.width() + 20);
      rect1.height(text1.height() + 20);
      text1.text(info);
      group1.x(this.margin_left + 10);
      group1.y(22);

      if (this.showCurLine) {
        var linex = layer5.findOne('.linex');
        if (linex) {
          linex.remove();
        }
        var liney = layer5.findOne('.liney');
        if (liney) {
          liney.remove();
        }
        linex = new Konva.Line({
          points: [this.waterfall_x, curY, this.waterfall_x + this.waterfall_width, curY],
          stroke: this.fore_color,
          strokeWidth: 1,
          listening: false,
          name: 'linex',
        });
        liney = new Konva.Line({
          points: [curX, this.margin_top, curX, this.stage.getHeight() - this.margin_bottom],
          stroke: this.fore_color,
          strokeWidth: 1,
          listening: false,
          name: 'liney',
        });

        layer5.add(linex);
        layer5.add(liney);
      }

      layer5.draw();
    }
  } else {
    layer5.destroyChildren();
    layer5.removeChildren();
    layer5.draw();
  }
};
waterfallwidget.prototype.showFreqInfo = function (p, auto) {
  //var _self = this;
  //p = p || 'pointer';
  //var x = _self.getPointByFreq(_self.adj_Pointer);
  //var y = _self.margin_top - 80;
  //var text = _self.adj_Pointer + "kHz";
  //if (p == 'band') {
  //    text = "BAND:" + _self.adj_Band + "Hz";
  //}
  //var d = {
  //    text: text,
  //    y: y,
  //    x: x,
  //    centerp: true
  //};
  //if (auto) {
  //    _self.showInfoAuto(d);
  //}
  //else {
  //    _self.showInfo(d);
  //}
};

waterfallwidget.prototype.initContextMenu = function () {
  var p0 = `<div id='warterfall-contextmenu' class="dropdown bootstrapMenu" style="z-index: 10000; position: absolute; display: none;">
<ul class="dropdown-menu" style="position:static;display:block;font-size:0.9em;">`;

  var p1 = '';
  if (this.allowRunMode === 0) {
    p1 = `<li class='ddc-item-click ddc-item' ><a href="javascript:void(0);"><span>单次侦察</span></a></li><li class='divider ddc-item' ></li>`;
  }
  var p1_1 = '';
  if (this.allowRunMode === 0) {
    p1_1 = `<li class='item-loop-ana ddc-item' ><a href="javascript:void(0);"><span>持续侦察</span></a></li><li class='divider ddc-item' ></li>`;
  }
  //备份
  var p1_1_1 = '';
  if (this.allowRunMode === 0) {
    p1_1_1 =
      `<li class="dropdown-submenu action-info ddc-item">
                    <a class="dropdown-item dropdown-toggle" data-toggle="dropdown" data-stopPropagation="true">持续侦察</a>
                    <ul class="dropdown-menu">
                    <li class='ddc-item-click-loop ddc-item' ><a href="javascript:void(0);"><span>循环检测</span></a></li>


<li class='ddc-item-click-loop ddc-item d-none' ><a href="javascript:void(0);"><span>数据采集</span></a></li>
<li class='ddc-item-click-loop ddc-item d-none' ><a href="javascript:void(0);"><span>体制识别</span></a></li>
<li class='ddc-item-click-loop ddc-item d-none' ><a href="javascript:void(0);"><span>信号解调</span></a></li>
<li class='ddc-item-click-loop ddc-item d-none' ><a href="javascript:void(0);"><span>编码识别</span></a></li>
<li class='ddc-item-click-loop ddc-item d-none' ><a href="javascript:void(0);"><span>协议识别</span></a></li>` +
      (this.menuDoppler
        ? `<li class='ddc-item-click ddc-item d-none' ><a href="javascript:void(0);"><span>多普勒估计</span></a></li>`
        : ``) +
      `

</ul>
                </li>
<li class='divider ddc-item' ></li>`;
  }

  var p2 = '';
  if (this.allowRunMode == 1) {
    p2 = `
<li class="dropdown-submenu action-info ddc-item">
                    <a class="dropdown-item dropdown-toggle" data-toggle="dropdown">实时监视</a>
                    <ul class="dropdown-menu">


                    <li data-action="downloadpcm" class="action-info item-sound-add ddc-item">
                        <a href="javascript:void(0);" ><span class="actionName">音频数据(AM/FM)</span></a>
                    </li>

                    <li data-action="downloadfft" class="action-info item-adsb-add ddc-item">
                        <a href="javascript:void(0);" role="menuitem"><span class="actionName">态势(ADS-B)</span></a>
                    </li>
                    <li data-action="downloadfft" class="action-info item-acxx-add ddc-item">
                        <a href="javascript:void(0);" role="menuitem"><span class="actionName">态势(ACXX)</span></a>
                    </li>
                    </ul>
                </li>
<li class='divider ddc-item' ></li>`;
  }

  var p3 = `<li class='ddc-item-click-addExcludes ddc-item' ><a href="javascript:void(0);"><span>添加到黑名单</span></a></li>`;
  var p4 = ``;
  if (this.allowRunMode === 0) {
    p4 = `<li class='divider ddc-item' ></li><li class="dropdown-submenu action-info ddc-item">
                    <a class="dropdown-item dropdown-toggle" data-toggle="dropdown" href="javascript:void(0);">数据采集</a>
                    <ul class="dropdown-menu">`;
    if (this.isADGather == true) {
      p4 += `<li class='ddc-item-click-adnarrowband ddc-item' ><a href="javascript:void(0);"><span>窄带AD采集</span></a></li>
<li class='ddc-item-click-broadband ddc-item' ><a href="javascript:void(0);"><span>宽带AD采集</span></a></li>`;
    }
    //        p4 += `<li class='ddc-item-click-ddc ddc-item' ><a href="javascript:void(0);"><span>单路持续采集</span></a></li>
    //<li class='ddc-item-click-ddc-mut ddc-item ' ><a href="javascript:void(0);"><span>多路持续采集</span></a></li>
    //<li class='ddc-item-click-loop-ddc ddc-item' ><a href="javascript:void(0);"><span>能量触发采集</span></a></li>
    //<li class='ddc-item-click-loop-ddc-xl ddc-item ' ><a href="javascript:void(0);"><span>同步序列触发采集</span></a></li>
    //                    </ul>
    //                </li>`;
    p4 += `<li class='ddc-item-click-ddc ddc-item' ><a href="javascript:void(0);"><span>单路持续采集</span></a></li>
<li class='ddc-item-click-ddc-mut ddc-item ' ><a href="javascript:void(0);"><span>多路持续采集</span></a></li>
                    </ul>
                </li>`;
  }

  //短波
  var p10 = '';
  if (this.isHF) {
    p10 = `<li class='ddc-item-click ddc-item' ><a href="javascript:void(0);"><span>单次侦察</span></a></li><li class='divider ddc-item' ></li>`;
  }
  var p9 = `<li class='ddc-item ddc-item-disable' ><a href="javascript:void(0);"><span>${this.menuDisableText}</span></a></li>
              </ul></div>`;
  var p11 = '';
  if (this.showCheckSignal) {
    p11 = `<li class='ddc-item-click-addSignal'><a href="javascript:void(0);"><span>识别选中信号</span></a></li><li class='divider' ></li>`;
  }
  var p12 = '';
  if (this.showHoppingDetect) {
    p12 = `<li class='ddc-item-click-hoppdetect'><a href="javascript:void(0);"><span>跳频检测</span></a></li><li class='divider ddc-item' ></li>`;
  }

  if (this.isHF) {
    this.contextMenu = $(p0 + p1 + p1_1 + p2 + p11 + p3 + p4 + p9);
  } else if (this.isUHF) {
    this.contextMenu = $(p0 + p1 + p1_1 + p2 + p11 + p12 + p3 + p9); //+ p5
  } else {
    this.contextMenu = $(p0 + p1 + p1_1 + p2 + p11 + p12 + p3 + p4 + p9); //p1_1_2 + p5
  }
  $('body').append(this.contextMenu);
  this.contextMenu.on('click', 'a', (e) => {
    var li = $(e.currentTarget).closest('li');
    if (li.hasClass('ddc-item-click')) {
      this.fire('context-click', { action: $(e.currentTarget).text() });
    }
    //else if (li.hasClass('ddc-item-click-loop')) {
    //    this.fire("context-loop-click", { action: $(e.currentTarget).text() });
    //}
    else if (li.hasClass('ddc-item-click-loop-ddc')) {
      this.fire('context-loop-ddc-click', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('ddc-item-click-loop-ddc-xl')) {
      this.fire('context-loop-xl-ddc-click', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('ddc-item-click-addExcludes')) {
      this.fire('context-addExcludes-click', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('ddc-item-click-ddc')) {
      this.fire('context-ddc-click', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('ddc-item-click-adnarrowband')) {
      this.fire('context-adnarrowband-click', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('ddc-item-click-broadband')) {
      this.fire('context-broadband-click', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('ddc-item-click-ddc-mut')) {
      this.fire('context-ddc-mut-click', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('item-sound-add')) {
      this.fire('context-sound-add-click', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('item-adsb-add')) {
      this.fire('context-adsb-add-click', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('item-acxx-add')) {
      this.fire('context-acxx-add-click', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('item-loop-ana')) {
      this.fire('context-loop-ana-click', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('realtime-monitor')) {
      this.fire('context-realtime-monitor', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('ddc-item-click-addSignal')) {
      this.fire('context-addSignal-click', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('ddc-item-click-hoppdetect')) {
      this.fire('ddc-item-click-hoppdetect', { action: $(e.currentTarget).text() });
    }
    //else if (li.hasClass('item-loop-control')) {
    //    this.fire("context-loop-control-click", { action: $(e.currentTarget).text() });
    //}

    this.hideContextMenu();
  });
  //屏蔽区域内的右键菜单功能20210916 liujg
  this.contextMenu.on('contextmenu', (e) => {
    window.event.returnValue = false;
  });
  //鼠标离开菜单元素后自动隐藏功能菜单
  this.contextMenu.on('mouseleave', (e) => {
    this.hideContextMenu();
  });
};

waterfallwidget.prototype.initLabelsMenu = function () {
  _self = this;
  var p0 = `<div id='warterfall-labelsmenu' class="dropdown bootstrapMenu" style="z-index: 10000; position: absolute; display: none;">
<ul class="dropdown-menu" style="position:static;display:block;font-size:0.9em;">`;

  var p1 = '';
  if (this.allowRunMode === 0) {
    p1 = `<li class="dropdown-submenu action-info ddc-item">
                    <a class="dropdown-item dropdown-toggle" data-toggle="dropdown" data-stopPropagation="true">重新分析</a>
                    <ul class="dropdown-menu">
<li class='item-resysidentity-ana ddc-item' ><a class='label-menu-item' href="javascript:void(0);"><span>体制识别</span></a></li>
<li class='item-redemodsig-ana ddc-item' ><a class='label-menu-item' href="javascript:void(0);"><span>信号解调</span></a></li>
<li class='item-reencodefy-ana ddc-item' ><a class='label-menu-item' href="javascript:void(0);"><span>编码识别</span></a></li>
<li class='item-redoprotocol-ana ddc-item' ><a class='label-menu-item' href="javascript:void(0);"><span>协议识别</span></a></li>

            <li class='item-redoppler-ana ddc-item' ><a class='label-menu-item' href="javascript:void(0);"><span>多普勒估计</span></a></li>
             </ul>
                </li>
<li class='divider ddc-item' ></li>`;
  }
  var p2 = '';
  p2 += `<li class='item-setcolor-ana ddc-item'><a class='label-menu-item' href="javascript:void(0);" id="specColor" name="specColor"><span>颜色标注</span></a></li><li class='divider ddc-item' ></li>`;

  var p3 = `<li class='ddc-item-click-addExcludes ddc-item label-menu-ite' ><a class='label-menu-item' href="javascript:void(0);"><span>添加到黑名单</span></a></li>`;
  var p4 = ``;
  if (this.allowRunMode === 0) {
    p4 = `<li class='divider ddc-item' ></li><li class="dropdown-submenu action-info ddc-item">
                    <a class="dropdown-item dropdown-toggle" data-toggle="dropdown" href="javascript:void(0);">下载数据</a>
                    <ul class="dropdown-menu">`;

    p4 += `<li class='ddc-item-click-adnarrowband ddc-item' ><a class='label-menu-item' href="javascript:void(0);"><span>下载DDC/模采数据</span></a></li>
<li class='ddc-item-click-broadband ddc-item' ><a class='label-menu-item' href="javascript:void(0);"><span>下载解调数据</span></a></li>`;

    p4 += `<li class='ddc-item-click-ddc ddc-item' ><a class='label-menu-item' href="javascript:void(0);"><span>下载解码数据</span></a></li>
                    </ul>
                </li>`;
  }
  var p9 = `<li class='ddc-item ddc-item-disable' ><a href="javascript:void(0);"><span></span></a></li>
</ul></div>`;

  this.labelsMenu = $(p0 + p1 + p2 + p3 + p4 + p9);

  $('body').append(this.labelsMenu);

  this.labelsMenu.on('click', 'a', (e) => {
    var li = $(e.currentTarget).closest('li');
    if (li.hasClass('ddc-item-click')) {
      this.fire('context-click', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('item-setcolor-ana')) {
      this.fire('context-setcolor-click', { action: $(e.currentTarget) });
    } else if (li.hasClass('item-resysidentity-ana')) {
      this.fire('context-resysidentity-click', { action: $(e.currentTarget) });
    } else if (li.hasClass('item-redemodsig-ana')) {
      this.fire('context-redemodsig-click', { action: $(e.currentTarget) });
    } else if (li.hasClass('item-reencodefy-ana')) {
      this.fire('context-reencodefy-click', { action: $(e.currentTarget) });
    } else if (li.hasClass('item-redoprotocol-ana')) {
      this.fire('context-redoprotocol-click', { action: $(e.currentTarget) });
    } else if (li.hasClass('item-redoppler-ana')) {
      this.fire('context-redoppler-click', { action: $(e.currentTarget) });
    } else if (li.hasClass('ddc-item-click-addExcludes')) {
      this.fire('context-addExcludes-click', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('ddc-item-click-loop-ddc')) {
      this.fire('context-loop-ddc-click', { action: $(e.currentTarget).text() });
    } else if (li.hasClass('ddc-item-click-loop-ddc-xl')) {
      this.fire('context-loop-xl-ddc-click', { action: $(e.currentTarget).text() });
    }
    this.hideContextMenu();
  });
  //屏蔽区域内的右键菜单功能20210916 liujg
  this.labelsMenu.on('contextmenu', (e) => {
    window.event.returnValue = false;
  });
  //鼠标离开菜单元素后自动隐藏功能菜单
  this.labelsMenu.on('mouseleave', (e) => {
    this.hideContextMenu();
  });
};
waterfallwidget.prototype.destroryContextMenu = function () {
  this.contextMenu.remove();
  //this.labelsMenu.remove();
};
waterfallwidget.prototype.showLabelsMenu = function (el) {
  if (el) {
    createAttribute(el, 'label-menu-item');
  }
  this.labelsMenu.css('left', el.evt.clientX).css('top', el.evt.clientY);

  setTimeout((ee) => {
    //this.labelsMenu.show();
  }, 200);
};

createAttribute = function (el, itemId) {
  var menuItems = document.getElementsByClassName(itemId);

  if (menuItems.length <= 0) return;

  for (var i = 0; i < menuItems.length; i++) {
    var attr = document.createAttribute('label-id');
    attr.nodeValue = el.target.parent.label.id;
    menuItems[i].attributes.setNamedItem(attr);
  }
};
waterfallwidget.prototype.showContextMenu = function (x, y) {
  this.contextMenu.css('left', x).css('top', y);
  if (this.adj_show) {
    this.contextMenu.find('.ddc-item').removeClass('disabled');
  } else {
    this.contextMenu.find('.ddc-item').addClass('disabled');
  }

  var enable = this.menuEnableHandle ? !this.menuEnableHandle() : false;
  if (enable) {
    this.contextMenu.find('.ddc-item').show();
    this.contextMenu.find('.ddc-item-disable').hide();
  } else {
    this.contextMenu.find('.ddc-item').hide();
    this.contextMenu.find('.ddc-item-disable').show();
  }

  setTimeout((ee) => {
    this.contextMenu.show();
  }, 200);
};
waterfallwidget.prototype.hideContextMenu = function () {
  this.contextMenu.hide();
  //this.labelsMenu.hide();
};

waterfallwidget.prototype.zoomChange = function () {
  this.fire('zoom-change', { start: this.freq_start, end: this.freq_end });
};

waterfallwidget.prototype.setFreqRange = function (min, max) {
  this.min_freq = min;
  this.max_freq = max;

  //this.adj_Pointer = (this.max_freq - this.min_freq) / 2;
  this.zoomPer = (this.max_freq - this.min_freq) / this.zoomOption;
  this.setFreqZoom();
  this.zoomQueue = [];
};

waterfallwidget.prototype.setShowSpectrogramAvg = function (val) {
  this.showSpectrogramAvg = val;
  this.SpectrogramBuff = [];
};
waterfallwidget.prototype.setShowSpectrogramMin = function (val) {
  this.showSpectrogramMin = val;
  this.SpectrogramMinBuff = [];
};
waterfallwidget.prototype.setShowSpectrogramMax = function (val) {
  this.showSpectrogramMax = val;
  this.SpectrogramMaxBuff = [];
};
waterfallwidget.prototype.setShowPeakMarker = function (val) {
  this.showPeakMarker = val;
  if (this.showPeakMarker == false) {
    var context = this.layer_info2.getContext();
    context.clearRect(0, 0, this.layer_info2.getWidth(), this.layer_info2.getHeight());
    //清除Make功能图像
    var context2 = this.layer_info3.getContext();
    context2.clearRect(0, 0, this.layer_info3.getWidth(), this.layer_info3.getHeight());

    var context3 = this.layer_info4.getContext();
    context3.clearRect(0, 0, this.layer_info4.getWidth(), this.layer_info4.getHeight());

    var context = this.layer_info5.getContext();
    context.clearRect(0, 0, this.layer_info5.getWidth(), this.layer_info5.getHeight());

    //var context = this.layer_info6.getContext();
    //context.clearRect(0, 0, this.layer_info6.getWidth(), this.layer_info6.getHeight())

    //var context = this.layer_info7.getContext();
    //context.clearRect(0, 0, this.layer_info7.getWidth(), this.layer_info7.getHeight())
    this.MakeShow = [];
  }
};

//JC添加多点标注功能 20210110
waterfallwidget.prototype.setShowMake = function (bins, val, index) {
  var top = this.spectrogram_y;
  var left = this.spectrogram_x;
  var width = this.spectrogram_width;
  var height = this.spectrogram_height;
  if (this.MakeShow.length <= 0 || this.MakeShow == null) {
    var context = val.getContext();
    context.clearRect(0, 0, val.getWidth(), val.getHeight());
    return;
  }
  if (this.MakeShow[index] > this.freq_start && this.MakeShow[index] < this.freq_end) {
    var band = this.max_db - this.min_db;
    var peakMarkIndex = Math.ceil(
      (this.MakeShow[index] - this.freq_start) / ((this.freq_end - this.freq_start) / bins.length),
    );
    var markv = bins[peakMarkIndex];
    var marky = top + height - ((markv - this.min_db) / band) * height;
    var markx = left + width * (peakMarkIndex / bins.length);
    var markfre = this.getFreqByPoint(markx);
    var textfre = `${(markfre / 1000000).toFixed(3)} MHz`;
    var context = val.getContext();
    context.clearRect(0, 0, val.getWidth(), val.getHeight());
    context.beginPath();
    context.moveTo(markx - 3, marky - 15);
    context.lineTo(markx + 3, marky - 15);
    context.lineTo(markx, marky - 5);
    context.fillStyle = '#ff0000';
    context.fill();

    context.strokeStyle = this.fore_color;
    context.font = '13px serif';
    context.strokeText(textfre, markx + 5, marky - 15);
    context.strokeText(markv.toFixed(2) + ' dBm', markx + 5, marky - 1);
    if (index == 0) {
      this.MakeDb = markv.toFixed(2);
    } else {
      this.MakeDb1 = markv.toFixed(2);
    }
  } else {
    var context = val.getContext();
    context.clearRect(0, 0, val.getWidth(), val.getHeight());
  }
};

//载波检测线
waterfallwidget.prototype.setCarryLineMode = function (val) {
  console.log('setCarryLineMode:' + val);
  this.CarryLineMode = val;
  this.drawCarryLine();
};
waterfallwidget.prototype.setCarryLineList = function (val, fired = true) {
  //console.log("setCarryLineList:" + val);
  this.CarryLineList = val;
  this.drawCarryLine();
  if (fired) {
    this.throttleFireCarryLineChange(val);
  }
};
waterfallwidget.prototype.initCarryLine = function () {
  //必须在init调用一次 否则resize会出问题
  var layer = this.layer_carryline;
  layer.destroyChildren();
  layer.removeChildren();

  this.throttleFireCarryLineChange = _.throttle((vals) => {
    this.fire('carry-line-change', { list: vals });
  }, 100);

  var groupLine = new Konva.Group({
    x: this.area_x,
    y: 0,
    name: 'line-g',
    visible: false,
  });
  groupLine.add(
    new Konva.Line({
      points: [0, -10, this.area_width, 0],
      stroke: 'transparent',
      strokeWidth: 20,
      lineCap: 'round',
      lineJoin: 'round',
      visible: true,
      //dash:[10,4]
    }),
  );
  groupLine.add(
    new Konva.Line({
      points: [0, 0, this.area_width, 0],
      stroke: '#1d8cf8',
      strokeWidth: 2,
      lineCap: 'round',
      lineJoin: 'round',
      visible: true,
      //dash: [10, 4]
    }),
  );
  groupLine.add(
    new Konva.Circle({
      x: this.area_width,
      y: 0,
      fill: '#1d8cf8',
      radius: 3,
    }),
  );
  groupLine.add(
    new Konva.Circle({
      x: 0,
      y: 0,
      fill: '#1d8cf8',
      radius: 3,
    }),
  );

  groupLine.on('mousedown', (e) => {
    console.log(e.evt.button);
    if (e.evt.button != 0) {
      return;
    }
    this.stage.on('mousemove', (e) => {
      var ndb = this.getDbByPoint(e.evt.offsetY);
      if (ndb < this.min_db) {
        ndb = this.min_db;
      }
      if (ndb > this.max_db) {
        ndb = this.max_db;
      }

      this.setCarryLineList([ndb]);
    });
    this.stage.on('mouseup', (e) => {
      this.stage.off('mousemove');
      this.stage.off('mouseup');
    });
  });
  //增益区域鼠标移入鼠标图标变化
  groupLine.on('mouseover', (e) => {
    this.stage.container().style.cursor = 'row-resize';
  });
  groupLine.on('mouseout', (e) => {
    this.stage.container().style.cursor = 'default';
  });

  layer.add(groupLine);

  this.drawCarryLine();
};
waterfallwidget.prototype.clearCarryLine = function () {
  var layer = this.layer_carryline;
  var groupLine1 = layer.findOne('.carryline');
  if (groupLine1) {
    groupLine1.remove();
  }
  var nodes = layer.find('.carryline-node');
  if (nodes) {
    for (item of nodes) {
      item.remove();
    }
  }

  var groupLine = layer.findOne('.line-g');
  if (groupLine) {
    groupLine.visible(false);
  }

  layer.batchDraw();
};
waterfallwidget.prototype.drawCarryLine = function () {
  if (this.CarryLineMode == 1) {
    this.drawCarryLine1();
  } else if (this.CarryLineMode == 2) {
    this.drawCarryLine2();
  } else {
    this.clearCarryLine();
  }
};
//折线
waterfallwidget.prototype.drawCarryLine1 = function () {
  if (!this.CarryLineList) {
    this.CarryLineList = [];
  }
  if (this.CarryLineList.length == 1) {
    //代表是模式2的单值方式
    this.CarryLineList = [];
  }
  var arr = [];
  for (var i = 0; i < this.CarryLineList.length; i += 2) {
    arr.push(this.getPointByFreq(this.CarryLineList[i]));
    arr.push(this.getPointByDb(this.CarryLineList[i + 1]));
  }

  var layer = this.layer_carryline;
  layer.destroyChildren();
  layer.removeChildren();

  var line = new Konva.Line({
    points: arr,
    stroke: '#1d8cf8',
    strokeWidth: 2,
    lineCap: 'round',
    lineJoin: 'round',
    name: 'carryline',
    visible: true,
  });
  layer.add(line);
  for (var i = 0; i < arr.length; i += 2) {
    let circle = new Konva.Circle({
      x: arr[i],
      y: arr[i + 1],
      fill: '#1d8cf8',
      radius: 3,
      name: 'carryline-node',
    });
    layer.add(circle);
  }
  layer.batchDraw();
};
//直线
waterfallwidget.prototype.drawCarryLine2 = function () {
  if (!this.CarryLineList) {
    this.CarryLineList = [-80];
  }
  if (this.CarryLineList.length != 1) {
    this.CarryLineList = [-80];
  }

  var val = this.CarryLineList[0];

  var layer = this.layer_carryline;

  var groupLine = layer.findOne('.line-g');

  //console.log("drawCarryLine2", val, groupLine);

  groupLine.visible(true);
  groupLine.y(this.getPointByDb(val));

  layer.batchDraw();
};

//频率标注
waterfallwidget.prototype.drawFreqPointLableItem = function (item) {
  if (!item) return;
  var layer = this.layer_freqpointlable;
  var textfre = `${(item.freq / 1000000).toFixed(6)} MHz`;
  var id = item.id;
  var color = item.txtColor;
  var info = item.lableInfo;
  var freq = item.freq;
  var txt = item.lableType;
  let _x = this.getPointByFreq(freq);
  if (_x > this.area_x + this.area_width - 5) return;
  _x = _x - 9;
  let _y = this.waterfall_y - 30;
  var fontSize = 18;
  if (txt == '1') {
    txt = '▼';
    _y = _y - 2;
  } else if (txt == '2') {
    txt = '◎';
    _y = _y - 5;
    fontSize = 26;
  } else if (txt == '3') {
    txt = '◆';
    _y = _y - 6;
    fontSize = 30;
  } else if (txt == '4') {
    txt = '■';
    _y = _y - 7;
    fontSize = 24;
  } else if (txt == '5') {
    txt = '★';
    _y = _y - 5;
    fontSize = 22;
  }
  var abcRect = new Konva.Text({
    x: _x,
    y: _y,
    fontSize: fontSize,
    text: txt,
    name: id,
    align: 'center',
    fontFamily: 'Calibri',
    fill: color,
  });
  var _self = this;
  abcRect.on('mousedown', function (e) {
    var id = e.target.attrs.name;
    console.log('mousedown', e.evt);
    if (e.evt.button == 0) {
      //左键编辑
      _self.UpdateFreqPointLable(id);
    } else if (e.evt.button == 2) {
      console.log('id', e.target.attrs);
      //右键删除
      _self.RemoveFreqPointLable(id);
    }
  });
  //增益区域鼠标移入鼠标图标变化
  abcRect.on('mouseover', (e) => {
    this.stage.container().style.cursor = 'pointer';
    _self._showInfo(
      {
        x: e.evt.offsetX - 30,
        y: e.evt.offsetY - 70,
        textcolor: this.fore_color,
        bgcolor: this.bg_color,
        text: '频点:' + textfre + '\r\n' + '标注信息:' + info,
      },
      true,
    );
  });
  abcRect.on('mouseout', (e) => {
    this.stage.container().style.cursor = 'default';
    _self.hideInfo();
  });
  layer.add(abcRect);
};
//新增频点标注
waterfallwidget.prototype.AddFreqPointLable = function (freq) {
  this.fire('freqPointLable-add-click', { freq });
};
//修改频点标注
waterfallwidget.prototype.UpdateFreqPointLable = function (id) {
  this.fire('freqPointLable-update-click', { id });
};
//删除频点标注
waterfallwidget.prototype.RemoveFreqPointLable = function (id) {
  if (this.wfFreqPointLableArray.length == 0) return;
  this.fire('freqPointLable-remove-click', { id });
  this.drawFreqPointLables();
};
//绘制所有频点标注
waterfallwidget.prototype.drawFreqPointLables = function () {
  if (this.wfFreqPointLable == false || !this.wfFreqPointLableArray) return;
  var layer = this.layer_freqpointlable;
  layer.removeChildren();
  for (let i = 0; i < this.wfFreqPointLableArray.length; i++) {
    let item = this.wfFreqPointLableArray[i];
    this.drawFreqPointLableItem(item);
  }
  layer.batchDraw();
};

//初始化频点标注
waterfallwidget.prototype.InitFreqPointLables = function () {
  if (this.wfFreqPointLable == false) return;
  if (this.wfFreqPointLableList && this.wfFreqPointLableList.length > 0) {
    this.wfFreqPointLableArray = this.wfFreqPointLableList;
    this.drawFreqPointLables();
  }
};
//重新设置频点标注数据
waterfallwidget.prototype.SetFreqPointLablesData = function (list) {
  if (this.wfFreqPointLable == false) return;
  //console.log("SetFreqPointLablesData",list);
  if (list) {
    this.wfFreqPointLableArray = list;
  }
  this.drawFreqPointLables();
};
//黑名单
waterfallwidget.prototype.drawWhiteList = async function () {
  var _self = this;
  if (this.showWhitelist) {
    var layer = this.layer_white;
    var opaLine = 0.3;
    var opaNormal = 0.5;
    var opaSelected = 0.9;
    var rowStart = this.spectrogram_y + 1;
    layer.destroyChildren();
    layer.removeChildren();
    var ret = await $.post('/setting/GetWhiteList');
    for (var i = 0; i < ret.data.length; i++) {
      var data = ret.data[i];
      var text = data.name;
      if (data.end <= _self.min_freq || data.start >= _self.max_freq) {
        continue;
      }
      var bw = data.end - data.start;
      var fc = data.start;
      if (fc <= 0 || bw <= 0) {
        continue;
      }
      var text = new Konva.Text({
        x: 2,
        y: 2,
        text: text,
        fontSize: 10,
        fill: '#B3BAC5',
      });
      var rect = new Konva.Rect({
        x: 0,
        y: 0,
        fill: 'transparent',
        width: text.width() > 0 ? text.width() + 4 : 0,
        height: text.height() > 0 ? text.height() + 4 : 0,
        cornerRadius: 0,
        strokeWidth: 0,
        name: 'rect',
      });
      var line = new Konva.Rect({
        x: 0,
        y: 0,
        fill: '#f4f5f7',
        width: _self.getWidthByBw(bw),
        height: this.area_height,
        cornerRadius: 0,
        name: 'line',
        opacity: opaLine,
      });

      var group = new Konva.Group({
        x: _self.getPointByFreq(fc),
        y: rowStart,
        opacity: opaNormal,
      });
      group.add(line);
      group.add(rect);
      group.add(text);
      layer.add(group);
    }
    layer.batchDraw();
  }
};

waterfallwidget.prototype.init = function () {
  if (!this.stage) return; //防止已经销毁但是仍然响应了大小变化事件

  this.stage.setWidth(this.container.clientWidth);
  this.stage.setHeight(this.container.clientHeight);
  //确定位置和大小
  this.area_x = this.margin_left;
  this.area_y = this.margin_top;
  this.area_width = this.stage.getWidth() - this.margin_left - this.margin_right - 2;
  this.area_height = this.stage.getHeight() - this.margin_top - this.margin_bottom - 2;
  this.spectrogram_y = this.margin_top;
  this.spectrogram_x = this.margin_left + 1;
  this.spectrogram_width = this.area_width;
  this.spectrogram_height = Math.floor(this.area_height * this.spec_per) - 1; //分割线
  this.waterfall_y = this.margin_top + this.spectrogram_height + 1;
  this.waterfall_x = this.margin_left + 1;
  this.waterfall_width = this.area_width;
  this.waterfall_height = Math.floor(this.area_height * (1 - this.spec_per));

  this.wf = document.createElement('canvas');
  this.wf.height = this.waterfall_height;
  this.wf.width = this.visual_MapLen;
  this.ctx_wf = this.wf.getContext('2d');
  this.ctx_wf.fillStyle = this.bg_color;

  this.spec = document.createElement('canvas');
  this.spec.height = this.spectrogram_height;
  this.spec.width = this.visual_MapLen;
  this.ctx_spec = this.spec.getContext('2d');
  this.ctx_spec.fillStyle = this.bg_color;
  this.ctx_spec.strokeStyle = this.wave_color;
  this.ctx_spec.lineWidth = 1;

  this.drawCoor();

  this.setFreqZoom();
  this.drawCoorFreq();
  this.drawCoorFreqWheel();

  this.drawBottomScroll();

  this.drawMap();

  this.drawRuler();
  this.drawAdj();
  //if (this.allowRunMode == 0) { this.drawAdj(); }
  if (this.isUHF) {
    this.drawGather();
    this.drawGatherLocation();
  }
  this.split_draw();
  this.darwLabel();
  this.initCarryLine();
  this.InitFreqPointLables(); //频点标注信息
  this.drawWhiteList();
};
waterfallwidget.prototype.destroy = function () {
  this._events = [];
  this.container.oncontextmenu = null;
  this.container = null;
  this.stage.destroy();
  this.stage = null;
  this.color_map = null;
  this.wf = null;
  this.ctx_wf = null;
  this.label_manager = null;

  this.CompareCurLineBuff = [];
  this.wfFreqPointLableArray = [];
  this.layer_coor.destroy();
  this.layer_coorFreq.destroy();
  this.layer_coorFreqWeel.destroy();
  this.layer_wf.destroy();
  this.layer_map.destroy();
  this.layer_mapRuler.destroy();
  //20211228焦超 添加make功能
  this.layer_info3.destroy();
  this.layer_info4.destroy();
  //this.layer_info6.destroy();
  //this.layer_info5.destroy();
  //this.layer_info6.destroy();
  //this.layer_info7.destroy();
  this.layer_adj.destroy();
  this.layer_label.destroy();
  this.layer_labelActive.destroy();

  if (this.layer_split) {
    this.layer_split.destroy(); //2021.05.07 西部需要拖动修改频谱图大小，李伟添加
  }
  this.layer_freqpointlable.destroy();
  this.layer_instant.destroy();
  this.layer_chanel.destroy();
  this.layer_botscroll.destroy();
  this.layer_cover.destroy();
  this.layer_info.destroy();
  this.layer_info2.destroy();
  this.layer_white.destroy();
  this.destroryContextMenu();

  console.log('warterfall destory...............');
};
waterfallwidget.prototype.initResize = function () {
  var _self = this;
  $(this.container).resize(function () {
    var target = this;
    if (target.resizeFlag) {
      clearTimeout(target.resizeFlag);
    }
    target.resizeFlag = setTimeout(function () {
      _self.init();
      target.resizeFlag = null;
    }, 100);
  });
};

function waterfallwidget(id, options) {
  this.options = options;
  this.SpectrogramBuff = [];
  this.SpectrogramBuffCount = 10;
  this.SpectrogramMinBuff = [];
  this.SpectrogramMaxBuff = [];
  this.CompareCurLineBuff = [];
  this.wfFreqPointLableArray = []; //频点标注信息
  this.MakeShow = []; //Make 存储用户选择的频点
  this.MakeDb; //存储用户选择的频点的电平值
  this.MakeDb1; //存储用户选择的频点的电平值

  this.showScrollLocal = options && !options.showScrollLocal ? true : false;

  this.showSpectrogramAvg =
    options && (options.showSpectrogramAvg === false || options.showSpectrogramAvg === true)
      ? options.showSpectrogramAvg
      : false;
  this.showSpectrogramMin =
    options && (options.showSpectrogramMin === false || options.showSpectrogramMin === true)
      ? options.showSpectrogramMin
      : false;
  this.showSpectrogramMax =
    options && (options.showSpectrogramMax === false || options.showSpectrogramMax === true)
      ? options.showSpectrogramMax
      : false;
  this.showPeakMarker =
    options && (options.showPeakMarker === false || options.showPeakMarker === true) ? options.showPeakMarker : false;

  this._events = {};
  var enentNames = [
    'adj-change',
    'pointer-change',
    'band-change',
    'pointer-type-change',
    'zoom-change',
    'label-change',
    'context-click',
    'context-ddc-click',
    'gravity-ruler-change',
  ];
  this.on = function (type, fn, scope) {
    if (type + '' !== type) {
      console && console.error && console.error('the first argument type is requird as string');
      return this;
    }
    if (typeof fn != 'function') {
      console && console.error && console.error('the second argument fn is requird as function');
      return this;
    }
    type = type.toLowerCase();

    if (!this._events[type]) {
      this._events[type] = [];
    }
    this._events[type].push(scope ? [fn, scope] : [fn]);

    return this;
  };
  this.fire = async function (type, data) {
    type = type.toLowerCase();
    var eventArr = this._events[type];
    var fn,
      scope,
      event = Object.assign(
        {
          // 事件类型
          type: type,
          // 绑定的源
          origin: this,
          // scope 为 this 或用户指定的上下文，
          // 是否取消
          cancel: false,
        },
        data,
      );

    if (!eventArr) return event;
    for (var i = 0, l = eventArr.length; i < l; ++i) {
      fn = eventArr[i][0];
      scope = eventArr[i][1];
      if (scope) {
        event.scope = scope;
        fn.call(scope, event);
      } else {
        event.scope = this;
        fn(event);
      }
    }
    return event;
  };
  this.off = function (type, fn) {
    type = type.toLowerCase();
    var eventArr = this._events[type];
    if (!eventArr || !eventArr.length) return this;
    if (!fn) {
      this._events[type] = eventArr = [];
    } else {
      for (var i = 0; i < eventArr.length; ++i) {
        if (fn === eventArr[i][0]) {
          eventArr.splice(i, 1);
          // 1、找到后不能立即 break 可能存在一个事件一个函数绑定多次的情况
          // 删除后数组改变，下一个仍然需要遍历处理！
          --i;
        }
      }
    }
    return this;
  };
  this.one = function (type, fn, scope) {
    var that = this;

    function nfn() {
      // 执行时 先取消绑定
      that.off(type, nfn);
      // 再执行函数
      fn.apply(scope || that, arguments);
    }
    this.on(type, nfn, scope);
    return this;
  };

  this.coorFreqType = options && options.coorFreqType ? options.coorFreqType : 0;
  this.menuEnableHandle = options && options.menuEnableHandle ? options.menuEnableHandle : null;
  this.menuDisableText = options && options.menuDisableText ? options.menuDisableText : '菜单禁止使用';

  this.allowRunMode = options && options.allowRunMode != undefined ? options.allowRunMode : 0;
  this.isADGather = options && options.isADGather != undefined ? options.isADGather : false; //是否开启AD采集
  this.isHF = options && options.isHF != undefined ? options.isHF : false; //是否短波界面
  this.isUHF = options && options.isUHF != undefined ? options.isUHF : false; //是否超短波界面
  //this.allowCycleControl = (options && (options.allowCycleControl === false || options.allowCycleControl === true)) ? options.allowCycleControl : false;;//侦察控守

  this.showCheckSignal = options && options.showCheckSignal != undefined ? options.showCheckSignal : false; //是否显示右键 识别选中信号
  this.showHoppingDetect = options && options.showHoppingDetect != undefined ? options.showHoppingDetect : false; //是否显示超短 跳频检测

  this.min_band = options && options.min_band ? options.min_band : 500;
  this.max_band = options && options.max_band ? options.max_band : 200000;

  //这是整体的频谱大小 hz
  this.min_freq = options && options.min_freq ? options.min_freq : 0;
  this.max_freq = options && options.max_freq ? options.max_freq : 40000;

  //这是当前缩放尺度的大小
  this.freq_start = 0;
  this.freq_end = 0;

  this.disableZoom = options && options.disableZoom ? options.disableZoom : false;
  this.zoomOption = options && options.zoomOption ? options.zoomOption : 16;
  this.zoomPer = (this.max_freq - this.min_freq) / this.zoomOption;
  this.zoomQueue = [];

  this.fucFFTBuff = options && options.fucFFTBuff ? options.fucFFTBuff : null;
  this.unitBuffId = options && options.unitBuffId ? options.unitBuffId : 0;
  this.fftModelId = options && options.fftModelId ? options.fftModelId : 0;

  this.visual_MapLen = 2000;
  // Handle options
  this.min_db = options && options.min_db ? options.min_db : -200;
  this.max_db = options && options.max_db ? options.max_db : 0;
  this.db_counter = options && options.db_counter ? options.db_counter : 10;
  this.onAutomaticAdjustment = options.onAutomaticAdjustment;

  this.info_Position = options && options.info_Position ? options.info_Position : 0; //跟随鼠标  1：右上角

  this.freq_zoom = options && options.freq_zoom ? options.freq_zoom : -1;
  this.show_msFreq =
    options && (options.show_msFreq === false || options.show_msFreq === true) ? options.show_msFreq : true;

  this.showFreqLable =
    options && (options.showFreqLable === false || options.showFreqLable === true) ? options.showFreqLable : true;
  this.wfFreqPointLable =
    options && (options.wfFreqPointLable === false || options.wfFreqPointLable === true)
      ? options.wfFreqPointLable
      : false; //频点标注
  this.wfFreqPointLableList = options && options.wfFreqPointLable === true ? options.wfFreqPointLableList : []; //频点标注数据
  //this.adj_Pointer = (options && options.adj_Pointer) ? options.adj_Pointer : (this.max_freq - this.min_freq) / 2;
  //this.adj_Type = (options && options.adj_Type) ? options.adj_Type : 'center';
  //this.adj_Band = (options && options.adj_Band) ? options.adj_Band : 3600;

  //余晖图
  //this.enableAfterglow = (options && (options.enableAfterglow === false || options.enableAfterglow === true)) ? options.enableAfterglow : false;
  this.delayAfterglow = options && options.delayAfterglow ? options.delayAfterglow : 0; //3秒
  this.isBwFc = options && (options.isBwFc === false || options.isBwFc === true) ? options.show_msFreq : false;
  if (options.adj_show === false) {
    this.adj_show = false;
  } else if (options.adj_show === true) {
    this.adj_show = true;
  } else {
    this.adj_show = this.allowRunMode == 1 ? true : false;
  }
  this.gather_show = this.allowRunMode == 0 ? true : false;
  this.split_show = true; //2021.05.07 西部需求拖动更改频谱窗口大小，李伟添加；

  this.adj_defaultbw = 1;
  this.adj_maxbw = options && options.adj_maxbw ? options.adj_maxbw : 90000000;

  this.adj_lineWidth = this.allowRunMode == 0 ? 1 : 2; //4 : 2
  if (this.adj_lineType == undefined) {
    this.adj_lineType = 0;
  }

  this.adj_color = options && options.adj_color ? options.adj_color : this.allowRunMode == 0 ? '#6CE26C' : '#F37570';
  this.adjcenter_color =
    options && options.adjcenter_color ? options.adjcenter_color : this.allowRunMode == 0 ? '#007ACC' : '#007ACC';

  this.adj_start = options.adj_start;
  this.adj_end = options.adj_end;

  if (!this.adj_start) {
    this.adj_start = this.min_freq + (this.max_freq - this.min_freq) / 2;
  }
  if (!this.adj_end) {
    this.adj_end = this.adj_start + this.adj_defaultbw;
  }
  this.gather_fc = 0;
  this.gather_bw = 0;
  this.adj_step = options && options.adj_step ? options.adj_step : 0;

  this.wf_size = options && options.wf_size ? options.wf_size : 1000;
  this.wf_rows = options && options.wf_rows ? options.wf_rows : 1024;

  this.timeQueue = [];
  this.timeIndex = 0;
  this.time_span = 20; //每20像素画一个时间
  //this.time_out = (options && options.time_out) ? options.time_out : 100; //代表一提供数据的时间单位是 ms 废弃

  this.showCurLine = options && options.showCurLine ? options.showCurLine : false;
  //对比谱线
  this.showCompareCurLine = options && options.showCompareCurLine ? options.showCompareCurLine : false;

  this.time_rate = options && options.time_rate ? options.time_rate : 1; //代表速度(暂未实现) 比如0-1
  //this.bg_color = (options && options.bg_color) ? options.bg_color : '#27293D';
  this.bg_color = options && options.bg_color ? options.bg_color : '#37384B';
  this.fore_color = options && options.bg_color ? options.bg_color : '#CCCCFF';
  this.wave_color = options && options.wave_color ? options.wave_color : '#4BF3A7'; //'#296FF5';
  this.wave_color_avg = options && options.wave_color_avg ? options.wave_color_avg : '#FC6945';
  this.wave_color_max = options && options.wave_color_max ? options.wave_color_max : '#ffff00'; //'#296FF5';//'#00BF9A';
  this.wave_color_min = options && options.wave_color_min ? options.wave_color_min : '#fff';
  this.wave_color_compare = options && options.wave_color_compare ? options.wave_color_compare : '#f5365c';

  this.waveAfterglow_color = options && options.waveAfterglow_color ? options.waveAfterglow_color : '#BCF90A'; //'#296FF5';

  this.instant_color = options && options.instant_color ? options.instant_color : '#f8ffed';
  this.instant_show =
    options && (options.instant_show === false || options.instant_show === true) ? options.instant_show : true;

  this.chanel_color = options && options.chanel_color ? options.chanel_color : '#ffffff';
  this.chanel_show =
    options && (options.chanel_show === false || options.chanel_show === true) ? options.chanel_show : true;

  this.spec_per = options && (options.spec_per === 0 || options.spec_per) ? options.spec_per : 0.5;
  this.labelMode = options && (options.labelMode === false || options.labelMode === true) ? options.labelMode : true;

  this.showWhitelist = options && options.showWhitelist ? options.showWhitelist : false;

  this.label_manager =
    options && options.label_manager
      ? options.label_manager
      : {
          labels: [
            {
              name: 'FM',
              id: 'id1',
              bg_color: '#2bffc6',
              fore_color: '#000',
              location: 80000000,
            },
            {
              name: 'AM',
              id: 'id2',
              bg_color: '#2bffc6',
              fore_color: '#000',
              location: 90000000,
            },
            {
              name: 'USB',
              id: 'id3',
              bg_color: '#fd5d93',
              fore_color: '#fff',
              location: 100000000,
            },
            {
              name: 'FSK',
              id: 'id4',
              bg_color: '#ff8d72',
              fore_color: '#fff',
              location: 110000000,
            },
            {
              name: 'QPSK',
              id: 'id5',
              bg_color: '#5603ad',
              fore_color: '#fff',
              location: 120000000,
            },
            {
              name: '4FSK',
              id: 'id6',
              bg_color: '#5603ad',
              fore_color: '#fff',
              location: 130000000,
            },
            {
              name: 'USB',
              id: 'id7',
              bg_color: '#fd5d93',
              fore_color: '#fff',
              location: 140000000,
            },
            {
              name: '2FSK',
              id: 'id8',
              bg_color: '#ff8d72',
              fore_color: '#fff',
              location: 150000000,
            },
            {
              name: 'LSB',
              id: 'id8',
              bg_color: '#ff8d72',
              fore_color: '#fff',
              location: 160000000,
            },
            {
              name: 'QPSK',
              id: 'id9',
              bg_color: '#5603ad',
              fore_color: '#fff',
              location: 170000000,
            },
          ],
          onclick: function (e) {},
          load: function (start, end) {
            return this.labels.filter((x) => x.location <= end && x.location >= start);
          },
          onRemove: function (id) {
            console.log('label delete' + id);
          },
        };
  //this.label_manager = null;
  this.currentLabel = null;

  this.margin_top = 20;
  if (this.labelMode) {
    this.margin_top = 140;
  }
  this.margin_bottom = 5;
  this.margin_left = 60;
  this.margin_right = 80; // Increased right margin to move content left

  if (!this.options) {
    this.options = {};
  }
  if (!this.options.wfOption) {
    this.options.wfOption = {
      wfRulerEnable: true,
      wfTheme: 'default',
      wfRulerGravity: true,
      wfRulerLocation: -100,
    };
  }
  this.gravity_location = this.options.wfOption.wfRulerLocation;
  this.showRuler = this.options.wfOption.wfRulerEnable;
  //console.log(`option gravity location=${this.gravity_location} gravity_value = ${this.getGravityPerByLocation()}`)
  this.color_map = new colormapwidget({
    name: this.options.wfOption.wfTheme,
    gravity: this.options.wfOption.wfRulerGravity,
    gravity_value: this.getGravityPerByLocation(),
    count: this.max_db - this.min_db,
    mapCount: this.max_db - this.min_db,
  });

  this.container = document.getElementById(id);
  //屏蔽右键菜单
  this.container.oncontextmenu = function () {
    return false;
  };

  this.throttleSetFreqZoomUp = _.throttle((start, end, record) => {
    this.setFreqZoomUp(start, end, record);
  }, 100);

  this.stage = new Konva.Stage({
    container: id, // id of container <div>
    width: this.container.clientWidth || 500,
    height: this.container.clientHeight || 500,
  });

  this.layer_coor = new Konva.Layer();
  this.layer_coor.hitGraphEnabled(false);
  this.layer_coorFreq = new Konva.Layer();
  this.layer_coorFreq.hitGraphEnabled(false);

  this.layer_coorFreqWeel = new Konva.Layer();

  this.layer_wf = new Konva.Layer();
  this.layer_wf.hitGraphEnabled(false);
  this.layer_map = new Konva.Layer();
  this.layer_mapRuler = new Konva.Layer();
  //绿色，在侦察模型下 能右键选中的区域。
  this.layer_adj = new Konva.Layer();
  //this.layer_split = new Konva.Layer();//2021.05.07 西部需要拖动修改频谱图大小，李伟添加

  this.layer_label = new Konva.Layer();
  this.layer_labelActive = new Konva.Layer();

  this.layer_info = new Konva.Layer();
  this.layer_info.hitGraphEnabled(false);

  this.layer_info2 = new Konva.Layer();
  this.layer_info2.hitGraphEnabled(false);

  this.layer_instant = new Konva.Layer();
  this.layer_instant.hitGraphEnabled(false);

  this.layer_chanel = new Konva.Layer();
  this.layer_chanel.hitGraphEnabled(false);

  this.layer_cover = new Konva.Layer();
  this.layer_cover.hitGraphEnabled(false);

  this.layer_carryline = new Konva.Layer();
  //this.layer_carryline.hitGraphEnabled(false);

  this.layer_botscroll = new Konva.Layer();

  //多点标记功能
  this.layer_info3 = new Konva.Layer();
  this.layer_info3.hitGraphEnabled(false);

  this.layer_info4 = new Konva.Layer();
  this.layer_info4.hitGraphEnabled(false);

  this.layer_info5 = new Konva.Layer();
  this.layer_info5.hitGraphEnabled(false);
  //该层是砖红色的，在超短波模式下代表当前通道真实带宽。
  this.layer_gather = new Konva.Layer();
  this.layer_gather.hitGraphEnabled(false);

  //this.layer_info6 = new Konva.Layer();
  //this.layer_info6.hitGraphEnabled(false);

  //this.layer_info7 = new Konva.Layer();
  //this.layer_info7.hitGraphEnabled(false);
  //频点标记 频率尺 标记 三角形 圆形 菱形 dhj 20241215
  this.layer_freqpointlable = new Konva.Layer();
  this.layer_freqpointlable.hitGraphEnabled(true);

  this.layer_white = new Konva.Layer();
  this.layer_white.hitGraphEnabled(true);

  this.stage.add(this.layer_coor);
  this.stage.add(this.layer_wf);
  this.stage.add(this.layer_coorFreq);
  this.stage.add(this.layer_labelActive);

  this.stage.add(this.layer_coorFreqWeel);

  this.stage.add(this.layer_label);

  this.stage.add(this.layer_map);
  this.stage.add(this.layer_mapRuler);

  this.stage.add(this.layer_adj);
  this.stage.add(this.layer_gather);
  this.stage.add(this.layer_white);
  //this.stage.add(this.layer_split);//2021.05.07 西部需要拖动修改频谱图大小，李伟添加
  this.stage.add(this.layer_instant);
  this.stage.add(this.layer_chanel);
  this.stage.add(this.layer_botscroll);
  this.stage.add(this.layer_cover);
  this.stage.add(this.layer_carryline);
  this.stage.add(this.layer_info);
  this.stage.add(this.layer_info2);

  //JC添加make功能
  this.stage.add(this.layer_info3);
  this.stage.add(this.layer_info4);
  this.stage.add(this.layer_info5);
  //this.stage.add(this.layer_info6);
  this.stage.add(this.layer_freqpointlable);
  //this.stage.add(this.layer_info7);
  this.initContextMenu();
  // this.initLabelsMenu();
  this.init();

  this.initResize();
}
