Browse Source

[新增]安信盒子标绘

非煤矿业企业安全风险监测预警系统
邵佳豪 2 years ago
parent
commit
1316265917
  1. 3
      src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.html
  2. 9
      src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.ts
  3. 3
      src/app/system-management/host-config/host-config.component.html
  4. 48
      src/app/system-management/host-config/host-config.component.ts
  5. 50
      src/app/system-management/image-label-anxin/image-label-anxin.component.html
  6. 86
      src/app/system-management/image-label-anxin/image-label-anxin.component.scss
  7. 25
      src/app/system-management/image-label-anxin/image-label-anxin.component.spec.ts
  8. 487
      src/app/system-management/image-label-anxin/image-label-anxin.component.ts
  9. 2
      src/app/system-management/system-management.module.ts

3
src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.html

@ -50,12 +50,13 @@
<td class="operation">
<!-- <a (click)="edit(data)" style="margin-right: 12px;">编辑</a> -->
<a (click)="config(data)" style="margin-right: 12px;">配置</a>
<nz-modal [(nzVisible)]="isVisible" [nzWidth]="300" nzTitle="请选择要配置的边缘主机" (nzOnCancel)="handleCancel()"
<nz-modal [(nzVisible)]="isVisible" [nzWidth]="350" nzTitle="请选择要配置的边缘主机" (nzOnCancel)="handleCancel()"
(nzOnOk)="handleOk()">
<ng-container *nzModalContent>
<nz-radio-group [(ngModel)]="radioValue">
<label nz-radio nzValue="交大">交大盒子</label>
<label nz-radio nzValue="黄海">黄海盒子</label>
<label nz-radio nzValue="安信">安信盒子</label>
</nz-radio-group>
</ng-container>
</nz-modal>

9
src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.ts

