SPainter.ts 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. /*
  2. * *********************************************************************************************************************
  3. *
  4. * !!
  5. * .F88X
  6. * X8888Y
  7. * .}888888N;
  8. * i888888N; .:! .I$WI:
  9. * R888888I .'N88~ i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8&
  10. * .R888888I .;N8888~ .X8' "8I.!,/8" !%NY8`"8I8~~8>,88I
  11. * +888888N; .8888888Y "&&8Y.}8,
  12. * ./888888N; .R888888Y .'}~ .>}'.`+> i}! "i' +/' .'i~ !11,.:">, .~]! .i}i
  13. * ~888888%: .I888888l .]88~`1/iY88Ii+1'.R$8$8]"888888888> Y8$ W8E X8E W8888'188Il}Y88$*
  14. * 18888888 E8888881 .]W%8$`R8X'&8%++N8i,8N%N8+l8%` .}8N:.R$RE%N88N%N$K$R 188,FE$8%~Y88I
  15. * .E888888I .i8888888' .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~
  16. * 8888888I .,N888888~ ~88i"8W,!N8*.I88.}888%F,i$88"F88" 888:E8X.>88!i88>`888*.}Fl1]*}1YKi'
  17. * i888888N' I888Y ]88;/EX*IFKFK88X K8R .l8W 88Y ~88}'88E&%8W.X8N``]88!.$8K .:W8I
  18. * .i888888N; I8Y .&8$ .X88! i881.:%888>I88 ;88] +88+.';;;;:.Y88X 18N.,88l .+88/
  19. * .:R888888I
  20. * .&888888I Copyright (c) 2009-2020. 博锐尚格科技股份有限公司
  21. * ~8888'
  22. * .!88~ All rights reserved.
  23. *
  24. * *********************************************************************************************************************
  25. */
  26. import { SMatrix, SObject } from "@persagy-web/base";
  27. import { SPaintEngine } from "./engines/SPaintEngine";
  28. import {
  29. SBrush,
  30. SCanvasPaintEngine,
  31. SCanvasView,
  32. SFont,
  33. SLine,
  34. SPath,
  35. SPen,
  36. SPoint,
  37. SRect,
  38. SSize
  39. } from "./";
  40. import { SCompositeType } from "./enums/SCompositeType";
  41. import { SArrow } from "./types/SArrow";
  42. import { SArrowStyleType } from "./enums/SArrowStyleType";
  43. import { SShadow } from "./SShadow";
  44. /**
  45. * Painter
  46. *
  47. * @author 庞利祥(sybotan@126.com)
  48. */
  49. export class SPainter extends SObject {
  50. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  51. // 属性定义
  52. /** 绘制引擎 */
  53. private readonly engine: SPaintEngine;
  54. /** 画笔 */
  55. get pen(): SPen {
  56. return this.engine.state.pen;
  57. } // Get pen
  58. set pen(value: SPen) {
  59. this.engine.state.pen = value;
  60. } // Set pen
  61. /** 画刷 */
  62. get brush(): SBrush {
  63. return this.engine.state.brush;
  64. } // Get brush
  65. set brush(value: SBrush) {
  66. this.engine.state.brush = value;
  67. } // Set brush
  68. /** 字体属性 */
  69. get font(): SFont {
  70. return this.engine.state.font;
  71. } // Get font
  72. set font(value: SFont) {
  73. this.engine.state.font = value;
  74. this.engine.changeFont(value);
  75. } // Set font
  76. /** 融合属性 */
  77. get composite(): number {
  78. return this.engine.state._composite;
  79. } // Get composite
  80. set composite(value: number) {
  81. this.engine.state._composite = value;
  82. } // Set composite
  83. /** 阴影设置 */
  84. get shadow(): SShadow {
  85. return this.engine.state.shadow;
  86. } // Get shadow
  87. set shadow(value: SShadow) {
  88. this.engine.state.shadow = value;
  89. } // Set shadow
  90. /** 变换矩阵 */
  91. get worldTransform(): SMatrix {
  92. return this.engine.state.matrix;
  93. } // Get worldTransform
  94. /**
  95. * 构造函数
  96. *
  97. * @param engine 绘制引擎
  98. */
  99. constructor(engine: SCanvasView | SPaintEngine) {
  100. super();
  101. if (engine instanceof SCanvasView) {
  102. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  103. this.engine = new SCanvasPaintEngine(engine.canvas!!);
  104. } else {
  105. this.engine = engine;
  106. }
  107. this.pen = new SPen();
  108. this.brush = new SBrush();
  109. this.font = new SFont();
  110. this.composite = SCompositeType.SourceOver;
  111. this.shadow = new SShadow();
  112. } // Constructor()
  113. /**
  114. * 保存painter状态
  115. */
  116. save(): void {
  117. this.engine.save();
  118. } // Function save()
  119. /**
  120. * 恢复painter状态
  121. */
  122. restore(): void {
  123. this.engine.restore();
  124. } // Function restore()
  125. // =================================================================================================================
  126. // 变换相关
  127. /**
  128. * 平移变换
  129. *
  130. * @param x X轴方向平移
  131. * @param y Y辆方向平移
  132. */
  133. translate(x: number, y: number): void {
  134. this.engine.translate(x, y);
  135. } // Function translate()
  136. /**
  137. * 缩放
  138. *
  139. * @param x X轴方向缩放
  140. * @param y Y辆方向缩放
  141. */
  142. scale(x: number, y: number): void {
  143. this.engine.scale(x, y);
  144. } // Function scale()
  145. /**
  146. * 旋转
  147. *
  148. * @param angle 旋转角度(单位弧度)
  149. */
  150. rotate(angle: number): void {
  151. this.engine.rotate(angle);
  152. } // Function rotate()
  153. /**
  154. * 将当前的变形矩阵乘上一个基于自身参数的矩阵
  155. *
  156. * @param m11 水平方向的缩放
  157. * @param m12 水平方向的倾斜偏移
  158. * @param m21 竖直方向的倾斜偏移
  159. * @param m22 竖直方向的缩放
  160. * @param dx 水平方向的移动
  161. * @param dy 竖直方向的移动
  162. */
  163. transform(
  164. m11: number,
  165. m12: number,
  166. m21: number,
  167. m22: number,
  168. dx: number,
  169. dy: number
  170. ): void {
  171. this.engine.transform(m11, m12, m21, m22, dx, dy);
  172. } // Function transform()
  173. /**
  174. * 将当前的变形矩阵重置为单位矩阵,再将当前的变形矩阵乘上一个基于自身参数的矩阵
  175. *
  176. * @param m11 水平方向的缩放
  177. * @param m12 水平方向的倾斜偏移
  178. * @param m21 竖直方向的倾斜偏移
  179. * @param m22 竖直方向的缩放
  180. * @param dx 水平方向的移动
  181. * @param dy 竖直方向的移动
  182. */
  183. setTransform(
  184. m11: number,
  185. m12: number,
  186. m21: number,
  187. m22: number,
  188. dx: number,
  189. dy: number
  190. ): void {
  191. this.engine.setTransform(m11, m12, m21, m22, dx, dy);
  192. } // Function transform()
  193. /**
  194. * 重置当前变形为单位矩阵。等价于调用setTransform(1, 0, 0, 1, 0, 0)
  195. */
  196. resetTransform(): void {
  197. this.engine.resetTransform();
  198. } // Function resetTransform()
  199. // =================================================================================================================
  200. // 绘制相关
  201. /**
  202. * 设置裁剪路径
  203. *
  204. * @param path 裁剪路径
  205. */
  206. setClip(path: Path2D): void {
  207. this.engine.setClip(path);
  208. } // Function setClip()
  209. /**
  210. * 清空矩形区域
  211. *
  212. * @param rect 矩形
  213. */
  214. clearRect(rect: SRect): void;
  215. /**
  216. * 清空矩形区域
  217. *
  218. * @param leftTop 左上角坐标
  219. * @param rightBottom 右下角坐标
  220. */
  221. clearRect(leftTop: SPoint, rightBottom: SPoint): void;
  222. /**
  223. * 清空矩形区域
  224. *
  225. * @param leftTop 左上角坐标
  226. * @param size 大小
  227. */
  228. clearRect(leftTop: SPoint, size: SSize): void;
  229. /**
  230. * 清空矩形区域
  231. *
  232. * @param x X坐标
  233. * @param y Y坐标
  234. * @param w 宽度
  235. * @param h 高度
  236. */
  237. clearRect(x: number, y: number, w: number, h: number): void;
  238. /**
  239. * 清空矩形区域(重载实现)
  240. *
  241. * @param x X坐标 | 左上角坐标 | 矩形
  242. * @param y Y坐标 | 右下角坐标 | 大小
  243. * @param w 宽度
  244. * @param h 高度
  245. */
  246. clearRect(
  247. x: number | SPoint | SRect,
  248. y?: number | SPoint | SSize,
  249. w?: number,
  250. h?: number
  251. ): void {
  252. if (x instanceof SRect) {
  253. this.engine.clearRect(x);
  254. } else if (x instanceof SPoint && y instanceof SPoint) {
  255. this.engine.clearRect(new SRect(x, y));
  256. } else if (x instanceof SPoint && y instanceof SSize) {
  257. this.engine.clearRect(new SRect(x, y));
  258. } else {
  259. this.engine.clearRect(
  260. new SRect(x as number, y as number, w as number, h as number)
  261. );
  262. }
  263. } // Function clearRect()
  264. /**
  265. * 绘制矩形
  266. *
  267. * @param rect 矩形
  268. */
  269. drawRect(rect: SRect): void;
  270. /**
  271. * 绘制矩形
  272. *
  273. * @param leftTop 左上角坐标
  274. * @param rightBottom 右下角坐标
  275. */
  276. drawRect(leftTop: SPoint, rightBottom: SPoint): void;
  277. /**
  278. * 绘制矩形
  279. *
  280. * @param leftTop 左上角坐标
  281. * @param size 大小
  282. */
  283. drawRect(leftTop: SPoint, size: SSize): void;
  284. /**
  285. * 绘制矩形
  286. *
  287. * @param x X坐标
  288. * @param y Y坐标
  289. * @param w 宽度
  290. * @param h 高度
  291. */
  292. drawRect(x: number, y: number, w: number, h: number): void;
  293. /**
  294. * 绘制矩形
  295. *
  296. * @param x X坐标 | 左上角坐标 | 矩形
  297. * @param y Y坐标 | 右下角坐标 | 大小
  298. * @param w 宽度
  299. * @param h 高度
  300. */
  301. drawRect(
  302. x: number | SPoint | SRect,
  303. y?: number | SPoint | SSize,
  304. w?: number,
  305. h?: number
  306. ): void {
  307. if (x instanceof SRect) {
  308. this.engine.drawRect(x);
  309. } else if (x instanceof SPoint && y instanceof SPoint) {
  310. this.engine.drawRect(new SRect(x, y));
  311. } else if (x instanceof SPoint && y instanceof SSize) {
  312. this.engine.drawRect(new SRect(x, y));
  313. } else {
  314. this.engine.drawRect(
  315. new SRect(x as number, y as number, w as number, h as number)
  316. );
  317. }
  318. } // Function drawRect()
  319. /**
  320. * 绘制带导角矩形
  321. *
  322. * @param rect 矩形
  323. * @param r 导角半径
  324. */
  325. drawRoundRect(rect: SRect, r: number): void;
  326. /**
  327. * 绘制带导角矩形
  328. *
  329. * @param pos 左上角位置
  330. * @param size 大小
  331. * @param r 导角半径
  332. */
  333. drawRoundRect(pos: SPoint, size: SSize, r: number): void;
  334. /**
  335. * 绘制带导角矩形
  336. *
  337. * @param x X坐标
  338. * @param y Y坐标
  339. * @param w 宽度
  340. * @param h 高度
  341. * @param r 导角半径
  342. */
  343. drawRoundRect(x: number, y: number, w: number, h: number, r: number): void;
  344. /**
  345. * 绘制带导角矩形
  346. *
  347. * @param x X坐标
  348. * @param y Y坐标
  349. * @param w 宽度
  350. * @param h 高度
  351. * @param radius 导角半径
  352. */
  353. drawRoundRect(
  354. x: number | SPoint | SRect,
  355. y: number | SSize,
  356. w?: number,
  357. h?: number,
  358. radius?: number
  359. ): void {
  360. let rect: SRect | null;
  361. let r: number | null;
  362. if (x instanceof SRect) {
  363. rect = x;
  364. r = y as number;
  365. } else if (x instanceof SPoint && y instanceof SSize) {
  366. rect = new SRect(x, y);
  367. r = w as number;
  368. } else {
  369. rect = new SRect(
  370. x as number,
  371. y as number,
  372. w as number,
  373. h as number
  374. );
  375. r = radius as number;
  376. }
  377. if (rect != null && r != null) {
  378. this.engine.drawRoundRect(rect, r);
  379. }
  380. } // Function drawRoundRect()
  381. /**
  382. * 绘制圆形
  383. *
  384. * @param cx 圆心X坐标
  385. * @param cy 圆心X坐标
  386. * @param r 圆半径
  387. */
  388. drawCircle(cx: number, cy: number, r: number): void {
  389. this.engine.drawCircle(cx, cy, r);
  390. } // Function drawCircle()
  391. /**
  392. * 绘制椭圆
  393. *
  394. * @param cx 圆点X坐标
  395. * @param cy 圆点Y坐标
  396. * @param rx 水平半径
  397. * @param ry 垂直半径
  398. */
  399. drawEllipse(cx: number, cy: number, rx: number, ry: number): void {
  400. this.engine.drawEllipse(cx, cy, rx, ry);
  401. } // Function drawEllipse()
  402. /**
  403. * 绘制一条线段
  404. *
  405. * @param line 线段
  406. */
  407. drawLine(line: SLine): void;
  408. /**
  409. * 绘制一条线段
  410. *
  411. * @param p1 启点坐标
  412. * @param p2 终点坐标
  413. */
  414. drawLine(p1: SPoint, p2: SPoint): void;
  415. /**
  416. * 绘制一条线段
  417. *
  418. * @param x1 启点X坐标
  419. * @param y1 启点Y坐标
  420. * @param x2 终点X坐标
  421. * @param y2 终点Y坐标
  422. */
  423. drawLine(x1: number, y1: number, x2: number, y2: number): void;
  424. /**
  425. * 绘制一条线段(重载实现)
  426. *
  427. * @param x1 启点X坐标 | 起点1坐标 | 线段 |
  428. * @param y1 启点Y坐标 | 终点坐标
  429. * @param x2 终点X坐标
  430. * @param y2 终点Y坐标
  431. */
  432. drawLine(
  433. x1: number | SPoint | SLine,
  434. y1?: number | SPoint,
  435. x2?: number,
  436. y2?: number
  437. ): void {
  438. if (x1 instanceof SLine) {
  439. this.engine.drawLine(x1);
  440. } else if (x1 instanceof SPoint && y1 instanceof SPoint) {
  441. this.engine.drawLine(new SLine(x1, y1));
  442. } else {
  443. this.engine.drawLine(
  444. new SLine(
  445. x1 as number,
  446. y1 as number,
  447. x2 as number,
  448. y2 as number
  449. )
  450. );
  451. }
  452. } // Function drawLine()
  453. /**
  454. * 绘制折线
  455. *
  456. * @param points 折线折点
  457. */
  458. drawPolyline(points: SPoint[]): void {
  459. this.engine.drawPolyline(points);
  460. } // Function drawPolyline()
  461. /**
  462. * 绘制多边形
  463. *
  464. * @param points 多边形顶点
  465. */
  466. drawPolygon(points: SPoint[]): void {
  467. this.engine.drawPolygon(points);
  468. } // Function drawPolygon()
  469. /**
  470. * 绘制路径
  471. *
  472. * @param path 路径
  473. */
  474. drawPath(path: SPath): void {
  475. this.engine.drawPath(path);
  476. } // Function drawPath()
  477. /**
  478. * 绘制文本
  479. *
  480. * @param text 文本内容
  481. * @param x X坐标
  482. * @param y Y坐标
  483. * @param maxWidth 最大宽度
  484. */
  485. drawText(text: string, x: number, y: number, maxWidth?: number): void {
  486. this.engine.drawText(text, x, y, maxWidth);
  487. } // Function drawText()
  488. /**
  489. * 绘制图片
  490. *
  491. * @param img 图片
  492. * @param x X坐标
  493. * @param y Y坐标
  494. * @param width 宽度
  495. * @param height 高度
  496. */
  497. drawImage(
  498. img: CanvasImageSource,
  499. x: number,
  500. y: number,
  501. width?: number,
  502. height?: number
  503. ): void {
  504. this.engine.drawImage(img, x, y, width, height);
  505. } // Function drawImage()
  506. /**
  507. * painter转实现view象素
  508. *
  509. * @param p 绘制坐标
  510. */
  511. toPx(p: number): number {
  512. return p / this.engine.state.matrix.a;
  513. } // Function painterToView()
  514. /**
  515. * 预测量文本宽度
  516. *
  517. * @param text 文本字符
  518. * @return 文本所占长度像素
  519. * */
  520. textWidth(text: string): number {
  521. return this.engine.textWidth(text);
  522. }
  523. /**
  524. * 绘制带箭头的线段
  525. *
  526. * @param line 线段
  527. * @param style 末端样式
  528. */
  529. drawArrowLine(line: SLine, style?: SArrow): void;
  530. /**
  531. * 绘制带箭头的线段
  532. *
  533. * @param p1 启点坐标
  534. * @param p2 终点坐标
  535. * @param style 末端样式
  536. */
  537. drawArrowLine(p1: SPoint, p2: SPoint, style?: SArrow): void;
  538. /**
  539. * 绘制带箭头的线段
  540. *
  541. * @param x1 启点X坐标
  542. * @param y1 启点Y坐标
  543. * @param x2 终点X坐标
  544. * @param y2 终点Y坐标
  545. * @param style 末端样式
  546. */
  547. drawArrowLine(
  548. x1: number,
  549. y1: number,
  550. x2: number,
  551. y2: number,
  552. style?: SArrow
  553. ): void;
  554. /**
  555. * 绘制带箭头的线段
  556. *
  557. * @param x1 启点X坐标
  558. * @param y1 启点Y坐标
  559. * @param x2 终点X坐标
  560. * @param y2 终点Y坐标
  561. * @param st 线段两端样式
  562. */
  563. drawArrowLine(
  564. x1: number | SPoint | SLine,
  565. y1?: number | SPoint | SArrow,
  566. x2?: number | SArrow,
  567. y2?: number,
  568. st?: SArrow
  569. ): void {
  570. let line: SLine, style: SArrow;
  571. if (x1 instanceof SLine) {
  572. line = x1;
  573. style = y1 as SArrow;
  574. } else if (x1 instanceof SPoint && y1 instanceof SPoint) {
  575. line = new SLine(x1, y1);
  576. style = x2 as SArrow;
  577. } else {
  578. line = new SLine(
  579. x1 as number,
  580. y1 as number,
  581. x2 as number,
  582. y2 as number
  583. );
  584. style = st as SArrow;
  585. }
  586. this.engine.drawLine(line);
  587. if (style) {
  588. if (style.begin) {
  589. if (style.begin == SArrowStyleType.Basic) {
  590. this.drawBasicArrow(line, false);
  591. } else if (style.begin == SArrowStyleType.Triangle) {
  592. this.drawTriangleArrow(line, false);
  593. } else if (style.begin == SArrowStyleType.Diamond) {
  594. this.drawDiamondArrow(line, false);
  595. } else if (style.begin == SArrowStyleType.Square) {
  596. this.drawSquareArrow(line, false);
  597. } else if (style.begin == SArrowStyleType.Circle) {
  598. this.drawCircleArrow(line, false);
  599. }
  600. }
  601. if (style.end) {
  602. if (style.end == SArrowStyleType.Basic) {
  603. this.drawBasicArrow(line, true);
  604. } else if (style.end == SArrowStyleType.Triangle) {
  605. this.drawTriangleArrow(line, true);
  606. } else if (style.end == SArrowStyleType.Diamond) {
  607. this.drawDiamondArrow(line, true);
  608. } else if (style.end == SArrowStyleType.Square) {
  609. this.drawSquareArrow(line, true);
  610. } else if (style.end == SArrowStyleType.Circle) {
  611. this.drawCircleArrow(line, true);
  612. }
  613. }
  614. }
  615. } // Function drawArrowLine()
  616. /**
  617. * 私有计算方法-绘制线段末端标准箭头
  618. *
  619. * @param line 要加末端样式的线段
  620. * @param isEnd 是否为结束位置
  621. * */
  622. private drawBasicArrow(line: SLine, isEnd: boolean = true): void {
  623. // 定义箭头长度
  624. const d = this.toPx(10);
  625. // 箭头横坐标
  626. const x1 = d * Math.cos(Math.PI / 4);
  627. // 箭头纵坐标
  628. const y1 = d * Math.sin(Math.PI / 4);
  629. // 线段与x轴夹角
  630. const fo = Math.atan(line.dy / line.dx);
  631. this.save();
  632. // 是否为终点画箭头
  633. if (isEnd) {
  634. this.translate(line.x2, line.y2);
  635. this.rotate((fo * 180) / Math.PI);
  636. this.engine.drawPolyline([
  637. new SPoint(-x1, y1),
  638. new SPoint(0, 0),
  639. new SPoint(-x1, -y1)
  640. ]);
  641. } else {
  642. this.translate(line.x1, line.y1);
  643. this.rotate((fo * 180) / Math.PI);
  644. this.engine.drawPolyline([
  645. new SPoint(x1, y1),
  646. new SPoint(0, 0),
  647. new SPoint(x1, -y1)
  648. ]);
  649. }
  650. this.restore();
  651. } // Function drawArrow()
  652. /**
  653. * 私有计算方法-绘制线段末端三角形箭头
  654. *
  655. * @param line 要加末端样式的线段
  656. * @param isEnd 是否为结束位置
  657. * */
  658. private drawTriangleArrow(line: SLine, isEnd: boolean = true): void {
  659. // 定义箭头长度
  660. const d = this.toPx(10);
  661. // 箭头横坐标
  662. const x1 = d * Math.cos(Math.PI / 12);
  663. // 箭头纵坐标
  664. const y1 = d * Math.sin(Math.PI / 12);
  665. // 线段与x轴夹角
  666. const fo = Math.atan(line.dy / line.dx);
  667. this.save();
  668. // 是否为终点画箭头
  669. if (isEnd) {
  670. this.translate(line.x2, line.y2);
  671. this.rotate((fo * 180) / Math.PI);
  672. this.engine.drawPolygon([
  673. new SPoint(-x1, y1),
  674. new SPoint(0, 0),
  675. new SPoint(-x1, -y1)
  676. ]);
  677. } else {
  678. this.translate(line.x1, line.y1);
  679. this.rotate((fo * 180) / Math.PI);
  680. this.engine.drawPolygon([
  681. new SPoint(x1, y1),
  682. new SPoint(0, 0),
  683. new SPoint(x1, -y1)
  684. ]);
  685. }
  686. this.restore();
  687. } // Function drawTriangleArrow()
  688. /**
  689. * 私有计算方法-绘制线段末端菱形箭头
  690. *
  691. * @param line 要加末端样式的线段
  692. * @param isEnd 是否为结束位置
  693. * */
  694. private drawDiamondArrow(line: SLine, isEnd: boolean = true): void {
  695. // 定义箭头长度
  696. const d = this.toPx(5);
  697. // 箭头横坐标
  698. const x1 = d * Math.cos(Math.PI / 4);
  699. // 箭头纵坐标
  700. const y1 = d * Math.sin(Math.PI / 4);
  701. // 线段与x轴夹角
  702. const fo = Math.atan(line.dy / line.dx);
  703. this.save();
  704. // 是否为终点画箭头
  705. if (isEnd) {
  706. this.translate(line.x2, line.y2);
  707. this.rotate((fo * 180) / Math.PI);
  708. this.engine.drawPolygon([
  709. new SPoint(-x1, y1),
  710. new SPoint(0, 0),
  711. new SPoint(-x1, -y1),
  712. new SPoint(-Math.sqrt(2) * d, 0)
  713. ]);
  714. } else {
  715. this.translate(line.x1, line.y1);
  716. this.rotate((fo * 180) / Math.PI);
  717. this.engine.drawPolygon([
  718. new SPoint(x1, y1),
  719. new SPoint(0, 0),
  720. new SPoint(x1, -y1),
  721. new SPoint(Math.sqrt(2) * d, 0)
  722. ]);
  723. }
  724. this.restore();
  725. } // Function drawDiamondArrow()
  726. /**
  727. * 私有计算方法-绘制线段末端方形箭头
  728. *
  729. * @param line 要加末端样式的线段
  730. * @param isEnd 是否为结束位置
  731. * */
  732. private drawSquareArrow(line: SLine, isEnd: boolean = true): void {
  733. // 定义箭头长度
  734. const d = this.toPx(5);
  735. // 线段与x轴夹角
  736. const fo = Math.atan(line.dy / line.dx);
  737. this.save();
  738. // 是否为终点画箭头
  739. if (isEnd) {
  740. this.translate(line.x2, line.y2);
  741. this.rotate((fo * 180) / Math.PI);
  742. this.engine.drawPolygon([
  743. new SPoint(-d, d / 2),
  744. new SPoint(0, d / 2),
  745. new SPoint(0, -d / 2),
  746. new SPoint(-d, -d / 2)
  747. ]);
  748. } else {
  749. this.translate(line.x1, line.y1);
  750. this.rotate((fo * 180) / Math.PI);
  751. this.engine.drawPolygon([
  752. new SPoint(0, d / 2),
  753. new SPoint(d, d / 2),
  754. new SPoint(d, -d / 2),
  755. new SPoint(0, -d / 2)
  756. ]);
  757. }
  758. this.restore();
  759. } // Function drawSquareArrow()
  760. /**
  761. * 私有计算方法-绘制线段末端圆形箭头
  762. *
  763. * @param line 要加末端样式的线段
  764. * @param isEnd 是否为结束位置
  765. * */
  766. private drawCircleArrow(line: SLine, isEnd: boolean = true): void {
  767. // 定义箭头长度
  768. const d = this.toPx(5);
  769. // 线段与x轴夹角
  770. const fo = Math.atan(line.dy / line.dx);
  771. // 是否为终点画箭头
  772. this.save();
  773. if (isEnd) {
  774. this.translate(line.x2, line.y2);
  775. this.rotate((fo * 180) / Math.PI);
  776. this.engine.drawCircle(-d / 2, 0, d / 2);
  777. } else {
  778. this.translate(line.x1, line.y1);
  779. this.rotate((fo * 180) / Math.PI);
  780. this.engine.drawCircle(d / 2, 0, d / 2);
  781. }
  782. this.restore();
  783. } // Function drawCircleArrow()
  784. } // Class SPainter