vis.js is a dynamic, browser-based visualization library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

179 lines
5.1 KiB

  1. var Point3d = require('./Point3d');
  2. /**
  3. * The camera is mounted on a (virtual) camera arm. The camera arm can rotate
  4. * The camera is always looking in the direction of the origin of the arm.
  5. * This way, the camera always rotates around one fixed point, the location
  6. * of the camera arm.
  7. *
  8. * Documentation:
  9. * http://en.wikipedia.org/wiki/3D_projection
  10. * @class Camera
  11. */
  12. function Camera() {
  13. this.armLocation = new Point3d();
  14. this.armRotation = {};
  15. this.armRotation.horizontal = 0;
  16. this.armRotation.vertical = 0;
  17. this.armLength = 1.7;
  18. this.cameraOffset = new Point3d();
  19. this.offsetMultiplier = 0.6;
  20. this.cameraLocation = new Point3d();
  21. this.cameraRotation = new Point3d(0.5*Math.PI, 0, 0);
  22. this.calculateCameraOrientation();
  23. }
  24. /**
  25. * Set offset camera in camera coordinates
  26. * @param {Number} x offset by camera horisontal
  27. * @param {Number} y offset by camera vertical
  28. */
  29. Camera.prototype.setOffset = function(x, y) {
  30. var abs = Math.abs,
  31. sign = Math.sign,
  32. mul = this.offsetMultiplier,
  33. border = this.armLength * mul;
  34. if (abs(x) > border) {
  35. x = sign(x) * border;
  36. }
  37. if (abs(y) > border) {
  38. y = sign(y) * border;
  39. }
  40. this.cameraOffset.x = x;
  41. this.cameraOffset.y = y;
  42. this.calculateCameraOrientation();
  43. };
  44. /**
  45. * Get camera offset by horizontal and vertical
  46. * @returns {number}
  47. */
  48. Camera.prototype.getOffset = function() {
  49. return this.cameraOffset;
  50. };
  51. /**
  52. * Set the location (origin) of the arm
  53. * @param {Number} x Normalized value of x
  54. * @param {Number} y Normalized value of y
  55. * @param {Number} z Normalized value of z
  56. */
  57. Camera.prototype.setArmLocation = function(x, y, z) {
  58. this.armLocation.x = x;
  59. this.armLocation.y = y;
  60. this.armLocation.z = z;
  61. this.calculateCameraOrientation();
  62. };
  63. /**
  64. * Set the rotation of the camera arm
  65. * @param {Number} horizontal The horizontal rotation, between 0 and 2*PI.
  66. * Optional, can be left undefined.
  67. * @param {Number} vertical The vertical rotation, between 0 and 0.5*PI
  68. * if vertical=0.5*PI, the graph is shown from the
  69. * top. Optional, can be left undefined.
  70. */
  71. Camera.prototype.setArmRotation = function(horizontal, vertical) {
  72. if (horizontal !== undefined) {
  73. this.armRotation.horizontal = horizontal;
  74. }
  75. if (vertical !== undefined) {
  76. this.armRotation.vertical = vertical;
  77. if (this.armRotation.vertical < 0) this.armRotation.vertical = 0;
  78. if (this.armRotation.vertical > 0.5*Math.PI) this.armRotation.vertical = 0.5*Math.PI;
  79. }
  80. if (horizontal !== undefined || vertical !== undefined) {
  81. this.calculateCameraOrientation();
  82. }
  83. };
  84. /**
  85. * Retrieve the current arm rotation
  86. * @return {object} An object with parameters horizontal and vertical
  87. */
  88. Camera.prototype.getArmRotation = function() {
  89. var rot = {};
  90. rot.horizontal = this.armRotation.horizontal;
  91. rot.vertical = this.armRotation.vertical;
  92. return rot;
  93. };
  94. /**
  95. * Set the (normalized) length of the camera arm.
  96. * @param {Number} length A length between 0.71 and 5.0
  97. */
  98. Camera.prototype.setArmLength = function(length) {
  99. if (length === undefined)
  100. return;
  101. this.armLength = length;
  102. // Radius must be larger than the corner of the graph,
  103. // which has a distance of sqrt(0.5^2+0.5^2) = 0.71 from the center of the
  104. // graph
  105. if (this.armLength < 0.71) this.armLength = 0.71;
  106. if (this.armLength > 5.0) this.armLength = 5.0;
  107. this.setOffset(this.cameraOffset.x, this.cameraOffset.y);
  108. this.calculateCameraOrientation();
  109. };
  110. /**
  111. * Retrieve the arm length
  112. * @return {Number} length
  113. */
  114. Camera.prototype.getArmLength = function() {
  115. return this.armLength;
  116. };
  117. /**
  118. * Retrieve the camera location
  119. * @return {Point3d} cameraLocation
  120. */
  121. Camera.prototype.getCameraLocation = function() {
  122. return this.cameraLocation;
  123. };
  124. /**
  125. * Retrieve the camera rotation
  126. * @return {Point3d} cameraRotation
  127. */
  128. Camera.prototype.getCameraRotation = function() {
  129. return this.cameraRotation;
  130. };
  131. /**
  132. * Calculate the location and rotation of the camera based on the
  133. * position and orientation of the camera arm
  134. */
  135. Camera.prototype.calculateCameraOrientation = function() {
  136. // calculate location of the camera
  137. this.cameraLocation.x = this.armLocation.x - this.armLength * Math.sin(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical);
  138. this.cameraLocation.y = this.armLocation.y - this.armLength * Math.cos(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical);
  139. this.cameraLocation.z = this.armLocation.z + this.armLength * Math.sin(this.armRotation.vertical);
  140. // calculate rotation of the camera
  141. this.cameraRotation.x = Math.PI/2 - this.armRotation.vertical;
  142. this.cameraRotation.y = 0;
  143. this.cameraRotation.z = -this.armRotation.horizontal;
  144. var xa = this.cameraRotation.x;
  145. var za = this.cameraRotation.z;
  146. var dx = this.cameraOffset.x;
  147. var dy = this.cameraOffset.y;
  148. var sin = Math.sin, cos = Math.cos;
  149. this.cameraLocation.x = this.cameraLocation.x + dx * cos(za) + dy * - sin(za) * cos(xa);
  150. this.cameraLocation.y = this.cameraLocation.y + dx * sin(za) + dy * cos(za) * cos(xa);
  151. this.cameraLocation.z = this.cameraLocation.z + dy * sin(xa);
  152. };
  153. module.exports = Camera;