From e6daa47a388a06c5d36e5ee642b7e6490b665e3f Mon Sep 17 00:00:00 2001 From: SHAOJIAHAO <55341701@qq.com> Date: Sat, 4 Mar 2023 17:05:41 +0800 Subject: [PATCH] =?UTF-8?q?[=E6=96=B0=E5=A2=9E]=E9=BB=84=E6=B5=B7=E7=9B=92?= =?UTF-8?q?=E5=AD=90=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../analysis-of-the-host.component.html | 9 + .../analysis-of-the-host.component.ts | 29 +- .../host-config/host-config.component.html | 7 +- .../host-config/host-config.component.ts | 57 +- .../image-label/image-label.component.html | 53 +- .../image-label/image-label.component.scss | 79 +- .../image-label/image-label.component.ts | 860 ++++++++++++++---- .../system-management.module.ts | 49 +- 8 files changed, 938 insertions(+), 205 deletions(-) diff --git a/src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.html b/src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.html index 48d71cb..83207c2 100644 --- a/src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.html +++ b/src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.html @@ -48,6 +48,15 @@ 配置 + + + + + + + + 下载设备编号 diff --git a/src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.ts b/src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.ts index 18d5e47..9d0f3f5 100644 --- a/src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.ts +++ b/src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.ts @@ -37,11 +37,9 @@ export class AnalysisOfTheHostComponent implements OnInit { router.events .pipe(filter((e) => e instanceof NavigationEnd)) .subscribe((e) => { - - if(this.selectedOilStation && this.selectedOilStation.id){ + if (this.selectedOilStation && this.selectedOilStation.id) { this.getHost(); } - }); } ngOnInit(): void { @@ -204,12 +202,31 @@ export class AnalysisOfTheHostComponent implements OnInit { }); } + isVisible = false; + radioValue = '交大'; + configdata; config(data) { - this.router.navigate([`/system/host/camera`], { - queryParams: { hostId: data.id, orId: this.selectedOilStation.id }, - }); + this.isVisible = true; + this.configdata = data; + } + + handleOk(): void { + this.isVisible = false; + + setTimeout(() => { + this.router.navigate([`/system/host/camera`], { + queryParams: { + hostId: this.configdata.id, + orId: this.selectedOilStation.id, + type: this.radioValue, + }, + }); + }, 0); } + handleCancel(): void { + this.isVisible = false; + } download(data) { console.log(data); let params = { diff --git a/src/app/system-management/host-config/host-config.component.html b/src/app/system-management/host-config/host-config.component.html index d560e67..f97bc44 100644 --- a/src/app/system-management/host-config/host-config.component.html +++ b/src/app/system-management/host-config/host-config.component.html @@ -53,12 +53,15 @@ -
diff --git a/src/app/system-management/host-config/host-config.component.ts b/src/app/system-management/host-config/host-config.component.ts index b21ad4b..c17f0f5 100644 --- a/src/app/system-management/host-config/host-config.component.ts +++ b/src/app/system-management/host-config/host-config.component.ts @@ -20,6 +20,7 @@ import { catchError, tap } from 'rxjs/operators'; import { ConfigFormDataService } from 'src/app/service/configFormData.service'; import { SendFileComponent } from './send-file/send-file.component'; import { ImageLabel2Component } from '../image-label2/image-label2.component'; +import { ImageLabelComponent } from '../image-label/image-label.component'; interface Camera { name: string; user: string; @@ -50,9 +51,12 @@ export class HostConfigComponent implements OnInit { hostId; //主机id orId; //加油站id + hostType; //黄海还是交大的盒子 ngOnInit(): void { this.hostId = this.route.snapshot.queryParams.hostId; this.orId = this.route.snapshot.queryParams.orId; + + this.hostType = this.route.snapshot.queryParams.type; this.getCamera(); this.http.get(`/api/EdgeDevices/${this.hostId}`).subscribe({ @@ -203,15 +207,46 @@ export class HostConfigComponent implements OnInit { label(item) { this.http.get(`/api/EdgeDevices/${this.hostId}`).subscribe({ next: (data: any) => { - if (data.configFiles) { - this.isSourceYaml = true; + if (this.hostType == '交大') { + if (data.configFiles) { + this.isSourceYaml = true; + const element = document.documentElement; + if (element.requestFullscreen) { + //进入全屏 + element.requestFullscreen(); + } + const modal = this.modal.create({ + nzContent: ImageLabel2Component, + nzViewContainerRef: this.viewContainerRef, + nzWidth: 1920, + nzClosable: false, + nzFooter: null, + nzWrapClassName: 'canvasContentBox', + nzBodyStyle: { + 'border-radius': '0px', + padding: '0px', + margin: '0px', + }, + nzComponentParams: { + data: item.id, + }, + nzOnOk: async () => {}, + }); + modal.afterClose.subscribe((result) => { + this.ngOnInit(); + }); + } else { + this.isSourceYaml = false; + this.message.create('error', '请先下发source.yaml配置'); + } + } else if (this.hostType == '黄海') { const element = document.documentElement; if (element.requestFullscreen) { //进入全屏 element.requestFullscreen(); } const modal = this.modal.create({ - nzContent: ImageLabel2Component, + nzContent: ImageLabelComponent, nzViewContainerRef: this.viewContainerRef, nzWidth: 1920, nzClosable: false, @@ -223,24 +258,15 @@ export class HostConfigComponent implements OnInit { margin: '0px', }, nzComponentParams: { - data: item.id, + cameraId: item.id, }, - nzOnOk: async () => {}, }); - const instance = modal.getContentComponent(); - modal.afterClose.subscribe((result) => { this.ngOnInit(); }); - //this.router.navigate(['/system/host/camera/imageLabel'], { queryParams: { id: item.id } }) - } else { - this.isSourceYaml = false; - this.message.create('error', '请先下发source.yaml配置'); } }, - error: (err) => { - // this.message.create('error', '请先下发source.yaml配置'); - }, + error: (err) => {}, }); } @@ -1110,4 +1136,7 @@ rule_threshold: sessionStorage.setItem('config3', config3); sessionStorage.setItem('config4', config4); } + + //黄海配置文件 + config() {} } diff --git a/src/app/system-management/image-label/image-label.component.html b/src/app/system-management/image-label/image-label.component.html index 9b2c16e..c0293d7 100644 --- a/src/app/system-management/image-label/image-label.component.html +++ b/src/app/system-management/image-label/image-label.component.html @@ -1,12 +1,51 @@ -
+
+
- - - + + + + + + + + + + + + + + + + + + + + + + +
-
+ + +
-
+
+
-
+
\ No newline at end of file diff --git a/src/app/system-management/image-label/image-label.component.scss b/src/app/system-management/image-label/image-label.component.scss index 89f7b5b..8ee26e6 100644 --- a/src/app/system-management/image-label/image-label.component.scss +++ b/src/app/system-management/image-label/image-label.component.scss @@ -1,26 +1,77 @@ -.box { +.canvasBox { width: 100%; height: 100%; + background: #fff; + font-size: 15px; + color: black; + box-sizing: border-box; display: flex; flex-direction: column; -} + overflow: hidden; -.btnbox { - margin-bottom: 5px; - button { - margin-right: 15px; + .imgbox { + flex: 1; + overflow: hidden; } -} -.selectBtn { background-color: #1890ff; color: #fff; } -.imgbox { - width: 100%; - height:500px; - overflow: hidden; - canvas{ overflow: hidden; } - .content,.center{ + canvas { + overflow: hidden; + display: block; + } + + .content, + .center { width: 100%; height: 100%; overflow: hidden; } } + +.btnbox { + display: flex; + position: fixed; + left: 1%; + top: 1%; + z-index: 10; + + button { + margin-right: 6px; + display: flex; + } + + .deleteItem { + display: none; + color: red; + cursor: pointer; + margin-left: 5px; + } + + button:hover { + .deleteItem { + display: block; + } + } + + .leftTitle { + line-height: 32px; + margin-right: 10px; + color: #fff; + } + + .rightTitle { + line-height: 32px; + margin-left: 10px; + color: #fff; + } +} + +.imgbox, +.btnbox { + box-sizing: border-box; + padding: 0; +} + +.selectBtn { + background-color: #1890ff; + color: #fff; +} diff --git a/src/app/system-management/image-label/image-label.component.ts b/src/app/system-management/image-label/image-label.component.ts index 43cf808..61ffd3a 100644 --- a/src/app/system-management/image-label/image-label.component.ts +++ b/src/app/system-management/image-label/image-label.component.ts @@ -1,216 +1,762 @@ -import { Component, OnInit } from '@angular/core'; +import { HttpClient, HttpErrorResponse } from '@angular/common/http'; +import { Component, Input, OnInit } from '@angular/core'; +import { NzMessageService } from 'ng-zorro-antd/message'; +import { NzModalService } from 'ng-zorro-antd/modal'; @Component({ selector: 'app-image-label', templateUrl: './image-label.component.html', - styleUrls: ['./image-label.component.scss'] + styleUrls: ['./image-label.component.scss'], }) export class ImageLabelComponent implements OnInit { + constructor( + private http: HttpClient, + private message: NzMessageService, + private modal: NzModalService + ) {} - constructor() { } - - imgItem: any; + @Input() cameraId: any; //传递id + camerasData: any; //摄像头Data + imgItem: any; //图片 URL canvasWidth: number = 0; canvasHeight: number = 0; - copyCanvas: any; - markType: boolean = true; //标注type + copyCanvas: any; //拷贝 canvas底图 + + selectedBtn: string; //按钮选中 + //返回上一步路由 + goback() { + history.go(-1); + } + + ngOnInit(): void {} + + //获取 摄像头图片/标注点位 + getImgMarkData() { + return new Promise((resolve, reject) => { + this.http.get(`/api/Cameras/${this.cameraId}`).subscribe((info: any) => { + info.dimensionedPoints + ? (info.dimensionedPoints = JSON.parse(info.dimensionedPoints)) + : null; + this.camerasData = info; + this.markType = info.type; - ngOnInit(): void { + this.markType === 3 + ? (this.selectedBtn = '收银区') + : (this.selectedBtn = '停车区'); + const httpOptions = { + responseType: 'blob' as 'json', + params: { cameraId: this.cameraId }, + }; + this.http.get(`/api/Cameras/Images`, httpOptions).subscribe({ + next: (data) => { + resolve(data); + }, + error: (err) => { + reject('error'); + }, + }); + }); + }); + } + anewgetImg() { + let params = { + cameraId: this.cameraId, + }; + this.http + .put('/api/Cameras/Commands/CaptureImages', '', { params: params }) + .subscribe({ + next: (value: Object) => { + this.message.create( + 'success', + '向边缘设备发送请求成功,请过一段时间手动刷新页面!' + ); + }, + error: (error: HttpErrorResponse) => {}, + complete: () => {}, + }); } ngAfterContentInit(): void { - this.initBackgroundImg() + this.getImgMarkData() + .then((res: any) => { + this.imgItem = window.URL.createObjectURL(res); + window.setTimeout(() => { + this.initBackgroundImg(); + }, 0); + }) + .catch((err) => { + this.message.create('error', '获取图片失败!'); + }); } //初始化背景图 + + canvas; + ctx; + initBackgroundImg() { - let canvas = document.getElementById('canvas') as any; - canvas.oncontextmenu = () =>{ return false; }; - let that = this - let ctx + this.canvas = document.getElementById('canvas') as any; + //取消鼠标右键事件 + this.canvas.oncontextmenu = () => { + return false; + }; // 检测canvas支持性 - if (canvas.getContext) { - ctx = canvas.getContext('2d'); // 返回一个对象,该对象提供了用在画布上绘图的方法和属性 + if (this.canvas.getContext) { + this.ctx = this.canvas.getContext('2d'); // 返回一个对象,该对象提供了用在画布上绘图的方法和属性 } else { - document.write("你的浏览器不支持canvas,请升级你的浏览器!"); + document.write('你的浏览器不支持canvas,请升级你的浏览器!'); return; } - - // 读取可视区域 宽高 - let center = (document.getElementById('canvasCenter') as any).getBoundingClientRect(); - // 图片加载完后,将其显示在canvas中 var img = new Image(); - img.src = that.imgItem.url? that.imgItem.url : "../../../assets/images/bgImg.png"; + img.src = this.imgItem ? this.imgItem : '../../../assets/images/bgImg.png'; img.onload = () => { - // 等比例缩放图片 - var scale = 1; - if (img.width > center.width || img.height > center.height) { - if (img.width > img.height) { - scale = center.width / img.width; - }else { - scale = center.height / img.height; + this.canvasWidth = img.width; + this.canvasHeight = img.height; + window.setTimeout(() => { + // 加载图片 + this.ctx.drawImage(img, 0, 0, this.canvasWidth, this.canvasHeight); + this.copyCanvas = this.ctx.getImageData( + 0, + 0, + this.canvasWidth, + this.canvasHeight + ); + //初始化标绘图形 + this.initMark(this.canvas, this.ctx); + //监听canvas事件 + this.initCanvasEvent(this.canvas); + }, 0); + }; + } + + //初始化标绘图形 + initMark(canvas, context) { + this.camerasData.dimensionedPointsOfHH = sessionStorage.getItem('xxx'); + + if (!this.camerasData.dimensionedPointsOfHH) { + return; + } else { + this.camerasData.dimensionedPointsOfHH = JSON.parse( + this.camerasData.dimensionedPointsOfHH + ); + } + + console.log('原始标点数据', this.camerasData.dimensionedPointsOfHH); + + return; + //绘制停车区多边形 + this.camerasData.dimensionedPointsOfHH.carStopROI.forEach((element) => { + this.carStopROIDrawPolygon(element.x, element.y, canvas, context); + }); + + //绘制收银区多边形 + this.camerasData.dimensionedPointsOfHH.cashierROI.forEach((element) => { + this.cashierROIDrawPolygon(element.x, element.y, canvas, context); + }); + + //绘制闯入区多边形 + this.camerasData.dimensionedPointsOfHH.intrusionROI.forEach((element) => { + this.intrusionROIDrawPolygon(element.x, element.y, canvas, context); + }); + + //绘制卸油区矩形 + this.unloadingROIDrawOblong( + this.camerasData.dimensionedPointsOfHH.unloadingROI, + context + ); + } + + markType: number = 0; //0=进出口,1=加油区,2=卸油区,3=便利店, + + //记录鼠标点击位置 + downx = 0; + downy = 0; + + //初始化 canvas画布 监听事件 + context; + initCanvasEvent(canvas) { + var context = canvas.getContext('2d'); + this.context = context; + canvas.onmousedown = (e) => { + //鼠标按下事件 + var clickX = e.pageX - canvas.offsetLeft; + var clickY = e.pageY - canvas.offsetTop; + this.downx = clickX; + this.downy = clickY; + + if (this.markType === 0) { + //进出口 + this.carStopROIDrawPolygon(clickX, clickY, canvas, context); //绘制停车区 + } else if (this.markType === 1) { + //加油区(暂不需要标注) + } else if (this.markType === 2) { + //卸油区 + if (this.selectedBtn === '停车区') { + this.carStopROIDrawPolygon(clickX, clickY, canvas, context); //绘制停车区 + } else if (this.selectedBtn === '闯入区') { + this.intrusionROIDrawPolygon(clickX, clickY, canvas, context); //绘制闯入区 + } else if (this.selectedBtn === '卸油区') { + if (this.unloadingROIOblongPoints.length === 1) { + //限制数量 + this.message.create('warning', '卸油区只允许绘制1个!'); + return; + } + + //绘制矩形 + context.beginPath(); + context.moveTo(clickX, clickY); + context.strokeStyle = 'green'; + context.lineWidth = 3; + canvas.onmousemove = (ev) => { + //鼠标移动事件 + var moveX = ev.pageX - canvas.offsetLeft; + var moveY = ev.pageY - canvas.offsetTop; + + this.unloadingROIDrawOblong(this.unloadingROIOblongPoints, context); + context.strokeStyle = 'orange'; + let element = this.getOblongInfo( + this.downx, + this.downy, + moveX, + moveY + ); + context.strokeRect( + element.x, + element.y, + element.width, + element.height + ); + context.font = '22px Arial'; + context.fillText( + '高度:' + element.height, + element.x + 3, + element.y + 22 + ); + }; } + // + } else if (this.markType === 3) { + //便利店 + this.cashierROIDrawPolygon(clickX, clickY, canvas, context); //绘制停车区 } - that.canvasWidth = img.width * scale; - that.canvasHeight = img.height * scale; // 计算等比缩小后图片 - window.setTimeout(()=>{ // 加载图片 - ctx.drawImage(img, 0, 0, that.canvasWidth, that.canvasHeight); - this.copyCanvas = ctx.getImageData(0, 0, that.canvasWidth, that.canvasHeight) - that.initCanvasEvent(canvas) - }, 0) - } - } - - //线段的点的集合 - points = []; - points2 = []; - //可拖动圆圈的点的集合 - circles = []; - circles2 = []; - //整体移动点位 - allpoints = []; - allpoints2 = []; - isDragging = false - //是否在绘制区域内 - isInOut = false - //记录鼠标点击位置 - downx = 0 - downy = 0 + }; + + canvas.onmouseup = (e) => { + //鼠标松开事件 + canvas.onmousemove = (ev) => { + //鼠标移动事件 + return false; + }; + if (this.markType !== 2) { + //因为只有卸油区需要画矩形 + return; + } + if (this.markType === 2 && this.unloadingROIOblongPoints.length === 1) { + return; + } + if (this.markType === 2 && this.selectedBtn === '卸油区') { + var upX = e.pageX - canvas.offsetLeft; + var upY = e.pageY - canvas.offsetTop; + let point = this.getOblongInfo(this.downx, this.downy, upX, upY); + this.unloadingROIOblongPoints.push(point); + this.unloadingROIDrawOblong(this.unloadingROIOblongPoints, context); + } + }; + } + + //卸油区矩形 + unloadingROIOblongPoints = []; //矩形的点的集合 + unloadingROIDrawOblong(oblongList, context) { + context.clearRect(0, 0, this.canvasWidth, this.canvasHeight); + this.copyCanvas ? context.putImageData(this.copyCanvas, 0, 0) : null; + + //重绘停车区 + if (this.carStopROIPoints && this.carStopROIPoints.length != 0) { + this.redrawPolygon( + this.carStopROIPoints, + this.carStopROIAllpoints, + this.carStopROICircles, + context, + 'green' + ); + } + + //重绘闯入区 + if (this.carStopROIPoints && this.carStopROIPoints.length != 0) { + this.redrawPolygon( + this.intrusionROIPoints, + this.intrusionROIAllpoints, + this.intrusionROICircles, + context, + 'red' + ); + } + oblongList.forEach((element) => { + context.strokeStyle = 'orange'; + context.lineWidth = 3; + context.strokeRect(element.x, element.y, element.width, element.height); + context.font = '22px Arial'; + context.fontColor = 'orange'; + context.fillText('高度:' + element.height, element.x + 3, element.y + 22); + }); + } + /** 获取 矩形左上角点位/宽高 */ + getOblongInfo(startX, startY, endX, endY) { + let point = { + x: 0, + y: 0, + width: 0, + height: 0, + }; + if (startX > endX) { + point.x = endX; + point.width = startX - endX; + } else { + point.x = startX; + point.width = endX - startX; + } + if (startY > endY) { + point.y = endY; + point.height = startY - endY; + } else { + point.y = startY; + point.height = endY - startY; + } + return point; + } + + //停车区多边形 + carStopROIPoints = []; //线段的点的集合 + carStopROICircles = []; //可拖动圆圈的点的集合 + carStopROIAllpoints = []; //整体移动点位 + carStopROIIsDragging = false; //是否可拖拽 + carStopROIIsInOut = false; //是否在绘制区域内 + carStopROIDrawPolygon(clickX, clickY, canvas, context) { + if (this.isInt(clickX, clickY, this.carStopROIPoints)) { + this.carStopROIIsInOut = true; + return; + } else { + this.carStopROIIsInOut = false; + } + let index; + //判断当前点击点是否在已经绘制的圆圈上,如果是执行相关操作,并return,不进入画线的代码 + for (var i = 0; i < this.carStopROICircles.length; i++) { + let circle = this.carStopROICircles[i]; + //使用勾股定理计算这个点与圆心之间的距离 + var distanceFromCenter = Math.sqrt( + Math.pow(circle.x - clickX, 2) + Math.pow(circle.y - clickY, 2) + ); + // 如果是其他的点,则设置可以拖动 + if (distanceFromCenter <= circle.radius) { + // 清除之前选择的圆圈 + index = i; + this.carStopROIIsDragging = true; + //停止搜索 + return; + } + } + //如果点击新的位置,则进入下面的代码,绘制点 + context.clearRect(0, 0, canvas.width, canvas.height); + this.copyCanvas ? context.putImageData(this.copyCanvas, 0, 0) : null; + + //重绘闯入区 + if (this.carStopROIPoints && this.carStopROIPoints.length != 0) { + this.redrawPolygon( + this.intrusionROIPoints, + this.intrusionROIAllpoints, + this.intrusionROICircles, + context, + 'red' + ); + } + + //重绘卸油区 + if ( + this.unloadingROIOblongPoints && + this.unloadingROIOblongPoints.length != 0 + ) { + this.redrawRectangle(this.unloadingROIOblongPoints, context); + } + + //遍历数组画圆 + var circle = { + x: clickX, + y: clickY, + radius: 5, + color: 'white', + isSelected: false, //拖拽点的标记 + }; + this.carStopROICircles.push(circle); + this.carStopROIAllpoints = JSON.parse( + JSON.stringify(this.carStopROICircles) + ); + this.carStopROICircles[0].color = 'white'; + for (var i = 0; i < this.carStopROICircles.length; i++) { + let circle = this.carStopROICircles[i]; + // 绘制圆圈 + context.globalAlpha = 0.85; + context.beginPath(); + context.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2); + context.fillStyle = circle.color; + context.strokeStyle = 'red'; + context.fill(); + context.stroke(); + } + // 画线 + var point = { + x: clickX, + y: clickY, + }; + this.carStopROIPoints.push(point); + context.beginPath(); + context.lineWidth = 3; + //从起始点开始绘制 + context.moveTo(this.carStopROIPoints[0].x, this.carStopROIPoints[0].y); + for (var i = 0; i < this.carStopROIPoints.length; i++) { + context.lineTo(this.carStopROIPoints[i].x, this.carStopROIPoints[i].y); + } + context.closePath(); + context.strokeStyle = 'green'; + context.stroke(); + } + + //闯入区多边形 + intrusionROIPoints = []; //线段的点的集合 + intrusionROICircles = []; //可拖动圆圈的点的集合 + intrusionROIAllpoints = []; //整体移动点位 + intrusionROIIsDragging = false; //是否可拖拽 + intrusionROIIsInOut = false; //是否在绘制区域内 + intrusionROIDrawPolygon(clickX, clickY, canvas, context) { + if (this.isInt(clickX, clickY, this.intrusionROIPoints)) { + this.intrusionROIIsInOut = true; + return; + } else { + this.intrusionROIIsInOut = false; + } + let index; + //判断当前点击点是否在已经绘制的圆圈上,如果是执行相关操作,并return,不进入画线的代码 + for (var i = 0; i < this.intrusionROICircles.length; i++) { + let circle = this.intrusionROICircles[i]; + //使用勾股定理计算这个点与圆心之间的距离 + var distanceFromCenter = Math.sqrt( + Math.pow(circle.x - clickX, 2) + Math.pow(circle.y - clickY, 2) + ); + + // 如果是其他的点,则设置可以拖动 + if (distanceFromCenter <= circle.radius) { + // 清除之前选择的圆圈 + index = i; + this.intrusionROIIsDragging = true; + //停止搜索 + return; + } + } + + context.clearRect(0, 0, canvas.width, canvas.height); + this.copyCanvas ? context.putImageData(this.copyCanvas, 0, 0) : null; + + //重绘停车区 + if (this.carStopROIPoints && this.carStopROIPoints.length != 0) { + this.redrawPolygon( + this.carStopROIPoints, + this.carStopROIAllpoints, + this.carStopROICircles, + context, + 'green' + ); + } + + //重绘卸油区 + if ( + this.unloadingROIOblongPoints && + this.unloadingROIOblongPoints.length != 0 + ) { + this.redrawRectangle(this.unloadingROIOblongPoints, context); + } + + //遍历数组画圆 + var circle = { + x: clickX, + y: clickY, + radius: 5, + color: 'white', + isSelected: false, //拖拽点的标记 + }; + this.intrusionROICircles.push(circle); + this.intrusionROIAllpoints = JSON.parse( + JSON.stringify(this.intrusionROICircles) + ); + this.intrusionROICircles[0].color = 'white'; + for (var i = 0; i < this.intrusionROICircles.length; i++) { + let circle = this.intrusionROICircles[i]; + // 绘制圆圈 + context.globalAlpha = 0.85; + context.beginPath(); + context.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2); + context.fillStyle = circle.color; + context.strokeStyle = 'red'; + context.fill(); + context.stroke(); + } + // 画线 + var point = { + x: clickX, + y: clickY, + }; + this.intrusionROIPoints.push(point); + context.beginPath(); + context.lineWidth = 3; + //从起始点开始绘制 + context.moveTo(this.intrusionROIPoints[0].x, this.intrusionROIPoints[0].y); + for (var i = 0; i < this.intrusionROIPoints.length; i++) { + context.lineTo( + this.intrusionROIPoints[i].x, + this.intrusionROIPoints[i].y + ); + } + context.closePath(); + context.strokeStyle = 'red'; + context.stroke(); + } + + //收银区多边形 + cashierROIPoints = []; //线段的点的集合 + cashierROICircles = []; //可拖动圆圈的点的集合 + cashierROIAllpoints = []; //整体移动点位 + cashierROIIsDragging = false; //是否可拖拽 + cashierROIIsInOut = false; //是否在绘制区域内 + cashierROIDrawPolygon(clickX, clickY, canvas, context) { + if (this.isInt(clickX, clickY, this.cashierROIPoints)) { + this.cashierROIIsInOut = true; + return; + } else { + this.cashierROIIsInOut = false; + } + let index; + //判断当前点击点是否在已经绘制的圆圈上,如果是执行相关操作,并return,不进入画线的代码 + for (var i = 0; i < this.cashierROICircles.length; i++) { + let circle = this.cashierROICircles[i]; + //使用勾股定理计算这个点与圆心之间的距离 + var distanceFromCenter = Math.sqrt( + Math.pow(circle.x - clickX, 2) + Math.pow(circle.y - clickY, 2) + ); + + // 如果是其他的点,则设置可以拖动 + if (distanceFromCenter <= circle.radius) { + // 清除之前选择的圆圈 + index = i; + this.cashierROIIsDragging = true; + //停止搜索 + return; + } + } + + context.clearRect(0, 0, canvas.width, canvas.height); + this.copyCanvas ? context.putImageData(this.copyCanvas, 0, 0) : null; + + //遍历数组画圆 + var circle = { + x: clickX, + y: clickY, + radius: 5, + color: 'yellow', + isSelected: false, //拖拽点的标记 + }; + this.cashierROICircles.push(circle); + this.cashierROIAllpoints = JSON.parse( + JSON.stringify(this.cashierROICircles) + ); + this.cashierROICircles[0].color = 'white'; + for (var i = 0; i < this.cashierROICircles.length; i++) { + let circle = this.cashierROICircles[i]; + // 绘制圆圈 + context.globalAlpha = 0.85; + context.beginPath(); + context.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2); + context.fillStyle = circle.color; + context.strokeStyle = 'red'; + context.fill(); + context.stroke(); + } + // 画线 + var point = { + x: clickX, + y: clickY, + }; + this.cashierROIPoints.push(point); + context.beginPath(); + context.lineWidth = 3; + //从起始点开始绘制 + context.moveTo(this.cashierROIPoints[0].x, this.cashierROIPoints[0].y); + for (var i = 0; i < this.cashierROIPoints.length; i++) { + context.lineTo(this.cashierROIPoints[i].x, this.cashierROIPoints[i].y); + } + context.closePath(); + context.strokeStyle = 'blue'; + context.stroke(); + } + //判断点位是否在图形区域内 + isInt(x, y, points) { + if (!points[2]) { + return; + } + var pt = { + x: x, + y: y, + }; + return this.PointInPoly(pt, points); + } + //射线法判断点位 + PointInPoly(pt, poly) { + for (var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i) + ((poly[i].y <= pt.y && pt.y < poly[j].y) || + (poly[j].y <= pt.y && pt.y < poly[i].y)) && + pt.x < + ((poly[j].x - poly[i].x) * (pt.y - poly[i].y)) / + (poly[j].y - poly[i].y) + + poly[i].x && + (c = !c); + return c; + } //清空画布 clearCanvas() { - this.points = []; - this.points2 = []; - this.circles = []; - this.circles2 = []; - this.allpoints = []; - this.allpoints2 = []; let canvas = document.getElementById('canvas') as any; let context = canvas.getContext('2d'); - context.clearRect(0, 0, canvas.width, canvas.height); - this.copyCanvas?context.putImageData(this.copyCanvas, 0, 0) : null; + context.clearRect(0, 0, canvas.width, canvas.height); + this.copyCanvas ? context.putImageData(this.copyCanvas, 0, 0) : null; } - //初始化 canvas画布 点击事件 - initCanvasEvent(canvas) { - let context = canvas.getContext('2d'); - let html = document.documentElement - let boxDiv = document.getElementsByClassName("canvasDialog")[0] - canvas.onmousedown = (e)=>{ - var clickX = e.pageX - canvas.offsetLeft - ((html.clientWidth - boxDiv.clientWidth) / 2); - var clickY = e.pageY - canvas.offsetTop - ((html.clientHeight - boxDiv.clientHeight) / 2); - this.downx = clickX - this.downy = clickY - if (this.isInt(clickX, clickY)) { - this.isInOut = true - return - } else { - this.isInOut = false - } + //清除某个标绘 + clearCanvasItem(e, type) { + e.stopPropagation(); + this.modal.confirm({ + nzTitle: '确认要清除此标绘吗?', + nzOkText: '确定', + nzOkType: 'primary', + nzOkDanger: true, + nzOnOk: () => { + // if (type == 'isAllMonitoring') { + // //全局的多边形 + // this.pointsOfmonitor = []; + // this.circlesOfmonitor = []; + // this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight); + // this.copyCanvas + // ? this.context.putImageData(this.copyCanvas, 0, 0) + // : null; + // } + // this.initMark2(this.canvas, this.ctx); //初始化标绘图形 + }, + nzCancelText: '取消', + }); + } - let index - let beforeCircles = this.markType? this.circles: this.circles2 - //判断当前点击点是否在已经绘制的圆圈上,如果是执行相关操作,并return,不进入画线的代码 - for (var i = 0; i < beforeCircles.length; i++) { - let circle = beforeCircles[i]; - //使用勾股定理计算这个点与圆心之间的距离 - var distanceFromCenter = Math.sqrt(Math.pow(circle.x - clickX, 2) + Math.pow(circle.y - clickY, 2)); - - // 如果是其他的点,则设置可以拖动 - if (distanceFromCenter <= circle.radius) { - // 清除之前选择的圆圈 - index = i; - this.isDragging = true; - //停止搜索 - return; - } - } - //如果点击新的位置,则进入下面的代码,绘制点 - //context.clearRect(0, 0, canvas.width, canvas.height); + //根据已有数据重绘多边形 + redrawPolygon(data, points, circles, context, color) { + data.forEach((element) => { //遍历数组画圆 - var circle = { - x: clickX, - y: clickY, - radius: 10, - color: "blue", - isSelected: false, //拖拽点的标记 - }; - if (this.markType) { - this.circles.push(circle); - this.allpoints = JSON.parse(JSON.stringify(this.circles)) - this.circles[0].color = "green"; - } else { - this.circles2.push(circle); - this.allpoints2 = JSON.parse(JSON.stringify(this.circles2)) - this.circles2[0].color = "red"; - } - for (var i = 0; i < beforeCircles.length; i++) { - let circle = beforeCircles[i]; + points = JSON.parse(JSON.stringify(circles)); + circles[0].color = 'white'; + for (var i = 0; i < circles.length; i++) { + let circle = circles[i]; // 绘制圆圈 context.globalAlpha = 0.85; context.beginPath(); context.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2); context.fillStyle = circle.color; - context.strokeStyle = "black"; + context.strokeStyle = 'red'; context.fill(); context.stroke(); } // 画线 - var point = { - x: clickX, - y: clickY, - }; - this.markType? this.points.push(point) : this.points2.push(point) context.beginPath(); context.lineWidth = 3; //从起始点开始绘制 - let beforePoint = this.markType? this.points: this.points2 - context.moveTo(beforePoint[0].x, beforePoint[0].y); - for (var i = 0; i < beforePoint.length; i++) { - context.lineTo(beforePoint[i].x, beforePoint[i].y); + context.moveTo(data[0].x, data[0].y); + for (var i = 0; i < data.length; i++) { + context.lineTo(data[i].x, data[i].y); } - context.closePath() - context.fillStyle = "rgb(2,100,30)"; - context.fill(); - context.strokeStyle = "#9d4dca"; + context.closePath(); + context.strokeStyle = color; context.stroke(); - } + }); } - //判断点位是否在图形区域内 - isInt(x, y) { - if (this.markType && !this.points[2]) { - return - } - if (!this.markType && !this.points2[2]) { - return + //根据已有数据重绘矩形 + redrawRectangle(oblongList, context) { + oblongList.forEach((element) => { + context.strokeStyle = 'orange'; + context.lineWidth = 3; + context.strokeRect(element.x, element.y, element.width, element.height); + context.font = '22px Arial'; + context.fontColor = 'orange'; + context.fillText('高度:' + element.height, element.x + 3, element.y + 22); + }); + } + + //保存 + save() { + console.log(this.camerasData.dimensionedPointsOfHH); + if (!this.camerasData.dimensionedPointsOfHH) { + this.camerasData.dimensionedPointsOfHH = { + carStopROI: [], + intrusionROI: [], + cashierROI: [], + unloadingROI: [], + }; } - var pt = { - x: x, - y: y + //进出口 + if (this.markType === 0) { + if (this.carStopROIPoints.length === 0) { + this.message.create('warning', '绘制完整后可保存!'); + return; + } + this.camerasData.dimensionedPointsOfHH.carStopROI = this.carStopROIPoints; } - var poly = this.markType? this.points : this.points2; - return this.PointInPoly(pt, poly) - } + //卸油区 + if (this.markType === 2) { + if ( + this.carStopROIPoints.length === 0 || + this.intrusionROIPoints.length === 0 || + this.unloadingROIOblongPoints.length === 0 + ) { + this.message.create('warning', '绘制完整后可保存!'); + return; + } - //射线法判断点位 - PointInPoly(pt, poly) { - for (var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i) - ((poly[i].y <= pt.y && pt.y < poly[j].y) || (poly[j].y <= pt.y && pt.y < poly[i].y)) - && (pt.x < (poly[j].x - poly[i].x) * (pt.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x) - && (c = !c); - return c; - } + this.camerasData.dimensionedPointsOfHH.carStopROI = this.carStopROIPoints; + this.camerasData.dimensionedPointsOfHH.intrusionROI = + this.intrusionROIPoints; + this.camerasData.dimensionedPointsOfHH.unloadingROI = + this.unloadingROIOblongPoints; + } + //便利店 + if (this.markType === 3) { + if (this.cashierROIPoints.length === 0) { + this.message.create('warning', '绘制完整后可保存!'); + return; + } + this.camerasData.dimensionedPointsOfHH.cashierROI = this.cashierROIPoints; + } - //cneter height - heightCount() { - let style: any = {} - let height = document.documentElement.clientHeight - style.height = (height - 180) + 'px'; - return style + // let paramsData = JSON.parse(JSON.stringify(this.camerasData)); + // paramsData.dimensionedPointsHH = JSON.stringify( + // paramsData.dimensionedPointsHH + // ); + console.log('标点结果', this.camerasData.dimensionedPointsOfHH); + // this.http + // .put(`/api/Cameras/${this.camerasData.id}/DimensionedPoints`, paramsData) + // .subscribe((data) => { + // this.message.create('success', '保存成功!'); + // const isFullScreen = document.fullscreenElement; + // if (document.exitFullscreen && isFullScreen) { + // //关闭全屏 + // document.exitFullscreen(); + // } + // this.modal.closeAll(); + // }); } - } diff --git a/src/app/system-management/system-management.module.ts b/src/app/system-management/system-management.module.ts index 4bd5bf6..05e7342 100644 --- a/src/app/system-management/system-management.module.ts +++ b/src/app/system-management/system-management.module.ts @@ -45,8 +45,35 @@ import { FileComponent } from './condition-monitoring/file/file.component'; import { ScriptComponent } from './status-monitoring/script/script.component'; import { VideoStreamingComponent } from './video-streaming/video-streaming.component'; import { DetailsComponent } from './video-streaming/details/details.component'; +import { NzRadioModule } from 'ng-zorro-antd/radio'; @NgModule({ - declarations: [OrganizationComponent, NavigationComponent, AddorComponent, EditorComponent, AnalysisOfTheHostComponent, AddhostComponent, EdithostComponent, AddcameraComponent, EditcameraComponent, HostConfigComponent, ImageListComponent, ImageLabelComponent, PlottingImageComponent, cameraType, ImageLabel2Component, ConfigFormComponent, ConditionMonitoringComponent, SendFileComponent, ModelComponent, KafkaComponent, StatusMonitoringComponent, FileComponent, ScriptComponent, VideoStreamingComponent, DetailsComponent], + declarations: [ + OrganizationComponent, + NavigationComponent, + AddorComponent, + EditorComponent, + AnalysisOfTheHostComponent, + AddhostComponent, + EdithostComponent, + AddcameraComponent, + EditcameraComponent, + HostConfigComponent, + ImageListComponent, + ImageLabelComponent, + PlottingImageComponent, + cameraType, + ImageLabel2Component, + ConfigFormComponent, + ConditionMonitoringComponent, + SendFileComponent, + ModelComponent, + KafkaComponent, + StatusMonitoringComponent, + FileComponent, + ScriptComponent, + VideoStreamingComponent, + DetailsComponent, + ], imports: [ CommonModule, SystemRoutingModule, @@ -69,9 +96,21 @@ import { DetailsComponent } from './video-streaming/details/details.component'; NzCheckboxModule, NzPageHeaderModule, NzTabsModule, - NzPopconfirmModule + NzPopconfirmModule, + NzRadioModule, + ], + entryComponents: [ + AddorComponent, + EditorComponent, + AddhostComponent, + EdithostComponent, + AddcameraComponent, + EditcameraComponent, + SendFileComponent, + ModelComponent, + FileComponent, + ScriptComponent, + DetailsComponent, ], - entryComponents: [AddorComponent, EditorComponent, AddhostComponent, EdithostComponent, AddcameraComponent, EditcameraComponent, SendFileComponent, ModelComponent, FileComponent, ScriptComponent, DetailsComponent] - }) -export class SystemManagementModule { } +export class SystemManagementModule {}