SPath2D.ts 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. import { SPoint } from "./index";
  2. import {SStringBuilder} from "@persagy-web/base/lib";
  3. /**
  4. * Path对象
  5. *
  6. * @author 庞利祥(sybotan@126.com)
  7. */
  8. export class SPath2D {
  9. /** 内部path对象 */
  10. _path = new Path2D();
  11. private svgBuilder = new SStringBuilder();
  12. /**
  13. * svg数据值
  14. */
  15. svgPath(): string {
  16. return this.svgBuilder.toString(" ");
  17. } // Function svgPath()
  18. /**
  19. * 添加路径
  20. *
  21. * @param path 添加的路径
  22. */
  23. addPath(path: SPath2D): void {
  24. this._path.addPath(path._path);
  25. this.svgBuilder.append(path.svgBuilder.toString(" "))
  26. } // Function addPath()
  27. /**
  28. * 移动到指定位置
  29. *
  30. * @param x x坐标
  31. * @param y y坐标
  32. */
  33. moveTo(x: number, y: number): void {
  34. this._path.moveTo(x, y);
  35. this.svgBuilder.append(`M ${x} ${y}`);
  36. } // Function moveTo()
  37. /**
  38. * 从当前位置到指定位置画直线
  39. *
  40. * @param x x坐标
  41. * @param y y坐标
  42. */
  43. lineTo(x: number, y: number): void {
  44. this._path.lineTo(x, y);
  45. this.svgBuilder.append(`L ${x} ${y}`);
  46. } // Function moveTo()
  47. /**
  48. * 矩形
  49. *
  50. * @param x 左上角x坐标
  51. * @param y 左上角y坐标
  52. * @param width 宽度
  53. * @param height 高度
  54. */
  55. rect(x: number, y: number, width: number, height: number): void {
  56. let r = x + width;
  57. let b = y + height;
  58. this._path.moveTo(x, y);
  59. this._path.lineTo(r, y);
  60. this._path.lineTo(r, b);
  61. this._path.lineTo(x, b);
  62. this._path.closePath();
  63. this.svgBuilder.append(`M ${x} ${y} L${r} ${y} L${r} ${b} L${x} ${b} Z`);
  64. // // 逆时针
  65. // this._path.moveTo(x, y);
  66. // this._path.lineTo(r, y);
  67. // this._path.lineTo(r, b);
  68. // this._path.lineTo(x, b);
  69. // this._path.closePath();
  70. // this.svgBuilder.append(`M ${x} ${y} L${r} ${y} L${} ${} L${} ${} L${} ${}`);
  71. } // Function rect()
  72. /**
  73. * 绘制折线
  74. *
  75. * @param points 折线折点
  76. */
  77. polyline(points: SPoint[]): void {
  78. if (points.length < 2) {
  79. return;
  80. }
  81. points.map((it: SPoint, index: number): void => {
  82. if (index == 0) {
  83. this._path.moveTo(it.x, it.y);
  84. this.svgBuilder.append(`M ${it.x} ${it.y}`);
  85. } else {
  86. this._path.lineTo(it.x, it.y);
  87. this.svgBuilder.append(`L ${it.x} ${it.y}`);
  88. }
  89. });
  90. } // Function drawPolyline()
  91. /**
  92. * 绘制多边形
  93. *
  94. * @param points 多边形顶点
  95. */
  96. polygon(points: SPoint[]): void {
  97. if (points.length < 3) {
  98. return;
  99. }
  100. points.map((it: SPoint, index: number): void => {
  101. if (index == 0) {
  102. this._path.moveTo(it.x, it.y);
  103. this.svgBuilder.append(`M ${it.x} ${it.y}`);
  104. } else {
  105. this._path.lineTo(it.x, it.y);
  106. this.svgBuilder.append(`L ${it.x} ${it.y}`);
  107. }
  108. });
  109. this._path.closePath();
  110. this.svgBuilder.append(`Z`);
  111. } // Functin polygon()
  112. /**
  113. * 椭圆弧
  114. *
  115. * @param x 椭圆所在矩形X坐标
  116. * @param y 椭圆所在矩形Y坐标
  117. * @param width 椭圆所在矩形宽度
  118. * @param height 椭圆所在矩形高度
  119. * @param startAngle 开始角度(单位弧度)
  120. * @param endAngle 结束角度(单位弧度)
  121. */
  122. static arc(
  123. x: number,
  124. y: number,
  125. width: number,
  126. height: number,
  127. startAngle: number,
  128. endAngle: number
  129. ): string {
  130. let a = width / 2;
  131. let b = height / 2;
  132. let p1 = SPath2D.arcPoint(a, b, startAngle);
  133. let p2 = SPath2D.arcPoint(a, b, endAngle);
  134. let large = SPath2D.largeArcFlag(startAngle, endAngle);
  135. p1.x = x + a + p1.x;
  136. p1.y = y + b - p1.y;
  137. p2.x = x + a + p2.x;
  138. p2.y = y + b - p2.y;
  139. return `M ${p1.x} ${p1.y} A ${a} ${b} 0 ${large} 0 ${p2.x} ${p2.y}`;
  140. } // Function arc()
  141. /**
  142. * 绘制椭圆弦弧
  143. *
  144. * @param x 椭圆所在矩形X坐标
  145. * @param y 椭圆所在矩形Y坐标
  146. * @param width 椭圆所在矩形宽度
  147. * @param height 椭圆所在矩形高度
  148. * @param startAngle 开始角度(单位弧度)
  149. * @param endAngle 结束角度(单位弧度)
  150. */
  151. static chord(
  152. x: number,
  153. y: number,
  154. width: number,
  155. height: number,
  156. startAngle: number,
  157. endAngle: number
  158. ): string {
  159. let a = width / 2;
  160. let b = height / 2;
  161. let p1 = SPath2D.arcPoint(a, b, startAngle);
  162. let p2 = SPath2D.arcPoint(a, b, endAngle);
  163. let large = SPath2D.largeArcFlag(startAngle, endAngle);
  164. p1.x = x + a + p1.x;
  165. p1.y = y + b - p1.y;
  166. p2.x = x + a + p2.x;
  167. p2.y = y + b - p2.y;
  168. return `M ${p1.x} ${p1.y} A ${a} ${b} 0 ${large} 0 ${p2.x} ${p2.y} Z`;
  169. } // Function chord()
  170. /**
  171. * 绘制椭圆饼
  172. *
  173. * @param x 椭圆所在矩形X坐标
  174. * @param y 椭圆所在矩形Y坐标
  175. * @param width 椭圆所在矩形宽度
  176. * @param height 椭圆所在矩形高度
  177. * @param startAngle 开始角度(单位弧度)
  178. * @param endAngle 结束角度(单位弧度)
  179. */
  180. static pie(
  181. x: number,
  182. y: number,
  183. width: number,
  184. height: number,
  185. startAngle: number,
  186. endAngle: number
  187. ): string {
  188. let a = width / 2;
  189. let b = height / 2;
  190. let p1 = SPath2D.arcPoint(a, b, startAngle);
  191. let p2 = SPath2D.arcPoint(a, b, endAngle);
  192. let large = SPath2D.largeArcFlag(startAngle, endAngle);
  193. p1.x = x + a + p1.x;
  194. p1.y = y + b - p1.y;
  195. p2.x = x + a + p2.x;
  196. p2.y = y + b - p2.y;
  197. return `M ${x + a} ${y + b} L ${p1.x} ${
  198. p1.y
  199. } A ${a} ${b} 0 ${large} 0 ${p2.x} ${p2.y} Z`;
  200. } // Function pie()
  201. /**
  202. * 计算大弧标志
  203. *
  204. * @param startAngle 启动角度(单位弧度)
  205. * @param endAngle 结束角度(单位弧度)
  206. */
  207. static largeArcFlag(startAngle: number, endAngle: number): number {
  208. return ((Math.abs(endAngle - startAngle) * 180) / Math.PI) % 360 >
  209. 179.99999
  210. ? 1
  211. : 0;
  212. } // Function largeArcFlag()
  213. // https://blog.csdn.net/xiamentingtao/article/details/85804823
  214. static arcPoint(a: number, b: number, angle: number): SPoint {
  215. let p = new SPoint();
  216. if (angle >= 0) {
  217. angle = angle - Math.floor(angle / Math.PI / 2) * 2 * Math.PI;
  218. } else {
  219. angle = angle + Math.ceil(-angle / Math.PI / 2) * 2 * Math.PI;
  220. }
  221. if (Math.abs(Math.PI / 2 - angle) <= 0.000001) {
  222. p.x = 0;
  223. p.y = b;
  224. } else if (Math.abs((Math.PI * 3) / 2 - angle) <= 0.000001) {
  225. p.x = 0;
  226. p.y = -b;
  227. } else if (Math.PI / 2 < angle && angle < (Math.PI * 3) / 2) {
  228. p.x =
  229. -(a * b) /
  230. Math.sqrt(b * b + a * a * Math.tan(angle) * Math.tan(angle));
  231. p.y =
  232. -(a * b * Math.tan(angle)) /
  233. Math.sqrt(b * b + a * a * Math.tan(angle) * Math.tan(angle));
  234. } else {
  235. p.x =
  236. (a * b) /
  237. Math.sqrt(b * b + a * a * Math.tan(angle) * Math.tan(angle));
  238. p.y =
  239. (a * b * Math.tan(angle)) /
  240. Math.sqrt(b * b + a * a * Math.tan(angle) * Math.tan(angle));
  241. }
  242. return p;
  243. } // Function arcPoint()
  244. } // Class SPath2D