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'], },