summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/pipelines/components/graph_shared/drawing_utils.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/pipelines/components/graph_shared/drawing_utils.js')
-rw-r--r--app/assets/javascripts/pipelines/components/graph_shared/drawing_utils.js97
1 files changed, 97 insertions, 0 deletions
diff --git a/app/assets/javascripts/pipelines/components/graph_shared/drawing_utils.js b/app/assets/javascripts/pipelines/components/graph_shared/drawing_utils.js
new file mode 100644
index 00000000000..65c215be794
--- /dev/null
+++ b/app/assets/javascripts/pipelines/components/graph_shared/drawing_utils.js
@@ -0,0 +1,97 @@
+import * as d3 from 'd3';
+
+export const createUniqueLinkId = (stageName, jobName) => `${stageName}-${jobName}`;
+
+/**
+ * This function expects its first argument data structure
+ * to be the same shaped as the one generated by `parseData`,
+ * which contains nodes and links. For each link,
+ * we find the nodes in the graph, calculate their coordinates and
+ * trace the lines that represent the needs of each job.
+ * @param {Object} nodeDict - Resulting object of `parseData` with nodes and links
+ * @param {String} containerID - Id for the svg the links will be draw in
+ * @returns {Array} Links that contain all the information about them
+ */
+
+export const generateLinksData = ({ links }, containerID, modifier = '') => {
+ const containerEl = document.getElementById(containerID);
+ return links.map((link) => {
+ const path = d3.path();
+
+ const sourceId = link.source;
+ const targetId = link.target;
+
+ const modifiedSourceId = `${sourceId}${modifier}`;
+ const modifiedTargetId = `${targetId}${modifier}`;
+
+ const sourceNodeEl = document.getElementById(modifiedSourceId);
+ const targetNodeEl = document.getElementById(modifiedTargetId);
+
+ const sourceNodeCoordinates = sourceNodeEl.getBoundingClientRect();
+ const targetNodeCoordinates = targetNodeEl.getBoundingClientRect();
+ const containerCoordinates = containerEl.getBoundingClientRect();
+
+ // Because we add the svg dynamically and calculate the coordinates
+ // with plain JS and not D3, we need to account for the fact that
+ // the coordinates we are getting are absolutes, but we want to draw
+ // relative to the svg container, which starts at `containerCoordinates(x,y)`
+ // so we substract these from the total. We also need to remove the padding
+ // from the total to make sure it's aligned properly. We then make the line
+ // positioned in the center of the job node by adding half the height
+ // of the job pill.
+ const paddingLeft = parseFloat(
+ window.getComputedStyle(containerEl, null).getPropertyValue('padding-left'),
+ );
+ const paddingTop = parseFloat(
+ window.getComputedStyle(containerEl, null).getPropertyValue('padding-top'),
+ );
+
+ const sourceNodeX = sourceNodeCoordinates.right - containerCoordinates.x - paddingLeft;
+ const sourceNodeY =
+ sourceNodeCoordinates.top -
+ containerCoordinates.y -
+ paddingTop +
+ sourceNodeCoordinates.height / 2;
+ const targetNodeX = targetNodeCoordinates.x - containerCoordinates.x - paddingLeft;
+ const targetNodeY =
+ targetNodeCoordinates.y -
+ containerCoordinates.y -
+ paddingTop +
+ sourceNodeCoordinates.height / 2;
+
+ // Start point
+ path.moveTo(sourceNodeX, sourceNodeY);
+
+ // Make cross-stages lines a straight line all the way
+ // until we can safely draw the bezier to look nice.
+ // The adjustment number here is a magic number to make things
+ // look nice and should change if the padding changes. This goes well
+ // with gl-px-6. gl-px-8 is more like 100.
+ const straightLineDestinationX = targetNodeX - 60;
+ const controlPointX = straightLineDestinationX + (targetNodeX - straightLineDestinationX) / 2;
+
+ if (straightLineDestinationX > 0) {
+ path.lineTo(straightLineDestinationX, sourceNodeY);
+ }
+
+ // Add bezier curve. The first 4 coordinates are the 2 control
+ // points to create the curve, and the last one is the end point (x, y).
+ // We want our control points to be in the middle of the line
+ path.bezierCurveTo(
+ controlPointX,
+ sourceNodeY,
+ controlPointX,
+ targetNodeY,
+ targetNodeX,
+ targetNodeY,
+ );
+
+ return {
+ ...link,
+ source: sourceId,
+ target: targetId,
+ ref: createUniqueLinkId(sourceId, targetId),
+ path: path.toString(),
+ };
+ });
+};