component/crosshair.js

  1. import * as d3 from "d3";
  2. import { colorParse } from "../colorHelper.js";
  3. /**
  4. * Reusable 3D Crosshair Component
  5. *
  6. * @module
  7. */
  8. export default function() {
  9. /* Default Properties */
  10. let dimensions = { x: 40, y: 40, z: 40 };
  11. let colors = ["blue", "red", "green"];
  12. let classed = "d3X3dCrosshair";
  13. let radius = 0.1;
  14. /* Scales */
  15. let xScale;
  16. let yScale;
  17. let zScale;
  18. /**
  19. * Constructor
  20. *
  21. * @constructor
  22. * @alias crosshair
  23. * @param {d3.selection} selection - The chart holder D3 selection.
  24. */
  25. const my = function(selection) {
  26. selection.each(function(data) {
  27. const element = d3.select(this)
  28. .classed(classed, true)
  29. .attr("id", (d) => d.key);
  30. dimensions.x = xScale ? Math.max(...xScale.range()) : dimensions.x;
  31. dimensions.y = yScale ? Math.max(...yScale.range()) : dimensions.y;
  32. dimensions.z = zScale ? Math.max(...zScale.range()) : dimensions.z;
  33. const xOff = dimensions.x / 2;
  34. const yOff = dimensions.y / 2;
  35. const zOff = dimensions.z / 2;
  36. const xVal = xScale(data.x);
  37. const yVal = yScale(data.y);
  38. const zVal = zScale(data.z);
  39. function getPositionVector(axisDir) {
  40. const positionVectors = {
  41. x: [xOff, yVal, zVal],
  42. y: [xVal, yOff, zVal],
  43. z: [xVal, yVal, zOff]
  44. };
  45. return positionVectors[axisDir];
  46. }
  47. function getRotationVector(axisDir) {
  48. const rotationVectors = {
  49. x: [1, 1, 0, Math.PI],
  50. y: [1, 0, 1, Math.PI],
  51. z: [0, 1, 1, Math.PI]
  52. };
  53. return rotationVectors[axisDir];
  54. }
  55. const colorScale = d3.scaleOrdinal()
  56. .domain(Object.keys(dimensions))
  57. .range(colors);
  58. // Origin Ball
  59. const ballSelect = element.selectAll(".ball")
  60. .data([data]);
  61. let ball = ballSelect.enter()
  62. .append("Transform")
  63. .attr("translation", `${xVal} ${yVal} ${zVal}`)
  64. .classed("ball", true)
  65. .append("Shape");
  66. ball.append("Appearance")
  67. .append("Material")
  68. .attr("diffuseColor", colorParse("blue"));
  69. ball.append("Sphere")
  70. .attr("radius", 0.3);
  71. ball.merge(ballSelect);
  72. ballSelect.transition()
  73. .ease(d3.easeQuadOut)
  74. .attr("translation", `${xVal} ${yVal} ${zVal}`);
  75. // Crosshair Lines
  76. const lineSelect = element.selectAll(".line")
  77. .data(Object.keys(dimensions));
  78. const line = lineSelect.enter()
  79. .append("Transform")
  80. .classed("line", true)
  81. .attr("translation", (d) => getPositionVector(d).join(" "))
  82. .attr("rotation", (d) => getRotationVector(d).join(" "))
  83. .append("Shape");
  84. line.append("cylinder")
  85. .attr("radius", radius)
  86. .attr("height", (d) => dimensions[d]);
  87. line.append("Appearance")
  88. .append("Material")
  89. .attr("diffuseColor", (d) => colorParse(colorScale(d)));
  90. line.merge(lineSelect);
  91. lineSelect.transition()
  92. .ease(d3.easeQuadOut)
  93. .attr("translation", (d) => getPositionVector(d).join(" "));
  94. });
  95. };
  96. /**
  97. * Dimensions Getter / Setter
  98. *
  99. * @param {{x: number, y: number, z: number}} _v - 3D object dimensions.
  100. * @returns {*}
  101. */
  102. my.dimensions = function(_v) {
  103. if (!arguments.length) return dimensions;
  104. dimensions = _v;
  105. return this;
  106. };
  107. /**
  108. * X Scale Getter / Setter
  109. *
  110. * @param {d3.scale} _v - D3 scale.
  111. * @returns {*}
  112. */
  113. my.xScale = function(_v) {
  114. if (!arguments.length) return xScale;
  115. xScale = _v;
  116. return my;
  117. };
  118. /**
  119. * Y Scale Getter / Setter
  120. *
  121. * @param {d3.scale} _v - D3 scale.
  122. * @returns {*}
  123. */
  124. my.yScale = function(_v) {
  125. if (!arguments.length) return yScale;
  126. yScale = _v;
  127. return my;
  128. };
  129. /**
  130. * Z Scale Getter / Setter
  131. *
  132. * @param {d3.scale} _v - D3 scale.
  133. * @returns {*}
  134. */
  135. my.zScale = function(_v) {
  136. if (!arguments.length) return zScale;
  137. zScale = _v;
  138. return my;
  139. };
  140. /**
  141. * Colors Getter / Setter
  142. *
  143. * @param {Array} _v - Array of colours used by color scale.
  144. * @returns {*}
  145. */
  146. my.colors = function(_v) {
  147. if (!arguments.length) return colors;
  148. colors = _v;
  149. return my;
  150. };
  151. return my;
  152. }