index.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /**
  2. * 刻度尺绘制
  3. *
  4. * @param {*} canvas - canvas元素
  5. * @param {*} canvasStyleWidth - canvasStyleWidth宽度
  6. * @param {*} canvasStyleHeight - canvasStyleHeight高度
  7. * @param {*} direcotion - 标尺方向
  8. * @param {*} scale - 缩放比例
  9. * @param {*} scrollX - 滚动x
  10. * @param {*} scrollY - 滚动y
  11. * @param {*} originX - 原点x
  12. * @param {*} originY - 原点y
  13. * */
  14. export function drawScaleplate({
  15. canvas,
  16. canvasStyleWidth,
  17. canvasStyleHeight,
  18. direcotion,
  19. scale,
  20. scrollX,
  21. scrollY,
  22. originX,
  23. originY,
  24. }: {
  25. canvas: HTMLCanvasElement;
  26. direcotion: "horizontal" | "vertical";
  27. canvasStyleWidth: number;
  28. canvasStyleHeight: number;
  29. scale: number;
  30. scrollX: number;
  31. scrollY: number;
  32. originX: number;
  33. originY: number;
  34. }) {
  35. const ctx = canvas.getContext("2d");
  36. if (!ctx) return;
  37. ctx.clearRect(0, 0, canvas.width, canvas.height);
  38. // 计算出清晰canvas的原始宽度 = 样式宽度 * 屏幕倍率
  39. const drp = window.devicePixelRatio || 1;
  40. const width = (canvas.width = canvasStyleWidth * drp);
  41. const height = (canvas.height = canvasStyleHeight * drp);
  42. // 起始位置
  43. const hStartNum = (scrollX - originX) / scale;
  44. const vStartNum = (scrollY - originY) / scale;
  45. // 计算大刻度, 判断跟20 50 100 250 500 1000谁更接近用谁
  46. const tickSpacingOptions = [20, 50, 100, 250, 500, 1000];
  47. const maxTickNum = tickSpacingOptions.reduce((prev, curr) => {
  48. return Math.abs(curr - 100 / scale) < Math.abs(prev - 100 / scale)
  49. ? curr
  50. : prev;
  51. });
  52. // 小刻度数
  53. const minTickNum = maxTickNum / 10;
  54. // 计算最小刻度的距离
  55. const minTickSpacing = (maxTickNum / 10) * scale * drp;
  56. const maxLength = direcotion === "horizontal" ? width : height;
  57. // 记录起始刻度值
  58. let startNum = Math.round(
  59. direcotion === "horizontal" ? hStartNum : vStartNum
  60. );
  61. // 计算起始刻度偏移量
  62. let startTickOffset = 0;
  63. if (startNum % minTickNum !== 0) {
  64. startTickOffset += Math.abs((startNum % minTickNum)) * scale * drp;
  65. startNum -= startNum % minTickNum;
  66. }
  67. // 每间隔小刻度数就绘制一个刻度
  68. for (
  69. let tickSpacing = startTickOffset;
  70. tickSpacing < maxLength;
  71. tickSpacing += minTickSpacing
  72. ) {
  73. // 如果当前为大刻度 需要展示数字
  74. if(startNum % maxTickNum === 0) {
  75. drawMaxTick(
  76. ctx,
  77. direcotion === "horizontal"
  78. ? tickSpacing
  79. : 0,
  80. direcotion === "horizontal"
  81. ? 0
  82. : tickSpacing,
  83. startNum,
  84. direcotion
  85. );
  86. } else if(startNum % minTickNum === 0) {
  87. // 如果当前为小刻度
  88. drawMinTick(
  89. ctx,
  90. direcotion === "horizontal"
  91. ? tickSpacing
  92. : 0,
  93. direcotion === "horizontal"
  94. ? 0
  95. : tickSpacing,
  96. direcotion
  97. );
  98. }
  99. startNum += minTickNum;
  100. }
  101. }
  102. // 绘制大刻度
  103. function drawMaxTick(
  104. ctx: CanvasRenderingContext2D,
  105. x: number,
  106. y: number,
  107. num: number,
  108. direcotion: "horizontal" | "vertical"
  109. ) {
  110. const drp = window.devicePixelRatio || 1;
  111. ctx.beginPath();
  112. if (direcotion === "horizontal") {
  113. ctx.moveTo(x + 1, 2);
  114. ctx.lineTo(x + 1, y + 20 * drp);
  115. } else {
  116. ctx.moveTo(x + 1, y);
  117. ctx.lineTo(x + 20 * drp, y);
  118. }
  119. ctx.strokeStyle = "#666";
  120. ctx.lineWidth = 1 * drp;
  121. ctx.stroke();
  122. ctx.fillStyle = "#666";
  123. ctx.font = "16px Arial";
  124. if (direcotion === "horizontal") {
  125. ctx.fillText(num.toString(), x + 5, 10 * drp);
  126. } else {
  127. ctx.save();
  128. if(num / 10 >= 100) {
  129. // >=1000
  130. ctx.translate(8, y + 25 * drp);
  131. } else if(num / 10 >= 10) {
  132. // >=100
  133. ctx.translate(8, y + 20 * drp);
  134. } else if(num / 10 >= 1) {
  135. // >=10
  136. ctx.translate(8, y + 20 * drp);
  137. } else if(num / 10 < 0) {
  138. ctx.translate(8, y + 25 * drp);
  139. } else {
  140. ctx.translate(8, y + 10 * drp);
  141. }
  142. ctx.rotate(-Math.PI / 2);
  143. ctx.fillText(num.toString(), 0, 10);
  144. ctx.restore();
  145. }
  146. }
  147. // 绘制小刻度
  148. function drawMinTick(
  149. ctx: CanvasRenderingContext2D,
  150. x: number,
  151. y: number,
  152. direcotion: "horizontal" | "vertical"
  153. ) {
  154. const drp = window.devicePixelRatio || 1;
  155. ctx.beginPath();
  156. if (direcotion === "horizontal") {
  157. ctx.moveTo(x + 1, 12 * drp);
  158. ctx.lineTo(x + 1, y + 20 * drp);
  159. } else {
  160. ctx.moveTo(12 * drp, y);
  161. ctx.lineTo(x + 20 * drp, y);
  162. }
  163. ctx.strokeStyle = "#666";
  164. ctx.lineWidth = 1 * drp;
  165. ctx.stroke();
  166. }