blastDelta1.vue 16 KB

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