line.ts 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. import { Nullable } from "babylonjs/types";
  2. import { Observer } from "babylonjs/Misc/observable";
  3. import { Vector3, Matrix } from "babylonjs/Maths/math";
  4. import { Tools } from "babylonjs/Misc/tools";
  5. import { Scene } from "babylonjs/scene";
  6. import { Control } from "./control";
  7. import { ValueAndUnit } from "../valueAndUnit";
  8. import { Measure } from "../measure";
  9. /** Class used to render 2D lines */
  10. export class Line extends Control {
  11. private _lineWidth = 1;
  12. private _x1 = new ValueAndUnit(0);
  13. private _y1 = new ValueAndUnit(0);
  14. private _x2 = new ValueAndUnit(0);
  15. private _y2 = new ValueAndUnit(0);
  16. private _dash = new Array<number>();
  17. private _connectedControl: Control;
  18. private _connectedControlDirtyObserver: Nullable<Observer<Control>>;
  19. /** Gets or sets the dash pattern */
  20. public get dash(): Array<number> {
  21. return this._dash;
  22. }
  23. public set dash(value: Array<number>) {
  24. if (this._dash === value) {
  25. return;
  26. }
  27. this._dash = value;
  28. this._markAsDirty();
  29. }
  30. /** Gets or sets the control connected with the line end */
  31. public get connectedControl(): Control {
  32. return this._connectedControl;
  33. }
  34. public set connectedControl(value: Control) {
  35. if (this._connectedControl === value) {
  36. return;
  37. }
  38. if (this._connectedControlDirtyObserver && this._connectedControl) {
  39. this._connectedControl.onDirtyObservable.remove(this._connectedControlDirtyObserver);
  40. this._connectedControlDirtyObserver = null;
  41. }
  42. if (value) {
  43. this._connectedControlDirtyObserver = value.onDirtyObservable.add(() => this._markAsDirty());
  44. }
  45. this._connectedControl = value;
  46. this._markAsDirty();
  47. }
  48. /** Gets or sets start coordinates on X axis */
  49. public get x1(): string | number {
  50. return this._x1.toString(this._host);
  51. }
  52. public set x1(value: string | number) {
  53. if (this._x1.toString(this._host) === value) {
  54. return;
  55. }
  56. if (this._x1.fromString(value)) {
  57. this._markAsDirty();
  58. }
  59. }
  60. /** Gets or sets start coordinates on Y axis */
  61. public get y1(): string | number {
  62. return this._y1.toString(this._host);
  63. }
  64. public set y1(value: string | number) {
  65. if (this._y1.toString(this._host) === value) {
  66. return;
  67. }
  68. if (this._y1.fromString(value)) {
  69. this._markAsDirty();
  70. }
  71. }
  72. /** Gets or sets end coordinates on X axis */
  73. public get x2(): string | number {
  74. return this._x2.toString(this._host);
  75. }
  76. public set x2(value: string | number) {
  77. if (this._x2.toString(this._host) === value) {
  78. return;
  79. }
  80. if (this._x2.fromString(value)) {
  81. this._markAsDirty();
  82. }
  83. }
  84. /** Gets or sets end coordinates on Y axis */
  85. public get y2(): string | number {
  86. return this._y2.toString(this._host);
  87. }
  88. public set y2(value: string | number) {
  89. if (this._y2.toString(this._host) === value) {
  90. return;
  91. }
  92. if (this._y2.fromString(value)) {
  93. this._markAsDirty();
  94. }
  95. }
  96. /** Gets or sets line width */
  97. public get lineWidth(): number {
  98. return this._lineWidth;
  99. }
  100. public set lineWidth(value: number) {
  101. if (this._lineWidth === value) {
  102. return;
  103. }
  104. this._lineWidth = value;
  105. this._markAsDirty();
  106. }
  107. /** Gets or sets horizontal alignment */
  108. public set horizontalAlignment(value: number) {
  109. return;
  110. }
  111. /** Gets or sets vertical alignment */
  112. public set verticalAlignment(value: number) {
  113. return;
  114. }
  115. private get _effectiveX2(): number {
  116. return (this._connectedControl ? this._connectedControl.centerX : 0) + this._x2.getValue(this._host);
  117. }
  118. private get _effectiveY2(): number {
  119. return (this._connectedControl ? this._connectedControl.centerY : 0) + this._y2.getValue(this._host);
  120. }
  121. /**
  122. * Creates a new Line
  123. * @param name defines the control name
  124. */
  125. constructor(public name?: string) {
  126. super(name);
  127. this.isHitTestVisible = false;
  128. this._horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  129. this._verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
  130. }
  131. protected _getTypeName(): string {
  132. return "Line";
  133. }
  134. public _draw(context: CanvasRenderingContext2D): void {
  135. context.save();
  136. if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
  137. context.shadowColor = this.shadowColor;
  138. context.shadowBlur = this.shadowBlur;
  139. context.shadowOffsetX = this.shadowOffsetX;
  140. context.shadowOffsetY = this.shadowOffsetY;
  141. }
  142. this._applyStates(context);
  143. context.strokeStyle = this.color;
  144. context.lineWidth = this._lineWidth;
  145. context.setLineDash(this._dash);
  146. context.beginPath();
  147. context.moveTo(this._cachedParentMeasure.left + this._x1.getValue(this._host), this._cachedParentMeasure.top + this._y1.getValue(this._host));
  148. context.lineTo(this._cachedParentMeasure.left + this._effectiveX2, this._cachedParentMeasure.top + this._effectiveY2);
  149. context.stroke();
  150. context.restore();
  151. }
  152. public _measure(): void {
  153. // Width / Height
  154. this._currentMeasure.width = Math.abs(this._x1.getValue(this._host) - this._effectiveX2) + this._lineWidth;
  155. this._currentMeasure.height = Math.abs(this._y1.getValue(this._host) - this._effectiveY2) + this._lineWidth;
  156. }
  157. protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
  158. this._currentMeasure.left = parentMeasure.left + Math.min(this._x1.getValue(this._host), this._effectiveX2) - this._lineWidth / 2;
  159. this._currentMeasure.top = parentMeasure.top + Math.min(this._y1.getValue(this._host), this._effectiveY2) - this._lineWidth / 2;
  160. }
  161. /**
  162. * Move one end of the line given 3D cartesian coordinates.
  163. * @param position Targeted world position
  164. * @param scene Scene
  165. * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
  166. */
  167. public moveToVector3(position: Vector3, scene: Scene, end: boolean = false): void {
  168. if (!this._host || this.parent !== this._host._rootContainer) {
  169. Tools.Error("Cannot move a control to a vector3 if the control is not at root level");
  170. return;
  171. }
  172. var globalViewport = this._host._getGlobalViewport(scene);
  173. var projectedPosition = Vector3.Project(position, Matrix.Identity(), scene.getTransformMatrix(), globalViewport);
  174. this._moveToProjectedPosition(projectedPosition, end);
  175. if (projectedPosition.z < 0 || projectedPosition.z > 1) {
  176. this.notRenderable = true;
  177. return;
  178. }
  179. this.notRenderable = false;
  180. }
  181. /**
  182. * Move one end of the line to a position in screen absolute space.
  183. * @param projectedPosition Position in screen absolute space (X, Y)
  184. * @param end (opt) Set to true to assign x2 and y2 coordinates of the line. Default assign to x1 and y1.
  185. */
  186. public _moveToProjectedPosition(projectedPosition: Vector3, end: boolean = false): void {
  187. let x: string = (projectedPosition.x + this._linkOffsetX.getValue(this._host)) + "px";
  188. let y: string = (projectedPosition.y + this._linkOffsetY.getValue(this._host)) + "px";
  189. if (end) {
  190. this.x2 = x;
  191. this.y2 = y;
  192. this._x2.ignoreAdaptiveScaling = true;
  193. this._y2.ignoreAdaptiveScaling = true;
  194. } else {
  195. this.x1 = x;
  196. this.y1 = y;
  197. this._x1.ignoreAdaptiveScaling = true;
  198. this._y1.ignoreAdaptiveScaling = true;
  199. }
  200. }
  201. }