canvasRenderer.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // import { throttle } from "@pureadmin/utils";
  2. import { emitter } from "@/utils/mitt";
  3. export class CanvasRenderer {
  4. private canvas: HTMLCanvasElement;
  5. private ctx: CanvasRenderingContext2D;
  6. private images: {
  7. img: HTMLImageElement;
  8. x: number;
  9. y: number;
  10. width: number;
  11. height: number;
  12. }[];
  13. private container: HTMLElement;
  14. private positionX: number;
  15. private isDragging: boolean;
  16. private startX: number;
  17. constructor(containerId: string) {
  18. this.canvas = document.createElement("canvas");
  19. this.ctx = this.canvas.getContext("2d")!;
  20. this.images = [];
  21. this.positionX = 0;
  22. this.isDragging = false;
  23. this.startX = 0;
  24. this.container = document.getElementById(containerId);
  25. if (this.container) {
  26. this.container.appendChild(this.canvas);
  27. this.canvas.width = this.container.clientWidth;
  28. this.canvas.height = this.container.clientHeight;
  29. }
  30. }
  31. public addImage(
  32. url: string,
  33. x: number,
  34. y: number,
  35. width: number,
  36. height: number
  37. ) {
  38. const img = new Image();
  39. img.src = url;
  40. this.images.push({
  41. img,
  42. x,
  43. y,
  44. width,
  45. height
  46. });
  47. this.render();
  48. }
  49. public render() {
  50. this.clearRect();
  51. this.images.forEach(imgProps => {
  52. const x = imgProps.x + this.positionX;
  53. this.ctx.drawImage(
  54. imgProps.img,
  55. x,
  56. imgProps.y,
  57. imgProps.width,
  58. imgProps.height
  59. );
  60. });
  61. }
  62. public clearImages() {
  63. this.images = [];
  64. }
  65. public clearRect() {
  66. this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
  67. }
  68. public drawTick(event) {
  69. this.render();
  70. // 当前勾选图片的索引
  71. const index =
  72. Math.ceil(
  73. (Math.abs(this.positionX) + event.offsetX) / this.images[0].width
  74. ) - 1;
  75. const x = event.offsetX;
  76. const y = event.offsetY;
  77. // 绘制样式
  78. this.ctx.strokeStyle = "red";
  79. this.ctx.lineWidth = 4;
  80. this.ctx.lineCap = "round";
  81. // 绘制对勾
  82. this.ctx.beginPath();
  83. this.ctx.moveTo(x - 10, y);
  84. this.ctx.lineTo(x, y + 10);
  85. this.ctx.lineTo(x + 15, y - 10);
  86. this.ctx.stroke();
  87. emitter.emit("imageInfo", this.images[index]);
  88. }
  89. public addListener() {
  90. if (!this.canvas) return;
  91. this.canvas.addEventListener("click", this.handleClick);
  92. this.canvas.addEventListener("mousedown", this.handleMouseDown);
  93. this.canvas.addEventListener("mousemove", this.handleMouseMove);
  94. this.canvas.addEventListener("mouseup", this.handleMouseUp);
  95. this.canvas.addEventListener("touchstart", this.handleTouchStart);
  96. this.canvas.addEventListener("touchmove", this.handleTouchMove);
  97. this.canvas.addEventListener("touchend", this.handleTouchEnd);
  98. // window.addEventListener("resize", throttle(this.handleWindowResize, 200));
  99. }
  100. private handleClick = (event: MouseEvent) => {
  101. this.drawTick(event);
  102. };
  103. private handleMouseDown = (event: MouseEvent) => {
  104. this.startDrag(event.clientX);
  105. };
  106. private handleMouseMove = (event: MouseEvent) => {
  107. this.drag(event.clientX);
  108. };
  109. private handleMouseUp = () => {
  110. this.endDrag();
  111. };
  112. private handleTouchStart = (event: TouchEvent) => {
  113. if (event.touches.length === 1) {
  114. event.preventDefault();
  115. this.startDrag(event.touches[0].clientX);
  116. }
  117. };
  118. private handleTouchMove = (event: TouchEvent) => {
  119. if (event.touches.length === 1) {
  120. event.preventDefault();
  121. this.drag(event.touches[0].clientX);
  122. }
  123. };
  124. private handleTouchEnd = () => {
  125. this.endDrag();
  126. };
  127. private startDrag(clientX: number) {
  128. this.canvas.style.cursor = "grabbing";
  129. this.canvas.style.userSelect = "none";
  130. this.startX = clientX;
  131. this.isDragging = true;
  132. }
  133. private drag(clientX: number) {
  134. if (!this.isDragging) return;
  135. const deltaX = clientX - this.startX;
  136. const maxPositionX =
  137. this.images.length * this.images[0].width - this.container.clientWidth;
  138. this.positionX = Math.max(
  139. Math.min(this.positionX + deltaX, 0),
  140. -maxPositionX
  141. );
  142. this.startX = clientX;
  143. this.render();
  144. }
  145. private endDrag() {
  146. this.canvas.style.cursor = "grab";
  147. this.canvas.style.userSelect = "auto";
  148. this.isDragging = false;
  149. }
  150. // private handleWindowResize = () => {
  151. // this.canvas.width = this.container.clientWidth;
  152. // this.canvas.height = this.container.clientHeight;
  153. // this.render();
  154. // };
  155. }