14

I want to know if two text nodes are visually consecutive, regardless of html structure, i.e. that there isn't an empty line or any other element between both.

I'm using Ranges to get the rectangles (size and position) but there is a spacing between text nodes (the bottom of the first rect does not match the top of the second one).

I tried to calculate this spacing based on the line-height and font-size but I couldn't get the same value.

Here's a JsFiddle with my try: https://jsfiddle.net/3behsxxq/5/

Is there a way to calculate this spacing?

EDITED: In the first case of the jsFiddle code there are four lines ('first text', 'block', 'second', 'text block') that are visually consecutive, that is, visually the distance between them is the same, but the number that I get has a difference of 7 (in this first case). If I try to discard this space based on the difference between line-height/font-size and the values ​​of the range, they do not match, therefore I can not counteract it.

EDITED 2. Context: In the image below, the 6 lines have the same distance between them. I look for a way to determine that they are part of the same paragraph, regardless of the html structure (because the html could have a <p> element or any other element to represent the paragraph).

enter image description here

tru.d
  • 555
  • 2
  • 6
  • 23
jcbp
  • 475
  • 2
  • 10
  • I think part of the difficulty here is that the font-size in pixels is not the same as the full height from highest ascender (usually d, b, l, etc) to the lowest descender (p, q). Answers on this graphic design question are quite helpful: http://graphicdesign.stackexchange.com/questions/4035/what-does-the-size-of-the-font-translate-to-exactly – Robin James Kerrison Sep 20 '16 at 10:28
  • 2
    Is it enough for you to know that the space between the rectangles is less than the difference between the line-height and font-size? – Robin James Kerrison Sep 20 '16 at 10:33
  • Thanks for comment @RobinJamesKerrison. I am doing some test using a hidden element with a single line text and I create a range for this element to get the corresponding height. I would have liked to find a way to get this value from the element style but I think eventually I'll end up using this solution. – jcbp Sep 21 '16 at 15:09
  • 1
    Here's a related question that shows how to use jQuery to [determine the vertical distance from the top of the screen to the top of an element](https://stackoverflow.com/questions/7778580/how-to-find-the-vertical-distance-from-top-in-px-of-an-element-using-jquery). You should be able to use this, in conjunction with the element's height, to determine how far below the bottom of the first element the second element starts. – kmoser Sep 09 '17 at 03:19
  • @kmoser has a great point. Shouldn't this be possible with `element.offsetTop & element.offsetLeft & getClientRects`? – admcfajn Jan 06 '18 at 03:42
  • define "visually consecutive" in distance terms and it's possible to figure out from the different offset properties. – aviya.developer Jan 23 '19 at 11:45
  • 1
    @jcbp you want distance between two text Nodes. Your question is unclear please elaborate. – Maheer Ali Feb 08 '19 at 10:36
  • I edited the post for clarity. – jcbp Feb 12 '19 at 15:29
  • 2
    Even if two elements are visually consecutive, what if there is another element overlapping both of them via CSS relative or absolute positioning? – nnnnnn Feb 19 '19 at 06:00
  • @nnnnnn In my particular case, I resolve that in an independent way. I think of it as two different problems. – jcbp Feb 19 '19 at 13:49
  • Well, if there are 2 consecutive text nodes, they MUST be in 2 separate elements, or the DOM would turn them into a single text node. One way to measure the distance between them is to wrap each text node into an element, and find the distance between those elements using standard practices. – alfadog67 Apr 10 '19 at 22:52
  • Quite unsure what you are trying to achieve. If you want the GAP between rectangles, getBoundingClientRect() has top and bottom properties. var getGap = function(textNode1, textNode2) { const r = document.createRange(); r.selectNode(textNode1); const { bottom } = r.getBoundingClientRect(); r.selectNode(textNode2); const { top } = r.getBoundingClientRect(); return top - bottom; } – eavichay May 01 '19 at 14:28
  • @eavichay Thanks for commenting. I just edit again the post to add more clarity. Please see "Edited 2" for the context. – jcbp May 03 '19 at 03:11

1 Answers1

1
var extractTextNodes = function(paragraph) {
  var nodes = [];
  function callback(node) {
    if (node.nodeType === Node.TEXT_NODE) {
      nodes.push(node);
    } else if (node.nodeType === Node.ELEMENT_NODE) {
      node.childNodes.forEach(callback);
    }
  }
  paragraph.childNodes.forEach(callback);
  return nodes;
};

var findParentParagraph = function(node) {
  var parent = node.parentElement;
  while (parent) {
    if (parent.tagName === "P") {
      return parent;
    }
    parent = parent.parentElement;
  }

  return null;
};

var areTextNodesSiblings = function(textNode1, textNode2) {
  var p = findParentParagraph(textNode1);
  if (!p) {
    return false;
  }

  var allTextNodes = extractTextNodes(p);
  var index1 = allTextNodes.indexOf(textNode1);
  var index2 = allTextNodes.indexOf(textNode2);
  if (index2 === -1) {
    return false;
  }
  return (index1 === index2 - 1) || (index1 === index2 + 1);
};

And just call areTextNodesSiblings by passing the nodes.

Fiddle: https://jsfiddle.net/krmnve37/1/


The title says "visually consecutive" but "EDITED 2. Context" says that nodes must be in the same paragraph. The following function will check if the two nodes are just in the same paragraph, not if they're next to each other:

var areTextNodesInTheSameParagraph = function(textNode1, textNode2) {
  var p = findParentParagraph(textNode1);
  if (!p) {
    return false;
  }

  var allTextNodes = extractTextNodes(p);
  var index1 = allTextNodes.indexOf(textNode1);
  var index2 = allTextNodes.indexOf(textNode2);
  return index1 > -1 || index2 > -1;
};
Dimitar Nestorov
  • 2,411
  • 24
  • 29