draw/TLinePainter.mjs

  1. import { BIT } from '../core.mjs';
  2. import { DrawOptions } from '../base/BasePainter.mjs';
  3. import { ObjectPainter } from '../base/ObjectPainter.mjs';
  4. import { ensureTCanvas } from '../gpad/TCanvasPainter.mjs';
  5. import { addMoveHandler } from '../gui/utils.mjs';
  6. import { assignContextMenu } from '../gui/menu.mjs';
  7. const kLineNDC = BIT(14);
  8. /**
  9. * @summary Painter for TLine class
  10. * @private
  11. */
  12. class TLinePainter extends ObjectPainter {
  13. #side; // side which is interactively moved
  14. /** @summary Start interactive moving */
  15. moveStart(x, y) {
  16. const fullsize = Math.max(1, Math.sqrt((this.x1 - this.x2)**2 + (this.y1 - this.y2)**2)),
  17. sz1 = Math.sqrt((x - this.x1)**2 + (y - this.y1)**2)/fullsize,
  18. sz2 = Math.sqrt((x - this.x2)**2 + (y - this.y2)**2)/fullsize;
  19. if (sz1 > 0.9)
  20. this.#side = 1;
  21. else if (sz2 > 0.9)
  22. this.#side = -1;
  23. else
  24. this.#side = 0;
  25. }
  26. /** @summary Continue interactive moving */
  27. moveDrag(dx, dy) {
  28. if (this.#side !== 1) { this.x1 += dx; this.y1 += dy; }
  29. if (this.#side !== -1) { this.x2 += dx; this.y2 += dy; }
  30. this.getG().select('path').attr('d', this.createPath());
  31. }
  32. /** @summary Finish interactive moving */
  33. moveEnd(not_changed) {
  34. if (not_changed) return;
  35. const line = this.getObject();
  36. let exec = '',
  37. fx1 = this.svgToAxis('x', this.x1, this.isndc),
  38. fx2 = this.svgToAxis('x', this.x2, this.isndc),
  39. fy1 = this.svgToAxis('y', this.y1, this.isndc),
  40. fy2 = this.svgToAxis('y', this.y2, this.isndc);
  41. if (this.swap_xy)
  42. [fx1, fy1, fx2, fy2] = [fy1, fx1, fy2, fx2];
  43. line.fX1 = fx1;
  44. line.fX2 = fx2;
  45. line.fY1 = fy1;
  46. line.fY2 = fy2;
  47. if (this.#side !== 1) exec += `SetX1(${fx1});;SetY1(${fy1});;`;
  48. if (this.#side !== -1) exec += `SetX2(${fx2});;SetY2(${fy2});;`;
  49. this.submitCanvExec(exec + 'Notify();;');
  50. }
  51. /** @summary Returns object ranges
  52. * @desc Can be used for newly created canvas */
  53. getUserRanges() {
  54. const line = this.getObject(),
  55. isndc = line.TestBit(kLineNDC);
  56. if (isndc)
  57. return null;
  58. const minx = Math.min(line.fX1, line.fX2),
  59. maxx = Math.max(line.fX1, line.fX2),
  60. miny = Math.min(line.fY1, line.fY2),
  61. maxy = Math.max(line.fY1, line.fY2);
  62. return { minx, miny, maxx, maxy };
  63. }
  64. /** @summary Calculate line coordinates */
  65. prepareDraw() {
  66. const line = this.getObject();
  67. this.isndc = line.TestBit(kLineNDC);
  68. const use_frame = this.isndc ? false : new DrawOptions(this.getDrawOpt()).check('FRAME');
  69. this.createG(use_frame ? 'frame2d' : undefined);
  70. this.swap_xy = use_frame && this.getFramePainter()?.swap_xy();
  71. const func = this.getAxisToSvgFunc(this.isndc, true);
  72. this.x1 = func.x(line.fX1);
  73. this.y1 = func.y(line.fY1);
  74. this.x2 = func.x(line.fX2);
  75. this.y2 = func.y(line.fY2);
  76. if (this.swap_xy)
  77. [this.x1, this.y1, this.x2, this.y2] = [this.y1, this.x1, this.y2, this.x2];
  78. this.createAttLine({ attr: line });
  79. }
  80. /** @summary Create path */
  81. createPath() {
  82. const x1 = Math.round(this.x1), x2 = Math.round(this.x2), y1 = Math.round(this.y1), y2 = Math.round(this.y2);
  83. return `M${x1},${y1}` + (x1 === x2 ? `V${y2}` : (y1 === y2 ? `H${x2}` : `L${x2},${y2}`));
  84. }
  85. /** @summary Add extras - used for TArrow */
  86. addExtras() {}
  87. /** @summary Redraw line */
  88. redraw() {
  89. this.prepareDraw();
  90. const elem = this.appendPath(this.createPath())
  91. .call(this.lineatt.func);
  92. if (this.getObject()?.$do_not_draw)
  93. elem.remove();
  94. else {
  95. this.addExtras(elem);
  96. addMoveHandler(this);
  97. assignContextMenu(this);
  98. }
  99. return this;
  100. }
  101. /** @summary Draw TLine object */
  102. static async draw(dom, obj, opt) {
  103. const painter = new TLinePainter(dom, obj, opt);
  104. return ensureTCanvas(painter, false).then(() => painter.redraw());
  105. }
  106. } // class TLinePainter
  107. export { TLinePainter };