blastDelta.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. <template>
  2. <div class="blastDelta">
  3. <div ref="coord" class="coords">
  4. <div class="coord-lineY">
  5. <div :style="{ width: '5px', height: `${lengY}px`, 'border-top': '1px solid #0079ff' }" v-for="item in 10" :key="item"></div>
  6. </div>
  7. <div class="coord-labelY">
  8. <div :style="{ width: '20px', height: `${lengY}px`, color: '#fff' }" v-for="(ite, ind) in 10" :key="ind">{{ ind == 0 ? maxY : '' }}</div>
  9. </div>
  10. <div class="coord-lineX">
  11. <div :style="{ height: '5px', width: `${lengY}px`, 'border-right': '1px solid #0079ff' }" v-for="item in 15" :key="item"></div>
  12. </div>
  13. <div class="coord-labelX">
  14. <div :style="{ height: '20px', width: `${lengY}px`, color: '#fff' }" v-for="(ite, ind) in 15" :key="ind">{{ ind == 14 ? maxX : '' }}</div>
  15. </div>
  16. <div class="line-AB" :style="{ width: 'calc(100% - 10px)', height: 'calc(100% - 10px)' }">
  17. <canvas id="myCanvas" :width="canvasSize.width" :height="canvasSize.height"></canvas>
  18. </div>
  19. <!-- <div class="line-legend">
  20. <div class="legend-ite" v-for="ite in 4" :key="ite"></div>
  21. </div>
  22. <div class="legend-name">
  23. <div class="item-name" v-for="item in legendList" :key="item">{{ item.name }}</div>
  24. </div> -->
  25. </div>
  26. <div class="line-legend">
  27. <div class="legend-box" v-for="(item, index) in legendList" :key="index">
  28. <span class="legend-icon"></span>
  29. <span class="legend-label">{{ item.name }}</span>
  30. </div>
  31. </div>
  32. </div>
  33. </template>
  34. <script lang="ts" setup>
  35. import { ref, reactive, onMounted, watch, nextTick } from 'vue';
  36. let props = defineProps({
  37. posMonitor: {
  38. type: Object,
  39. default: () => {
  40. return {};
  41. },
  42. },
  43. canvasSize: {
  44. type: Object,
  45. default: () => {
  46. return { width: 348, height: 245 };
  47. },
  48. },
  49. });
  50. let coord = ref(null);
  51. let lengY = ref(0);
  52. //与x,y轴相交最大值坐标
  53. let maxY = ref(0);
  54. let maxX = ref(0);
  55. let maxY1 = ref(0);
  56. let maxX1 = ref(0);
  57. //A点坐标
  58. let coordinateA = reactive({
  59. x: 0,
  60. y: 0,
  61. });
  62. //B点坐标
  63. let coordinateB = reactive({
  64. x: 0,
  65. y: 0,
  66. });
  67. //E点坐标
  68. let coordinateE = reactive({
  69. x: 0,
  70. y: 0,
  71. });
  72. //F点坐标
  73. let coordinateF = reactive({
  74. x: 0,
  75. y: 0,
  76. });
  77. //G点坐标
  78. let coordinateG = reactive({
  79. x: 0,
  80. y: 0,
  81. });
  82. let legendList = ref<any[]>([{ name: '不爆炸' }, { name: '可燃气体不足' }, { name: '可爆炸' }, { name: '氧气不足' }]);
  83. function getAreas() {
  84. if (coord.value) {
  85. let width = coord.value.offsetWidth;
  86. let height = coord.value.offsetHeight;
  87. lengY.value = Math.ceil((height - 10) / 10);
  88. }
  89. }
  90. //根据A,B,E,G等点坐标绘制爆炸三角形
  91. function getBlast() {
  92. maxY.value = getCoordABY(0);
  93. // 获取canvas元素
  94. let canvas = document.getElementById('myCanvas');
  95. let ctx = canvas.getContext('2d');
  96. let scalcY, scalcX;
  97. if (coordinateB.x < 50) {
  98. maxX.value = 50;
  99. scalcY = canvas.height / maxY.value;
  100. scalcX = canvas.width / maxX.value;
  101. } else {
  102. maxX.value = parseInt(coordinateB.x + 10);
  103. scalcY = canvas.height / maxY.value;
  104. scalcX = canvas.width / maxX.value;
  105. }
  106. //绘制AB点线条
  107. ctx.beginPath();
  108. ctx.moveTo(coordinateA.x * scalcX, canvas.height - coordinateA.y * scalcY); // 开始绘制的点
  109. ctx.lineTo(coordinateB.x * scalcX, canvas.height - coordinateB.y * scalcY); // 结束绘制的点
  110. ctx.strokeStyle = '#000';
  111. ctx.stroke(); // 进行绘制
  112. //绘制AE线条
  113. ctx.beginPath();
  114. ctx.moveTo(coordinateA.x * scalcX, canvas.height - coordinateA.y * scalcY); // 开始绘制的点
  115. ctx.lineTo(coordinateE.x * scalcX, canvas.height - coordinateE.y * scalcY); // 结束绘制的点
  116. ctx.strokeStyle = '#000';
  117. ctx.stroke(); // 进行绘制
  118. //绘制BE线条
  119. ctx.beginPath();
  120. ctx.moveTo(coordinateB.x * scalcX, canvas.height - coordinateB.y * scalcY); // 开始绘制的点
  121. ctx.lineTo(coordinateE.x * scalcX, canvas.height - coordinateE.y * scalcY); // 结束绘制的点
  122. ctx.strokeStyle = '#000';
  123. ctx.stroke(); // 进行绘制
  124. //绘制A点与坐标轴连线
  125. ctx.beginPath();
  126. ctx.moveTo(0, canvas.height - maxY.value * scalcY); // 开始绘制的点
  127. ctx.lineTo(coordinateA.x * scalcX, canvas.height - coordinateA.y * scalcY); // 结束绘制的点
  128. ctx.strokeStyle = '#000';
  129. ctx.stroke(); // 进行绘制
  130. //绘制B点c连线
  131. ctx.beginPath();
  132. ctx.moveTo(coordinateB.x * scalcX, canvas.height - coordinateB.y * scalcY); // 开始绘制的点
  133. ctx.lineTo(maxX.value * scalcX, canvas.height - getCoordABY(maxX.value) * scalcY); // 结束绘制的点
  134. ctx.strokeStyle = '#000';
  135. ctx.stroke(); // 进行绘制
  136. //绘制c点与坐标轴连线
  137. ctx.beginPath();
  138. ctx.moveTo(maxX.value * scalcX, canvas.height - getCoordABY(maxX.value) * scalcY); // 开始绘制的点
  139. ctx.lineTo(maxX.value * scalcX, canvas.height); // 结束绘制的点
  140. ctx.strokeStyle = '#000';
  141. ctx.stroke(); // 进行绘制
  142. //绘制E,F线条
  143. ctx.beginPath();
  144. ctx.moveTo(coordinateE.x * scalcX, canvas.height - coordinateE.y * scalcY); // 开始绘制的点
  145. ctx.lineTo(coordinateF.x * scalcX, canvas.height - coordinateF.y * scalcY); // 结束绘制的点
  146. ctx.strokeStyle = '#000';
  147. ctx.stroke(); // 进行绘制
  148. //绘制GE线条
  149. ctx.beginPath();
  150. ctx.moveTo(coordinateG.x * scalcX, canvas.height - coordinateG.y * scalcY); // 开始绘制的点
  151. ctx.lineTo(coordinateE.x * scalcX, canvas.height - coordinateE.y * scalcY); // 结束绘制的点
  152. ctx.strokeStyle = '#000';
  153. ctx.stroke(); // 进行绘制
  154. ctx.clearRect(0, 0, canvas.width, canvas.height);
  155. let pointData = [
  156. {
  157. arr: [
  158. { x: coordinateG.x * scalcX, y: canvas.height - coordinateG.y * scalcY }, //G
  159. { x: coordinateE.x * scalcX, y: canvas.height - coordinateE.y * scalcY }, //E
  160. { x: coordinateA.x * scalcX, y: canvas.height - coordinateA.y * scalcY }, //A
  161. { x: 0, y: canvas.height - maxY.value * scalcY },
  162. ],
  163. color: 'rgb(1, 127, 2, .9)',
  164. },
  165. {
  166. arr: [
  167. { x: 0, y: canvas.height }, //原点
  168. { x: coordinateF.x * scalcX, y: canvas.height - coordinateF.y * scalcY }, //F
  169. { x: coordinateE.x * scalcX, y: canvas.height - coordinateE.y * scalcY }, //E
  170. { x: coordinateG.x * scalcX, y: canvas.height - coordinateG.y * scalcY }, //G
  171. ],
  172. color: 'rgb(127, 254, 2, .9)',
  173. },
  174. {
  175. arr: [
  176. { x: coordinateF.x * scalcX, y: canvas.height - coordinateF.y * scalcY }, //F
  177. { x: maxX.value * scalcX, y: canvas.height },
  178. { x: maxX.value * scalcX, y: canvas.height - getCoordABY(maxX.value) * scalcY },
  179. { x: coordinateB.x * scalcX, y: canvas.height - coordinateB.y * scalcY }, //B
  180. { x: coordinateE.x * scalcX, y: canvas.height - coordinateE.y * scalcY }, //E
  181. ],
  182. color: 'rgb(255, 255, 0, .9)',
  183. },
  184. {
  185. arr: [
  186. { x: coordinateE.x * scalcX, y: canvas.height - coordinateE.y * scalcY }, //E
  187. { x: coordinateB.x * scalcX, y: canvas.height - coordinateB.y * scalcY }, //B
  188. { x: coordinateA.x * scalcX, y: canvas.height - coordinateA.y * scalcY }, //A
  189. ],
  190. color: 'rgb(255, 0, 0, .9)',
  191. },
  192. ];
  193. pointData.forEach((item, index) => {
  194. ctx.beginPath();
  195. ctx.moveTo(item.arr[0].x, item.arr[0].y);
  196. item.arr.forEach((items, ind) => {
  197. if (ind != 0) {
  198. ctx.lineTo(item.arr[ind].x, item.arr[ind].y);
  199. }
  200. });
  201. ctx.closePath();
  202. ctx.fillStyle = item.color;
  203. ctx.fill();
  204. ctx.strokeStyle = 'transparent';
  205. ctx.lineWidth = 1;
  206. ctx.stroke();
  207. });
  208. // 标记点A
  209. ctx.beginPath();
  210. ctx.arc(coordinateA.x * scalcX, canvas.height - coordinateA.y * scalcY, 1, 0, 2 * Math.PI);
  211. ctx.fillStyle = '#eee';
  212. ctx.fill();
  213. // 在点附近添加文字
  214. ctx.font = '12px Arial';
  215. ctx.fillStyle = '#fff';
  216. ctx.fillText('A', coordinateA.x * scalcX + 10, canvas.height - coordinateA.y * scalcY); // 文字位置略微偏上,以便于文字与点对齐
  217. //标记点B
  218. ctx.beginPath();
  219. ctx.arc(coordinateB.x * scalcX, canvas.height - coordinateB.y * scalcY, 1, 0, 2 * Math.PI);
  220. ctx.fillStyle = '#eee';
  221. ctx.fill();
  222. // 在点附近添加文字
  223. ctx.font = '12px Arial';
  224. ctx.fillStyle = '#fff';
  225. ctx.fillText('B', coordinateB.x * scalcX + 10, canvas.height - coordinateB.y * scalcY); // 文字位置略微偏上,以便于文字与点对齐
  226. //标记点E
  227. ctx.beginPath();
  228. ctx.arc(coordinateE.x * scalcX, canvas.height - coordinateE.y * scalcY, 1, 0, 2 * Math.PI);
  229. ctx.fillStyle = '#eee';
  230. ctx.fill();
  231. // 在点附近添加文字
  232. ctx.font = '12px Arial';
  233. ctx.fillStyle = '#fff';
  234. ctx.fillText('E', coordinateE.x * scalcX + 5, canvas.height - coordinateE.y * scalcY + 10); // 文字位置略微偏上,以便于文字与点对齐
  235. //标记点G
  236. ctx.beginPath();
  237. ctx.arc(coordinateG.x * scalcX, canvas.height - coordinateG.y * scalcY, 1, 0, 2 * Math.PI);
  238. ctx.fillStyle = '#eee';
  239. ctx.fill();
  240. // 在点附近添加文字
  241. ctx.font = '12px Arial';
  242. ctx.fillStyle = '#fff';
  243. ctx.fillText('G', coordinateG.x * scalcX + 5, canvas.height - coordinateG.y * scalcY); // 文字位置略微偏上,以便于文字与点对齐
  244. //标记点F
  245. ctx.beginPath();
  246. ctx.arc(coordinateF.x * scalcX, canvas.height - coordinateF.y * scalcY, 1, 0, 2 * Math.PI);
  247. ctx.fillStyle = '#eee';
  248. ctx.fill();
  249. // 在点附近添加文字
  250. ctx.font = '12px Arial';
  251. ctx.fillStyle = '#fff';
  252. ctx.fillText('F', coordinateF.x * scalcX + 10, canvas.height - coordinateF.y * scalcY - 10); // 文字位置略微偏上,以便于文字与点对齐
  253. //标记点
  254. ctx.beginPath();
  255. ctx.arc(maxX1.value * scalcX, canvas.height - maxY1.value * scalcY, 5, 0, 2 * Math.PI);
  256. ctx.fillStyle = 'blue';
  257. ctx.fill();
  258. // 在点附近添加文字
  259. ctx.font = '12px Arial';
  260. ctx.fillStyle = '#fff';
  261. ctx.fillText('', maxX1.value * scalcX + 10, canvas.height - maxY1.value * scalcY - 10); // 文字位置略微偏上,以便于文字与点对齐
  262. }
  263. //绘制不爆炸三角形
  264. function getUnblast() {
  265. maxY.value = 21;
  266. maxX.value = 50;
  267. // 获取canvas元素
  268. let canvas = document.getElementById('myCanvas');
  269. let ctx = canvas.getContext('2d');
  270. let scalcY = canvas.height / maxY.value;
  271. let scalcX = canvas.width / maxX.value;
  272. //绘制AB点线条
  273. ctx.beginPath();
  274. ctx.moveTo(0, canvas.height - maxY.value * scalcY); // 开始绘制的点
  275. ctx.lineTo(maxX.value * scalcX, canvas.height); // 结束绘制的点
  276. ctx.strokeStyle = '#000';
  277. ctx.stroke(); // 进行绘制
  278. ctx.clearRect(0, 0, canvas.width, canvas.height);
  279. let pointData = [
  280. {
  281. arr: [
  282. { x: 0, y: canvas.height }, //原点
  283. { x: 0, y: canvas.height - maxY.value * scalcY }, //A
  284. { x: maxX.value * scalcX, y: canvas.height }, //B
  285. ],
  286. color: 'rgb(127, 254, 2, .9)',
  287. },
  288. ];
  289. pointData.forEach((item, index) => {
  290. ctx.beginPath();
  291. ctx.moveTo(item.arr[0].x, item.arr[0].y);
  292. item.arr.forEach((items, ind) => {
  293. if (ind != 0) {
  294. ctx.lineTo(item.arr[ind].x, item.arr[ind].y);
  295. }
  296. });
  297. ctx.closePath();
  298. ctx.fillStyle = item.color;
  299. ctx.fill();
  300. ctx.strokeStyle = 'transparent';
  301. ctx.lineWidth = 1;
  302. ctx.stroke();
  303. });
  304. // 标记点A
  305. ctx.beginPath();
  306. ctx.arc(0, canvas.height - maxY.value * scalcY, 1, 0, 2 * Math.PI);
  307. ctx.fillStyle = '#eee';
  308. ctx.fill();
  309. // 在点附近添加文字
  310. ctx.font = '12px Arial';
  311. ctx.fillStyle = '#fff';
  312. ctx.fillText('A', 10, canvas.height - maxY.value * scalcY + 10); // 文字位置略微偏上,以便于文字与点对齐
  313. // 标记点B
  314. ctx.beginPath();
  315. ctx.arc(maxX.value * scalcX, canvas.height, 1, 0, 2 * Math.PI);
  316. ctx.fillStyle = '#eee';
  317. ctx.fill();
  318. // 在点附近添加文字
  319. ctx.font = '12px Arial';
  320. ctx.fillStyle = '#fff';
  321. ctx.fillText('B', maxX.value * scalcX - 10, canvas.height - 10); // 文字位置略微偏上,以便于文字与点对齐
  322. //标记点
  323. ctx.beginPath();
  324. ctx.arc(maxX1.value * scalcX, canvas.height - maxY1.value * scalcY, 5, 0, 2 * Math.PI);
  325. ctx.fillStyle = 'blue';
  326. ctx.fill();
  327. // 在点附近添加文字
  328. ctx.font = '12px Arial';
  329. ctx.fillStyle = '#fff';
  330. ctx.fillText('', maxX1.value * scalcX + 10, canvas.height - maxY1.value * scalcY - 10); // 文字位置略微偏上,以便于文字与点对齐
  331. }
  332. //根据横坐标获取直线AB纵坐标
  333. function getCoordABY(params) {
  334. return Math.ceil(
  335. ((parseFloat(coordinateB.y) - parseFloat(coordinateA.y)) * params -
  336. parseFloat(coordinateA.x) * parseFloat(coordinateB.y) +
  337. parseFloat(coordinateB.x) * parseFloat(coordinateA.y)) /
  338. (parseFloat(coordinateB.x) - parseFloat(coordinateA.x))
  339. );
  340. }
  341. //根据纵坐标获取直线AB横坐标
  342. function getCoordABX(params1) {
  343. return Math.floor(
  344. ((parseFloat(coordinateB.x) - parseFloat(coordinateA.x)) * params1 +
  345. parseFloat(coordinateA.x) * parseFloat(coordinateB.y) -
  346. parseFloat(coordinateB.x) * parseFloat(coordinateA.y)) /
  347. (parseFloat(coordinateB.y) - parseFloat(coordinateA.y))
  348. );
  349. }
  350. watch(
  351. () => props.posMonitor,
  352. (newV, oldV) => {
  353. if (newV.btTriBlast) {
  354. maxY1.value = parseFloat(newV.o2val);
  355. maxX1.value = parseFloat(newV.coval) * 0.0001 + parseFloat(newV.gasval) + parseFloat(newV.ch2val) * 0.0001 + parseFloat(newV.chval) * 0.0001;
  356. let btTriBlasts = newV.btTriBlast;
  357. coordinateA.x = btTriBlasts.A_x;
  358. coordinateA.y = btTriBlasts.A_y;
  359. coordinateB.x = btTriBlasts.B_x;
  360. coordinateB.y = btTriBlasts.B_y;
  361. coordinateE.x = btTriBlasts.E_x;
  362. coordinateE.y = btTriBlasts.E_y;
  363. coordinateF.x = btTriBlasts.F_x;
  364. coordinateF.y = btTriBlasts.F_y;
  365. coordinateG.x = btTriBlasts.G_x;
  366. coordinateG.y = btTriBlasts.G_y;
  367. if (
  368. !((coordinateA.y - coordinateB.y) / (coordinateA.x - coordinateB.x)) ||
  369. (coordinateA.y - coordinateB.y) / (coordinateA.x - coordinateB.x) == 1
  370. ) {
  371. // 使用 nextTick 为了让 immediate watch 触发时等待组件挂载后执行绘制
  372. nextTick(getUnblast);
  373. } else {
  374. nextTick(getBlast);
  375. }
  376. }
  377. },
  378. { deep: true, immediate: true }
  379. );
  380. onMounted(() => {
  381. getAreas();
  382. });
  383. </script>
  384. <style lang="less" scoped>
  385. .blastDelta {
  386. position: relative;
  387. width: 100%;
  388. height: 450px;
  389. .line-legend {
  390. position: absolute;
  391. left: 50%;
  392. top: 20px;
  393. width: 75%;
  394. height: 20px;
  395. transform: translate(-50%, 0);
  396. display: flex;
  397. justify-content: space-around;
  398. .legend-box {
  399. display: flex;
  400. height: 100%;
  401. justify-content: center;
  402. align-items: center;
  403. font-size: 12px;
  404. &:nth-child(1) {
  405. flex: 1;
  406. .legend-icon {
  407. width: 10px;
  408. height: 10px;
  409. background-color: #7ffe02;
  410. margin-right: 5px;
  411. }
  412. }
  413. &:nth-child(2) {
  414. flex: 1.5;
  415. .legend-icon {
  416. width: 10px;
  417. height: 10px;
  418. background-color: #017f02;
  419. margin-right: 5px;
  420. }
  421. }
  422. &:nth-child(3) {
  423. flex: 1;
  424. .legend-icon {
  425. width: 10px;
  426. height: 10px;
  427. background-color: #ff0000;
  428. margin-right: 5px;
  429. }
  430. }
  431. &:nth-child(4) {
  432. flex: 1;
  433. .legend-icon {
  434. width: 10px;
  435. height: 10px;
  436. background-color: #ffff00;
  437. margin-right: 5px;
  438. }
  439. }
  440. }
  441. }
  442. .coords {
  443. position: absolute;
  444. left: 50%;
  445. top: 50%;
  446. width: 90%;
  447. height: 80%;
  448. border-left: 1px solid #006c9d;
  449. border-bottom: 1px solid #006c9d;
  450. transform: translate(-45%, -46%);
  451. .coord-lineY {
  452. position: absolute;
  453. left: -5px;
  454. top: 10px;
  455. width: 5px;
  456. height: calc(100% - 10px);
  457. }
  458. .coord-labelY {
  459. position: absolute;
  460. left: -25px;
  461. top: -5px;
  462. width: 20px;
  463. height: 100%;
  464. }
  465. .coord-lineX {
  466. display: flex;
  467. position: absolute;
  468. bottom: -5px;
  469. right: 10px;
  470. width: calc(100% - 10px);
  471. height: 5px;
  472. }
  473. .coord-labelX {
  474. display: flex;
  475. justify-content: flex-end;
  476. position: absolute;
  477. bottom: -25px;
  478. left: -5px;
  479. width: 100%;
  480. height: 20px;
  481. }
  482. .line-AB {
  483. position: absolute;
  484. left: 0;
  485. top: 10px;
  486. }
  487. // .legend-name {
  488. // position: absolute;
  489. // right: 0;
  490. // top: 20px;
  491. // height: 80px;
  492. // .item-name {
  493. // height: 20px;
  494. // line-height: 20px;
  495. // font-size: 10px;
  496. // color: #fff;
  497. // letter-spacing: 2px;
  498. // }
  499. // }
  500. }
  501. }
  502. </style>