diff --git a/.oxlintrc.json b/.oxlintrc.json
index 2acabca..f5adeba 100644
--- a/.oxlintrc.json
+++ b/.oxlintrc.json
@@ -8,6 +8,8 @@
"src/shadcn/**",
"src/components/InspiraUI/**",
"**/planispherewidget.js",
- "**/konva.2.4.2.min.js"
+ "**/konva.2.4.2.min.js",
+ "**/waterfallwidget.js",
+ "**/colormapwidget.js"
]
}
diff --git a/eslint.config.ts b/eslint.config.ts
index c1b1550..b2f16b8 100644
--- a/eslint.config.ts
+++ b/eslint.config.ts
@@ -36,6 +36,8 @@ const _ignores = [
'src/components/InspiraUI/**',
'**/planispherewidget.js',
'**/konva.*.min.js',
+ '**/waterfallwidget.js',
+ '**/colormapwidget.js',
]),
// <<<
];
diff --git a/src/pages/Page/canvas/ConstellationDiagram/ConstellationDiagram.md b/src/pages/Page/canvas/ConstellationDiagram/ConstellationDiagram.md
new file mode 100644
index 0000000..fcce86f
--- /dev/null
+++ b/src/pages/Page/canvas/ConstellationDiagram/ConstellationDiagram.md
@@ -0,0 +1 @@
+- [卫星星座图绘制原理](https://juejin.cn/post/6844904142448640007)
diff --git a/src/pages/Page/canvas/_星座图示例数据_100.ts b/src/pages/Page/canvas/ConstellationDiagram/_星座图示例数据_100.ts
similarity index 100%
rename from src/pages/Page/canvas/_星座图示例数据_100.ts
rename to src/pages/Page/canvas/ConstellationDiagram/_星座图示例数据_100.ts
diff --git a/src/pages/Page/canvas/_星座图示例数据_50.ts b/src/pages/Page/canvas/ConstellationDiagram/_星座图示例数据_50.ts
similarity index 100%
rename from src/pages/Page/canvas/_星座图示例数据_50.ts
rename to src/pages/Page/canvas/ConstellationDiagram/_星座图示例数据_50.ts
diff --git a/src/pages/Page/canvas/ConstellationDiagram.page.vue b/src/pages/Page/canvas/ConstellationDiagram/index.page.vue
similarity index 97%
rename from src/pages/Page/canvas/ConstellationDiagram.page.vue
rename to src/pages/Page/canvas/ConstellationDiagram/index.page.vue
index c11ff3c..9d40652 100644
--- a/src/pages/Page/canvas/ConstellationDiagram.page.vue
+++ b/src/pages/Page/canvas/ConstellationDiagram/index.page.vue
@@ -2,6 +2,7 @@
import { onMounted } from 'vue';
import { 星座图示例数据_50点 } from './_星座图示例数据_50.js';
+import './konva.2.4.2.min.js'; // 引入 Konva 库
import { PlanisphereWidget } from './planispherewidget.js'; // 导入 onMounted
definePage({
diff --git a/src/pages/Page/canvas/konva.2.4.2.min.js b/src/pages/Page/canvas/ConstellationDiagram/konva.2.4.2.min.js
similarity index 100%
rename from src/pages/Page/canvas/konva.2.4.2.min.js
rename to src/pages/Page/canvas/ConstellationDiagram/konva.2.4.2.min.js
diff --git a/src/pages/Page/canvas/planispherewidget.js b/src/pages/Page/canvas/ConstellationDiagram/planispherewidget.js
similarity index 96%
rename from src/pages/Page/canvas/planispherewidget.js
rename to src/pages/Page/canvas/ConstellationDiagram/planispherewidget.js
index f11bb83..e0e9394 100644
--- a/src/pages/Page/canvas/planispherewidget.js
+++ b/src/pages/Page/canvas/ConstellationDiagram/planispherewidget.js
@@ -1,6 +1,4 @@
// @ts-nocheck
-import './konva.2.4.2.min';
-
export class PlanisphereWidget {
constructor(id, options) {
console.log('PlanisphereWidget ' + id);
@@ -428,16 +426,16 @@ export class PlanisphereWidget {
this.destroy();
}
// initResize() {
- // 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);
- // });
+ // 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);
+ // });
// }
}
diff --git a/src/pages/Page/canvas/Spectrogram/Spectrogram.md b/src/pages/Page/canvas/Spectrogram/Spectrogram.md
new file mode 100644
index 0000000..66eac40
--- /dev/null
+++ b/src/pages/Page/canvas/Spectrogram/Spectrogram.md
@@ -0,0 +1,10 @@
+在卫星领域,语谱图(spectrogram)也发挥着重要的作用,主要应用于以下方面:
+
+- **信号分析与识别:**
+ - **信号干扰检测:** 通过观察语谱图,可以快速发现是否存在对卫星信号的干扰,例如人为的干扰(jamming)或意外的频率冲突。干扰信号通常在语谱图上会显示出异常的能量分布或特定的频率模式。
+ - **信号欺骗检测 (Spoofing):** 在卫星导航领域,语谱图可以帮助识别欺骗信号。欺骗信号可能会伪造卫星的定位信息,语谱图可以显示出与真实信号不同的特征。
+- **雷达应用:**
+ - **空间目标监视 (Space Domain Awareness):** 雷达卫星或地面雷达站利用语谱图分析反射回来的信号,可以识别和跟踪空间中的物体,如废弃的卫星或碎片。通过分析信号的多普勒频移等信息,可以估计目标的速度和距离。
+ - 研究报告提到,通过观察RHESSI卫星的观测数据生成的语谱图,可以进行空间目标监视的微多普勒特征分析。
+- **科学研究:**
+ - **粒子数据分析:** 在某些卫星任务中,例如分析太空中的粒子 flux(流量),可以将粒子能量随时间和空间(例如 McIlwain L 参数)的变化绘制成二维彩色图,这种图也被称为语谱图。虽然这里的语谱图侧重于能量分布而非频率,但可视化的原理是相似的。
diff --git a/src/pages/Page/canvas/Spectrogram/colormapwidget.js b/src/pages/Page/canvas/Spectrogram/colormapwidget.js
new file mode 100644
index 0000000..69b0202
--- /dev/null
+++ b/src/pages/Page/canvas/Spectrogram/colormapwidget.js
@@ -0,0 +1,153 @@
+// @ts-nocheck
+colormapwidget.names = ['default', 'blue', 'gray', 'cooledit'];
+
+colormapwidget.prototype.getGradientColors = function (name) {
+ if (name == 'blue') {
+ return ['#050525', '#000CFF', '#33FFFF', '#F9FFFF'];
+ } else if (name == 'gray') {
+ return ['#050525', '#FBFBFB'];
+ } else if (name == 'cooledit') {
+ return ['#010E19', '#720271', '#D7032C', '#FDBC5F', '#F8FFED'];
+ } else {
+ return ['#050525', '#0000CF', '#00FF20', '#EFFF00', '#FF007C'];
+ }
+};
+// 将hex表示方式转换为rgb表示方式(这里返回rgb数组模式)
+colormapwidget.prototype.colorRgb = function (sColor) {
+ var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
+ var sColor = sColor.toLowerCase();
+ 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 sColorChange;
+ } else {
+ return sColor;
+ }
+};
+
+// 将rgb表示方式转换为hex表示方式
+colormapwidget.prototype.colorHex = function (rgb) {
+ var reg = /(\d{1,3}),(\d{1,3}),(\d{1,3})/;
+ var arr = reg.exec(rgb);
+
+ function hex(x) {
+ return ('0' + parseInt(x).toString(16)).slice(-2);
+ }
+ var _hex = '#' + hex(arr[1]) + hex(arr[2]) + hex(arr[3]);
+ return _hex.toUpperCase();
+};
+
+//计算两个颜色的step个阶梯色
+colormapwidget.prototype.gradientColor = function (startColor, endColor, step) {
+ var startRGB = this.colorRgb(startColor); //转换为rgb数组模式
+ var startR = startRGB[0];
+ var startG = startRGB[1];
+ var startB = startRGB[2];
+
+ var endRGB = this.colorRgb(endColor);
+ var endR = endRGB[0];
+ var endG = endRGB[1];
+ var endB = endRGB[2];
+
+ var sR = (endR - startR) / step; //总差值
+ var sG = (endG - startG) / step;
+ var sB = (endB - startB) / step;
+
+ var colorArr = [];
+ for (var i = 0; i < step; i++) {
+ //计算每一步的hex值
+ //var hex = this.colorHex('rgb('+parseInt((sR*i+startR))+','+parseInt((sG*i+startG))+','+parseInt((sB*i+startB))+')');
+ //colorArr.push(hex);
+ colorArr.push([parseInt(sR * i + startR), parseInt(sG * i + startG), parseInt(sB * i + startB)]);
+ }
+ return colorArr;
+};
+
+colormapwidget.prototype.setDbRange = function (count) {
+ this.count = count;
+ this.mapCount = count;
+ this.calColors();
+};
+
+colormapwidget.prototype.getColors = function () {
+ if (
+ this.name === this.buff_name &&
+ this.gravity === this.buff_gravity &&
+ this.gravity_value === this.buff_gravity_value &&
+ this.count === this.buff_count
+ )
+ return this.buff_colors;
+
+ return this.calColors();
+};
+colormapwidget.prototype.getMapColors = function () {
+ return this.buff_mapCountcolors;
+};
+
+colormapwidget.prototype.calColors = function () {
+ this.buff_name = this.name;
+ this.buff_gravity = this.gravity;
+ this.buff_gravity_value = this.gravity_value;
+ this.buff_count = this.count;
+
+ this.buff_colors = this._calColorsByCount(this.count);
+ this.buff_mapCountcolors = this._calColorsByCount(this.mapCount);
+
+ return this.buff_colors;
+};
+
+colormapwidget.prototype._calColorsByCount = function (count) {
+ //console.log("_calColorsByCount " + count)
+ var colors = this.getGradientColors(this.name);
+ var arr = [];
+ var stepSpan = colors.length - 1;
+ if (!this.gravity) {
+ var step = Math.ceil(count / stepSpan);
+ for (var i = 0; i < stepSpan; i++) {
+ var carr = this.gradientColor(colors[i], colors[i + 1], step);
+ arr = arr.concat(carr);
+ }
+ } else {
+ var pStart = this.gravity_value - 0.2;
+ pStart = pStart < 0 ? 0 : pStart;
+ var pEnd = this.gravity_value + 0.2;
+ pEnd = pEnd > 1 ? 1 : pEnd;
+ pStart = count * pStart;
+ pEnd = count * pEnd;
+
+ for (var i = 0; i < pStart; i++) {
+ arr.push(this.colorRgb(colors[0]));
+ }
+
+ var step = Math.ceil((pEnd - pStart + 1) / stepSpan);
+ for (var i = 0; i < stepSpan; i++) {
+ var carr = this.gradientColor(colors[i], colors[i + 1], step);
+ arr = arr.concat(carr);
+ }
+
+ for (var i = pEnd; i < count; i++) {
+ arr.push(this.colorRgb(colors[colors.length - 1]));
+ }
+ }
+ return arr;
+};
+
+function colormapwidget(option) {
+ this.name = option && option.name ? option.name : 'default';
+ this.gravity = option && option.gravity ? option.gravity : false;
+ this.gravity_value = option && option.gravity_value ? option.gravity_value : 0.5;
+ this.count = option && option.count ? option.count : 200;
+ this.mapCount = option && option.mapCount ? option.mapCount : 200;
+
+ this.getColors();
+}
diff --git a/src/pages/Page/canvas/Spectrogram/index.page.vue b/src/pages/Page/canvas/Spectrogram/index.page.vue
new file mode 100644
index 0000000..70b25aa
--- /dev/null
+++ b/src/pages/Page/canvas/Spectrogram/index.page.vue
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/Page/canvas/Spectrogram/waterfallwidget.js b/src/pages/Page/canvas/Spectrogram/waterfallwidget.js
new file mode 100644
index 0000000..39071a0
--- /dev/null
+++ b/src/pages/Page/canvas/Spectrogram/waterfallwidget.js
@@ -0,0 +1,4711 @@
+// @ts-nocheck
+export 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(ret.data);
+ 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 = `
`;
+ var p11 = '';
+ if (this.showCheckSignal) {
+ p11 = `识别选中信号`;
+ }
+ var p12 = '';
+ if (this.showHoppingDetect) {
+ p12 = `跳频检测`;
+ }
+
+ 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 = ``;
+
+ 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 = 40;
+
+ 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
+ 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();
+}
diff --git a/src/types/shims/global.ts b/src/types/shims/global.d.ts
similarity index 100%
rename from src/types/shims/global.ts
rename to src/types/shims/global.d.ts
diff --git a/src/types/shims/md.d.ts b/src/types/shims/md.d.ts
new file mode 100644
index 0000000..5e50255
--- /dev/null
+++ b/src/types/shims/md.d.ts
@@ -0,0 +1,8 @@
+declare module '*.md' {
+ import type { ComponentOptions } from 'vue';
+
+ const Component: ComponentOptions;
+ export default Component;
+}
+
+export {};
diff --git a/typed-router.d.ts b/typed-router.d.ts
index 70e80dd..4065350 100644
--- a/typed-router.d.ts
+++ b/typed-router.d.ts
@@ -27,6 +27,7 @@ declare module 'vue-router/auto-routes' {
'Home': RouteRecordInfo<'Home', '/Home', Record, Record>,
'PageAPI': RouteRecordInfo<'PageAPI', '/Page/API', Record, Record>,
'PageCanvasConstellationDiagram': RouteRecordInfo<'PageCanvasConstellationDiagram', '/Page/canvas/ConstellationDiagram', Record, Record>,
+ 'PageCanvasSpectrogram': RouteRecordInfo<'PageCanvasSpectrogram', '/Page/canvas/Spectrogram', Record, Record>,
'PageFonts': RouteRecordInfo<'PageFonts', '/Page/fonts', Record, Record>,
'PageIcons': RouteRecordInfo<'PageIcons', '/Page/Icons', Record, Record>,
'PageJSPage': RouteRecordInfo<'PageJSPage', '/Page/JSPage', Record, Record>,
diff --git a/vite.config.ts b/vite.config.ts
index 88419d7..a186853 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -32,6 +32,7 @@ export default defineConfig(({ command, mode }) => {
'@ant-design/icons-vue',
'ant-design-vue/es',
'p5',
+ '@splinetool/runtime'
],
exclude: ['quill', 'chart.js/auto'],
},