draw/TArrowPainter.mjs

  1. import { TLinePainter } from './TLinePainter.mjs';
  2. import { ensureTCanvas } from '../gpad/TCanvasPainter.mjs';
  3. /**
  4. * @summary Painter for TArrow class
  5. * @private
  6. */
  7. class TArrowPainter extends TLinePainter {
  8. #beg;
  9. #mid;
  10. #end;
  11. #angle2; // half of angle in rad
  12. #wsize; // arrow size
  13. /** @summary Create line segment with rotation */
  14. rotate(angle, x0, y0) {
  15. let dx = this.#wsize * Math.cos(angle), dy = this.#wsize * Math.sin(angle), res = '';
  16. if ((x0 !== undefined) && (y0 !== undefined))
  17. res = `M${Math.round(x0-dx)},${Math.round(y0-dy)}`;
  18. else {
  19. dx = -dx; dy = -dy;
  20. }
  21. res += `l${Math.round(dx)},${Math.round(dy)}`;
  22. if (x0 && (y0 === undefined))
  23. res += 'z';
  24. return res;
  25. }
  26. /** @summary Create SVG path for the arrow */
  27. createPath() {
  28. const angle = Math.atan2(this.y2 - this.y1, this.x2 - this.x1),
  29. dlen = this.#wsize * Math.cos(this.#angle2),
  30. dx = dlen*Math.cos(angle), dy = dlen*Math.sin(angle);
  31. let path = '';
  32. if (this.#beg) {
  33. path += this.rotate(angle - Math.PI - this.#angle2, this.x1, this.y1) +
  34. this.rotate(angle - Math.PI + this.#angle2, this.#beg > 10);
  35. }
  36. if (this.#mid % 10 === 2) {
  37. path += this.rotate(angle - Math.PI - this.#angle2, (this.x1+this.x2-dx)/2, (this.y1+this.y2-dy)/2) +
  38. this.rotate(angle - Math.PI + this.#angle2, this.#mid > 10);
  39. }
  40. if (this.#mid % 10 === 1) {
  41. path += this.rotate(angle - this.#angle2, (this.x1+this.x2+dx)/2, (this.y1+this.y2+dy)/2) +
  42. this.rotate(angle + this.#angle2, this.#mid > 10);
  43. }
  44. if (this.#end) {
  45. path += this.rotate(angle - this.#angle2, this.x2, this.y2) +
  46. this.rotate(angle + this.#angle2, this.#end > 10);
  47. }
  48. return `M${Math.round(this.x1 + (this.#beg > 10 ? dx : 0))},${Math.round(this.y1 + (this.#beg > 10 ? dy : 0))}` +
  49. `L${Math.round(this.x2 - (this.#end > 10 ? dx : 0))},${Math.round(this.y2 - (this.#end > 10 ? dy : 0))}` +
  50. path;
  51. }
  52. /** @summary calculate all TArrow coordinates */
  53. prepareDraw() {
  54. super.prepareDraw();
  55. const arrow = this.getObject(),
  56. oo = arrow.fOption,
  57. rect = this.getPadPainter().getPadRect();
  58. this.#wsize = Math.max(3, Math.round(Math.max(rect.width, rect.height) * arrow.fArrowSize * 0.8));
  59. this.#angle2 = arrow.fAngle/2/180 * Math.PI;
  60. this.#beg = this.#mid = this.#end = 0;
  61. if (oo.indexOf('<') === 0)
  62. this.#beg = (oo.indexOf('<|') === 0) ? 12 : 2;
  63. if (oo.indexOf('->-') >= 0)
  64. this.#mid = 1;
  65. else if (oo.indexOf('-|>-') >= 0)
  66. this.#mid = 11;
  67. else if (oo.indexOf('-<-') >= 0)
  68. this.#mid = 2;
  69. else if (oo.indexOf('-<|-') >= 0)
  70. this.#mid = 12;
  71. const p1 = oo.lastIndexOf('>'), p2 = oo.lastIndexOf('|>'), len = oo.length;
  72. if ((p1 >= 0) && (p1 === len-1))
  73. this.#end = ((p2 >= 0) && (p2 === len-2)) ? 11 : 1;
  74. this.createAttFill({ attr: arrow, enable: (this.#beg > 10) || (this.#end > 10) });
  75. }
  76. /** @summary Add extras to path for TArrow */
  77. addExtras(elem) {
  78. elem.call(this.fillatt.func);
  79. }
  80. /** @summary Draw TArrow object */
  81. static async draw(dom, obj, opt) {
  82. const painter = new TArrowPainter(dom, obj, opt);
  83. return ensureTCanvas(painter, false).then(() => painter.redraw());
  84. }
  85. } // class TArrowPainter
  86. export { TArrowPainter };