@ -233,9 +233,8 @@ export class AnalysisOfTheHostComponent implements OnInit {
}
handleOk(): void {
let deviceProvider = this.radioValue === '交大' ? 0 : 1;
let body = {
deviceProvider: deviceProvider,
deviceProvider: DeviceProvider[this.radioValue],
};
this.http.put(`/api/EdgeDevices/${this.configdata.id}`, body).subscribe({
next: (data) => {
@ -289,3 +288,9 @@ export class AnalysisOfTheHostComponent implements OnInit {
});
}
}
enum DeviceProvider {
'交大' = 0,
'黄海' = 1,
'安信' = 2,
}

3
src/app/system-management/host-config/host-config.component.html

@ -62,6 +62,9 @@
<div class="footer" *ngIf="hostType === '黄海'">
<button nz-button nzType="primary" (click)="config()">下发黄海config.json配置</button>
</div>
<div class="footer" *ngIf="hostType === '安信'">
<button nz-button nzType="primary" (click)="configToAx()">下发安信config.json配置</button>
</div>
</div>
</div>
<div class="rightbox">

48
src/app/system-management/host-config/host-config.component.ts

@ -37,6 +37,7 @@ interface Camera {
import yaml from 'js-yaml';
import * as YAML from 'yaml';
import { ImageLabelAnxinComponent } from '../image-label-anxin/image-label-anxin.component';
@Component({
selector: 'app-host-config',
@ -106,15 +107,19 @@ export class HostConfigComponent implements OnInit {
console.log('摄像头列表', data.items);
data.items.forEach((element) => {
element.dimensionedPointsObj = JSON.parse(element.dimensionedPoints);
if(element.dimensionedPointsHuanghai){
if (element.dimensionedPointsHuanghai) {
element.dimensionedPointsHuanghaiObj = JSON.parse(
element.dimensionedPointsHuanghai
);
}
if (element.dimensionedPointsAnxin) {
element.dimensionedPointsAnxinObj = JSON.parse(
element.dimensionedPointsAnxin
);
}
});
this.listOfData = data.items;
this.isLoading = false;
});
}
addCamera() {
@ -141,9 +146,7 @@ export class HostConfigComponent implements OnInit {
this.http.post('/api/Cameras', body).subscribe({
next: (data: any) => {
resolve(data);
if (this.hostType === '黄海') {
this.anewgetImg(data.id);
}
this.anewgetImg(data.id);
this.message.create('success', '创建成功!');
this.getCamera();
this.isSourceYaml = false;
@ -188,9 +191,7 @@ export class HostConfigComponent implements OnInit {
order: instance.validateForm.value.order,
};
this.http.put(`/api/Cameras/${data.id}`, body).subscribe((mes) => {
if (this.hostType === '黄海') {
this.anewgetImg(data.id);
}
this.anewgetImg(data.id);
resolve(mes);
this.message.create('success', '编辑成功!');
this.getCamera();
@ -210,7 +211,7 @@ export class HostConfigComponent implements OnInit {
anewgetImg(id) {
let params = {
cameraId: id,
provider: 1,
// provider: type,
};
this.http
.put('/api/Cameras/Commands/CaptureImages', '', { params: params })
@ -307,6 +308,32 @@ export class HostConfigComponent implements OnInit {
modal.afterClose.subscribe((result) => {
this.ngOnInit();
});
} else if (this.hostType == '安信') {
const element = document.documentElement;
if (element.requestFullscreen) {
//进入全屏
element.requestFullscreen();
}
const modal = this.modal.create({
nzContent: ImageLabelAnxinComponent,
nzViewContainerRef: this.viewContainerRef,
nzWidth: 1920,
nzClosable: false,
nzFooter: null,
nzWrapClassName: 'canvasContentBox',
nzMaskClosable: false,
nzBodyStyle: {
'border-radius': '0px',
padding: '0px',
margin: '0px',
},
nzComponentParams: {
cameraId: item.id,
},
});
modal.afterClose.subscribe((result) => {
this.ngOnInit();
});
}
},
error: (err) => {},
@ -1473,4 +1500,7 @@ ${newstr}class-id=0
);
}
}
//安信配置文件
configToAx() {}
}

50
src/app/system-management/image-label-anxin/image-label-anxin.component.html

@ -0,0 +1,50 @@
<div class="canvasBox">
<div class="btnbox">
<label class="leftTitle" style="color: red;">安信盒子标记</label>
<label class="leftTitle" *ngIf="markType === 0">进出口</label>
<label class="leftTitle" *ngIf="markType === 1">加油区</label>
<label class="leftTitle" *ngIf="markType === 2">卸油区</label>
<label class="leftTitle" *ngIf="markType === 3">便利店</label>
<button nz-button [ngClass]="{selectBtn: selectedBtn === '进出口'}" (click)="selectedBtn = '进出口'">进出口
<span class="colorBlock" style="background-color: red;"></span>
<span class="deleteItem" (click)="clearCanvasItem($event,'进出口')">删除</span>
</button>
<button nz-button [ngClass]="{selectBtn: selectedBtn === '收银区'}" (click)="selectedBtn = '收银区'">收银区
<span class="colorBlock" style="background-color: yellow;"></span>
<span class="deleteItem" (click)="clearCanvasItem($event,'收银区')">删除</span>
</button>
<button nz-button [ngClass]="{selectBtn: selectedBtn === '加油区'}" (click)="selectedBtn = '加油区'">加油区
<span class="colorBlock" style="background-color: green;"></span>
<span class="deleteItem" (click)="clearCanvasItem($event,'加油区')">删除</span>
</button>
<button nz-button [ngClass]="{selectBtn: selectedBtn === '卸油区'}" (click)="selectedBtn = '卸油区'">卸油区
<span class="colorBlock" style="background-color: black;"></span>
<span class="deleteItem" (click)="clearCanvasItem($event,'卸油区')">删除</span>
</button>
<button nz-button nzType="primary" (click)="anewgetImg()">重新捕获摄像头图片</button>
<button nz-button nzType="primary" (click)="save()">保存</button>
<button nz-button nzType="primary" nzDanger nz-popconfirm nzPopconfirmTitle="您确定要清空吗?"
(nzOnConfirm)="clearCanvas()">清空</button>
<label *ngIf="camerasData" class="rightTitle">原始分辨率: {{camerasData.originalWeight}} ×
{{camerasData.originalHeight}}
</label>
</div>
<div class="imgbox">
<div class="content">
<div class="center" id="canvasCenter"><canvas id="canvas" [width]="canvasWidth"
[height]="canvasHeight"></canvas>
</div>
</div>
</div>
</div>

86
src/app/system-management/image-label-anxin/image-label-anxin.component.scss

@ -0,0 +1,86 @@
.canvasBox {
width: 100%;
height: 100%;
background: #fff;
font-size: 15px;
color: black;
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow: hidden;
.imgbox {
flex: 1;
overflow: hidden;
}
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;
align-items: center;
}
.colorBlock{
display: inline-block;
width: 12px;
height: 12px;
margin-left: 3px;
}
.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;
}

25
src/app/system-management/image-label-anxin/image-label-anxin.component.spec.ts

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ImageLabelAnxinComponent } from './image-label-anxin.component';
describe('ImageLabelAnxinComponent', () => {
let component: ImageLabelAnxinComponent;
let fixture: ComponentFixture<ImageLabelAnxinComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ImageLabelAnxinComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ImageLabelAnxinComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

487
src/app/system-management/image-label-anxin/image-label-anxin.component.ts

@ -0,0 +1,487 @@
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-anxin',
templateUrl: './image-label-anxin.component.html',
styleUrls: ['./image-label-anxin.component.scss'],
})
export class ImageLabelAnxinComponent implements OnInit {
constructor(
private http: HttpClient,
private message: NzMessageService,
private modal: NzModalService
) {}
@Input() cameraId: any; //传递id
camerasData: any; //摄像头Data
imgItem: any; //图片 URL
canvasWidth: number = 0;
canvasHeight: number = 0;
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((data: any) => {
this.camerasData = data;
this.markType = data.type;
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,
provider: 1,
};
this.http
.put('/api/Cameras/Commands/CaptureImages', '', { params: params })
.subscribe({
next: (value: Object) => {
this.message.create(
'success',
'向边缘设备发送请求成功,请过一段时间手动刷新页面!'
);
},
error: (error: HttpErrorResponse) => {},
complete: () => {},
});
}
ngAfterContentInit(): void {
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() {
this.canvas = document.getElementById('canvas') as any;
//取消鼠标右键事件
this.canvas.oncontextmenu = () => {
return false;
};
// 检测canvas支持性
if (this.canvas.getContext) {
this.ctx = this.canvas.getContext('2d'); // 返回一个对象,该对象提供了用在画布上绘图的方法和属性
} else {
document.write('你的浏览器不支持canvas,请升级你的浏览器!');
return;
}
// 图片加载完后,将其显示在canvas中
var img = new Image();
img.src = this.imgItem ? this.imgItem : '../../../assets/images/bgImg.png';
img.onload = () => {
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);
};
}
//初始化标绘图形
DrawPolygoning = '';
initMark(canvas, context) {
if (!this.camerasData.dimensionedPointsAnxin) {
return;
} else {
this.camerasData.dimensionedPointsAnxin = JSON.parse(
this.camerasData.dimensionedPointsAnxin
);
}
console.log('原始标点数据', this.camerasData.dimensionedPointsAnxin);
for (const key in this.camerasData.dimensionedPointsAnxin) {
const element = this.camerasData.dimensionedPointsAnxin[key];
console.log(key, element);
if (element.length !== 0) {
for (let index = 0; index < element.length; index++) {
const item = element[index];
let obj = this.PolygonData[key];
this.DrawPolygoning = key;
this.DrawPolygon(
item.x,
item.y,
canvas,
context,
obj.Points,
obj.Circles,
obj.Allpoints,
obj.IsDragging,
obj.IsInOut,
obj.Color
);
}
}
this.DrawPolygoning = '';
}
}
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) => {
if (!this.selectedBtn) {
this.message.create('warning', '请先选择要绘制的区域!');
return;
}
//鼠标按下事件
var clickX = e.pageX - canvas.offsetLeft;
var clickY = e.pageY - canvas.offsetTop;
this.downx = clickX;
this.downy = clickY;
let obj;
obj = this.PolygonData[this.selectedBtn];
this.DrawPolygon(
clickX,
clickY,
canvas,
context,
obj.Points,
obj.Circles,
obj.Allpoints,
obj.IsDragging,
obj.IsInOut,
obj.Color
);
};
canvas.onmouseup = (e) => {
//鼠标松开事件
canvas.onmousemove = (ev) => {
//鼠标移动事件
return false;
};
};
}
PolygonData = {
: {
//进出口多边形
Points: [], //线段的点的集合
Circles: [], //可拖动圆圈的点的集合
Allpoints: [], //整体移动点位
IsDragging: false, //是否可拖拽
IsInOut: false, //是否在绘制区域内
Color: 'red',
},
: {
//收银区多边形
Points: [], //线段的点的集合
Circles: [], //可拖动圆圈的点的集合
Allpoints: [], //整体移动点位
IsDragging: false, //是否可拖拽
IsInOut: false, //是否在绘制区域内
Color: 'yellow',
},
: {
//加油区多边形
Points: [], //线段的点的集合
Circles: [], //可拖动圆圈的点的集合
Allpoints: [], //整体移动点位
IsDragging: false, //是否可拖拽
IsInOut: false, //是否在绘制区域内
Color: 'green',
},
: {
Points: [], //线段的点的集合
Circles: [], //可拖动圆圈的点的集合
Allpoints: [], //整体移动点位
IsDragging: false, //是否可拖拽
IsInOut: false, //是否在绘制区域内
Color: 'black',
},
};
//绘制多边形的方法
DrawPolygon(
clickX,
clickY,
canvas,
context,
Points,
Circles,
Allpoints,
IsDragging,
IsInOut,
Color
) {
if (this.isInt(clickX, clickY, Points)) {
IsInOut = true;
return;
} else {
IsInOut = false;
}
let index;
//判断当前点击点是否在已经绘制的圆圈上,如果是执行相关操作,并return,不进入画线的代码
for (var i = 0; i < Circles.length; i++) {
let circle = Circles[i];
//使用勾股定理计算这个点与圆心之间的距离
var distanceFromCenter = Math.sqrt(
Math.pow(circle.x - clickX, 2) + Math.pow(circle.y - clickY, 2)
);
// 如果是其他的点,则设置可以拖动
if (distanceFromCenter <= circle.radius) {
// 清除之前选择的圆圈
index = i;
IsDragging = true;
//停止搜索
return;
}
}
//如果点击新的位置,则进入下面的代码,绘制点
context.clearRect(0, 0, canvas.width, canvas.height);
this.copyCanvas ? context.putImageData(this.copyCanvas, 0, 0) : null;
//重绘除了自己的其他区域
for (const key in this.PolygonData) {
const item = this.PolygonData[key];
if (key !== this.selectedBtn && key !== this.DrawPolygoning) {
this.redrawPolygon(
item.Points,
item.Allpoints,
item.Circles,
context,
item.Color
);
}
}
//遍历数组画圆
var circle = {
x: clickX,
y: clickY,
radius: 5,
color: Color,
isSelected: false, //拖拽点的标记
};
Circles.push(circle);
Allpoints = JSON.parse(JSON.stringify(Circles));
Circles[0].color = Color;
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 = Color;
context.fill();
context.stroke();
}
// 画线
var point = {
x: clickX,
y: clickY,
};
Points.push(point);
context.beginPath();
context.lineWidth = 3;
//从起始点开始绘制
context.moveTo(Points[0].x, Points[0].y);
for (var i = 0; i < Points.length; i++) {
context.lineTo(Points[i].x, Points[i].y);
}
context.closePath();
context.strokeStyle = Color;
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;
}
//根据已有数据重绘多边形
redrawPolygon(data, points, circles, context, color) {
data.forEach((element) => {
//遍历数组画圆
points = JSON.parse(JSON.stringify(circles));
circles[0].color = color;
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 = color;
context.fill();
context.stroke();
}
// 画线
context.beginPath();
context.lineWidth = 3;
//从起始点开始绘制
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.strokeStyle = color;
context.stroke();
});
}
//清空画布
clearCanvas() {
let canvas = document.getElementById('canvas') as any;
let context = canvas.getContext('2d');
for (const key in this.PolygonData) {
const element = this.PolygonData[key];
element.Points = [];
element.Circles = [];
element.Allpoints = [];
element.IsDragging = false;
element.IsInOut = false;
}
context.clearRect(0, 0, canvas.width, canvas.height);
this.copyCanvas ? context.putImageData(this.copyCanvas, 0, 0) : null;
// console.log(this.PolygonData)
}
//清除某个标绘
clearCanvasItem(e, type) {
e.stopPropagation();
this.modal.confirm({
nzTitle: '确认要清除此标绘吗?',
nzOkText: '确定',
nzOkType: 'primary',
nzOkDanger: true,
nzOnOk: () => {
this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
this.copyCanvas
? this.context.putImageData(this.copyCanvas, 0, 0)
: null;
this.PolygonData[type].Points = [];
this.PolygonData[type].Circles = [];
this.PolygonData[type].Allpoints = [];
this.redrawAll();
},
nzCancelText: '取消',
});
}
redrawAll() {
//重绘除了自己的其他区域
for (const key in this.PolygonData) {
const item = this.PolygonData[key];
this.redrawPolygon(
item.Points,
item.Allpoints,
item.Circles,
this.context,
item.Color
);
}
}
//保存
save() {
console.log(this.camerasData.dimensionedPointsAnxin);
if (!this.camerasData.dimensionedPointsAnxin) {
this.camerasData.dimensionedPointsAnxin = {
: [],
: [],
: [],
: [],
};
}
console.log('标点数据', this.PolygonData);
for (const key in this.PolygonData) {
const item = this.PolygonData[key];
this.camerasData.dimensionedPointsAnxin[key] = item.Points;
}
let body = {
dimensionedPointsAnxin: JSON.stringify(
this.camerasData.dimensionedPointsAnxin
),
};
console.log('标点结果', this.camerasData.dimensionedPointsAnxin);
this.http
.put(`/api/Cameras/${this.camerasData.id}/DimensionedPoints`, body)
.subscribe((data) => {
this.message.create('success', '保存成功!');
const isFullScreen = document.fullscreenElement;
if (document.exitFullscreen && isFullScreen) {
//关闭全屏
document.exitFullscreen();
}
this.modal.closeAll();
});
}
}

2
src/app/system-management/system-management.module.ts

@ -47,6 +47,7 @@ import { VideoStreamingComponent } from './video-streaming/video-streaming.compo
import { DetailsComponent } from './video-streaming/details/details.component';
import { NzRadioModule } from 'ng-zorro-antd/radio';
import { HuangHaiConfigComponent } from './host-config/huang-hai-config/huang-hai-config.component';
import { ImageLabelAnxinComponent } from './image-label-anxin/image-label-anxin.component';
@NgModule({
declarations: [
OrganizationComponent,
@ -75,6 +76,7 @@ import { HuangHaiConfigComponent } from './host-config/huang-hai-config/huang-ha
VideoStreamingComponent,
DetailsComponent,
HuangHaiConfigComponent,
ImageLabelAnxinComponent,
],
imports: [
CommonModule,

Loading…
Cancel
Save