drawBox.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <template>
  2. <canvas ref="canvasRef" :width="width" :height="height"></canvas>
  3. <!-- <div ref="canvasContainer" class="canvas-container"></div> -->
  4. </template>
  5. <script setup>
  6. import { nextTick, onMounted, ref, watch, watchEffect } from "vue";
  7. const props = defineProps({
  8. width: {
  9. type: [String,Number],
  10. default: "",
  11. },
  12. height: {
  13. type: [String,Number],
  14. default: "",
  15. },
  16. sourceData: {
  17. type: String,
  18. default: "",
  19. },
  20. });
  21. onMounted(() => {
  22. clearCanvas()
  23. nextTick(()=>{
  24. draw(props.sourceData);
  25. })
  26. });
  27. const transformRectanglesToArrayOfObjects = (
  28. rectanglesArray,
  29. widthMultiple,
  30. heightMultiple
  31. ) => {
  32. return rectanglesArray.map((rectanglePoints) => {
  33. // 提取矩形的左上角和右下角坐标
  34. const [x1, y1, x2, y2] = rectanglePoints;
  35. // 为当前矩形生成四个顶点的对象数组
  36. return [
  37. {
  38. x: x1 / widthMultiple,
  39. y: y1 / heightMultiple,
  40. }, // 左上角
  41. {
  42. x: x2 / widthMultiple,
  43. y: y1 / heightMultiple,
  44. }, // 右上角
  45. {
  46. x: x2 / widthMultiple,
  47. y: y2 / heightMultiple,
  48. }, // 右下角
  49. {
  50. x: x1 / widthMultiple,
  51. y: y2 / heightMultiple,
  52. }, // 左下角
  53. ];
  54. });
  55. };
  56. const canvasRef = ref(null);
  57. const draw = (value) => {
  58. // const value = props.sourceData;
  59. const obj = JSON.parse(value);
  60. if(!obj.color_ins) return
  61. const widthMultiple = obj.width=='undefined'?obj.width:4000 / props.width;
  62. const heightMultiple = obj.height=='undefined'?obj.height:3000 / props.height;
  63. const ctx = canvasRef.value.getContext("2d");
  64. const boxList = transformRectanglesToArrayOfObjects(
  65. obj.cor,
  66. widthMultiple,
  67. heightMultiple
  68. );
  69. boxList.forEach((ele, idx) => {
  70. ctx.beginPath(); // 开始新的路径
  71. ctx.moveTo(ele[0].x, ele[0].y); // 移动到第一个点
  72. for (var i = 1; i < ele.length; i++) {
  73. ctx.lineTo(ele[i].x, ele[i].y); // 绘制线段到下一个点
  74. }
  75. ctx.lineTo(ele[0].x, ele[0].y); // 闭合图形(回到起点)
  76. ctx.closePath(); // 可选,因为moveTo和lineTo已经形成了一个闭环
  77. // 设置线条样式
  78. ctx.strokeStyle = `rgb(${obj.color_ins[idx][0]},${obj.color_ins[idx][1]},${obj.color_ins[idx][2]})`;
  79. ctx.lineWidth = 2; // 线条宽度
  80. // 绘制图形
  81. ctx.stroke(); // 只绘制轮廓
  82. // 添加文字
  83. // 设置填充颜色
  84. ctx.fillStyle = `rgb(${obj.color_ins[idx][0]},${obj.color_ins[idx][1]},${obj.color_ins[idx][2]})`;
  85. // 设置字体样式
  86. ctx.font = "14px Arial";
  87. // 在画布上绘制填充文本
  88. ctx.fillText(obj.label[idx], ele[0].x, ele[0].y - 5);
  89. });
  90. };
  91. const clearCanvas = () => {
  92. const canvas = canvasRef.value;
  93. if (canvas.getContext) {
  94. const ctx = canvas.getContext("2d");
  95. // 使用clearRect方法清空整个画布
  96. // 第一个和第二个参数是矩形左上角的x和y坐标,第三个和第四个参数是矩形的宽度和高度
  97. // 这里我们设置为0, 0, canvas.width, canvas.height来清空整个画布
  98. ctx.clearRect(0, 0, props.width, props.height);
  99. }
  100. };
  101. watch(
  102. () => props.sourceData,
  103. (newValue, oldValue) => {
  104. clearCanvas()
  105. if(newValue){
  106. draw(newValue)
  107. }
  108. },
  109. );
  110. </script>
  111. <style lang="scss" scoped>
  112. .canvas-container {
  113. width: 100%;
  114. height: 100%;
  115. display: flex;
  116. justify-content: center;
  117. }
  118. canvas {
  119. position: absolute;
  120. }
  121. </style>