Skip to main content
Participant
Jun 25, 2024 6:54 PM UTC
Question

Align Objects to a Line with Different Heights

I'm wondering if there's a way for users to align objects to a line with varying heights. For example, I have a line that steps down at various places. Is there a way to align objects with each horizontal segment of the line at different heights? Ideally I would like to center align those objects with the horizontal line segments if possible.

 

 

 

This topic is closed to new replies. Start a new post to keep the conversation going.

9 replies

jduncan
Community Expert
Community Expert
Jun 28, 2024 3:11 AM UTC

If I understand your request, the script below should get you the desired result (see pic below). I tried to trace your reference path as close as possible for testing. I have also included before and after vector files for you to work with as well.

 

Looking at your example picture, the path starts and ends on a horizontal segment. With this in mind, the script just iterates over each set of 2 points, determines the center point between, and then draws a cross mark (offset above the path). All cross marks are put in a separate layer and grouped.

 

I set everything up to be customized, cross color, cross size, and cross offset. See comments in script...

 

Try the script out and let me know if it does what you need.

 

(function () {
  // setup variables
  var doc,
    sel,
    selectedPath,
    layer,
    crossMarksGroup,
    crossMarkSize,
    crossMarkVerticalOffset,
    crossMarkColor,
    p1,
    p2,
    centerPointX;

  // no need to continue if there is no active document
  if (!app.documents.length) {
    alert("No active document.");
    return;
  }
  doc = app.activeDocument;

  // no need to continue if there is no active selection
  if (!doc.selection.length) {
    alert("No active selection.");
    return;
  }
  sel = doc.selection;

  // get the **FIRST** pathItem of the selected objects
  for (var i = 0; i < sel.length; i++) {
    if (sel[i].typename === "PathItem") {
      selectedPath = sel[i];
      break;
    }
  }

  // no need to continue if no pathItems were selected
  if (typeof selectedPath === "undefined") {
    alert("No paths were selected.");
    return;
  }

  // create a new layer to hold the lines (use old if already present)
  try {
    layer = doc.layers.getByName("SCRIPT CROSSES");
  } catch (error) {
    $.writeln("layer not found");
  }
  if (typeof layer === "undefined") {
    layer = doc.layers.add();
    layer.name = "SCRIPT CROSSES";
  }

  // create a group to hold all cross marks
  crossMarksGroup = layer.groupItems.add();

  // setup cross mark
  crossMarkSize = 9; // points
  crossMarkVerticalOffset = 18; // point above line
  var crossMarkColor = new RGBColor();
  crossMarkColor.red = 255;
  crossMarkColor.green = crossMarkColor.blue = 0;

  // iterate over each set of 2 points and draw cross marks
  for (var i = 0; i < selectedPath.pathPoints.length - 1; i += 2) {
    p1 = selectedPath.pathPoints[i];
    p2 = selectedPath.pathPoints[i + 1];

    // skip set if y-values don't match
    if (p1.anchor[1] != p2.anchor[1]) {
      continue;
    }

    // calculate center point between x-values
    centerPointX = p1.anchor[0] + (p2.anchor[0] - p1.anchor[0]) / 2;

    // draw cross at center point
    drawCrossMark(centerPointX, p1.anchor[1]);
  }

  function drawCrossMark(x, y) {
    // make a group to hold cross mark parts
    var crossGroup = crossMarksGroup.groupItems.add();
    // draw x-line part
    var xLine = crossGroup.pathItems.add();
    xLine.setEntirePath([
      [x - crossMarkSize / 2, y + crossMarkVerticalOffset],
      [x + crossMarkSize / 2, y + crossMarkVerticalOffset],
    ]);
    // draw y-line part
    var yLine = crossGroup.pathItems.add();
    yLine.setEntirePath([
      [x, y + crossMarkVerticalOffset + crossMarkSize / 2],
      [x, y + crossMarkVerticalOffset - crossMarkSize / 2],
    ]);
    // set cross mark styling
    xLine.strokeColor = yLine.strokeColor = crossMarkColor;
    xLine.stroked = yLine.stroked = true;
    xLine.strokeWidth = yLine.strokeWidth = selectedPath.strokeWidth;
    xLine.filled = yLine.filled = false;
  }
})();

 

Translate
NCM81Author
Participant
Jul 3, 2024 4:26 PM UTC

Sorry, I don't think I was clear enough. The crosses should be vertically centered on the horizontal line segment below them. Many times, I get outputs from SAS or r (graphing programs) where the created objects don't cross the horizontal line segment it rests on directly in the middle of the object. Thank you for the script, but this doesn't do quite what I need it to. See my reply to Kurt Gold above.

Translate
Kurt Gold
Community Expert
Community Expert
Jul 3, 2024 6:53 PM UTC

I'm sure Josh Duncan's script actually is what you are looking for. You just have to change line 59.

 

Instead of

 

  crossMarkVerticalOffset = 18;

 

just use

 

  crossMarkVerticalOffset = 0;

 

One could also create an action, but Josh's script does it very well.

Translate
Kurt Gold
Community Expert
Community Expert
Jun 25, 2024 8:10 PM UTC

Do the objects always have the same shape, size and appearance attributes (like the crosses in your screenshot)?

Translate
NCM81Author
Participant
Jun 27, 2024 9:12 PM UTC

Yes, the objects will always have the same size, shape, and appearnce attributes.

Translate
Kurt Gold
Community Expert
Community Expert
Jun 27, 2024 9:37 PM UTC

Does that mean that something as shown in the screenshot below may be the desired result?

 

 

Translate
Jacob Bugge
Community Expert
Community Expert
Jun 25, 2024 7:38 PM UTC

NCM,

 

You can:

 

1) Deselect the stepwise path (you can Click an empty spot to make sure);

2) With the Direct Selection Tool ShiftClick each and all of the path segments you wish align to;

3) Ctrl/Cmd+C+F (hold Ctrl/Cmd and press C then F) to copy all of them as independent paths;

4) Object>Transform>Move vertically by the desired distance up to the objects (negative value unless old version);

5) Deselect, then centre align each object (set) to each of the lines from 4), using it as the key object.

 

Translate
NCM81Author
Participant
Jun 27, 2024 9:19 PM UTC

Thank you for these steps. This is pretty easy to follow until the paths become a lot more complicated. I was hoping there was a script that would recognize the lowest point of a path below the object to be aligned with it. For instance, if the line segment looks like this, it seems like it would take a tremendous amount of time when the path is more complicated. 

 

 

Translate