39 votes

Coordonnées du texte sélectionné dans la page du navigateur

J'ai besoin des coordonnées en pixels du début de la sélection de texte (n'importe où sur la page, pas dans une zone de texte).

J'ai essayé d'utiliser les coordonnées du curseur mais cela n'a pas bien fonctionné car les coordonnées du curseur et le début de la sélection ne sont pas toujours les mêmes (par exemple lorsque l'utilisateur fait glisser sur un texte).

J'espère que quelqu'un a la solution!

69voto

Tim Down Points 124501

Dans IE >= 9 et les navigateurs non-IE (Firefox 4+, navigateurs WebKit sortis depuis le début de 2009, Opera 11, peut-être plus tôt), vous pouvez utiliser la méthode getClientRects() de Range. Dans IE 4 à 10, vous pouvez utiliser les propriétés boundingLeft et boundingTop de TextRange qui peuvent être extraites de la sélection. Voici une fonction qui fera ce que vous voulez dans les navigateurs récents.

Remarquez qu'il existe certaines situations où vous pouvez obtenir incorrectement les coordonnées 0, 0, comme mentionné dans les commentaires par @Louis. Dans ce cas, vous devrez revenir à une solution de contournement en insérant temporairement un élément et en obtenant sa position.

jsFiddle: http://jsfiddle.net/NFJ9r/132/

Code:

function getSelectionCoords(win) {
    win = win || window;
    var doc = win.document;
    var sel = doc.selection, range, rects, rect;
    var x = 0, y = 0;
    if (sel) {
        if (sel.type != "Control") {
            range = sel.createRange();
            range.collapse(true);
            x = range.boundingLeft;
            y = range.boundingTop;
        }
    } else if (win.getSelection) {
        sel = win.getSelection();
        if (sel.rangeCount) {
            range = sel.getRangeAt(0).cloneRange();
            if (range.getClientRects) {
                range.collapse(true);
                rects = range.getClientRects();
                if (rects.length > 0) {
                    rect = rects[0];
                }
                x = rect.left;
                y = rect.top;
            }
            // Revenir à l'insertion d'un élément temporaire
            if (x == 0 && y == 0) {
                var span = doc.createElement("span");
                if (span.getClientRects) {
                    // Assurez-vous que le span a des dimensions et une position en
                    // ajoutant un caractère d'espace de largeur zéro
                    span.appendChild( doc.createTextNode("\u200b") );
                    range.insertNode(span);
                    rect = span.getClientRects()[0];
                    x = rect.left;
                    y = rect.top;
                    var spanParent = span.parentNode;
                    spanParent.removeChild(span);

                    // Coller les nœuds textuels fragmentés ensemble
                    spanParent.normalize();
                }
            }
        }
    }
    return { x: x, y: y };
}

MISE À JOUR

J'ai soumis un bogue WebKit suite aux commentaires, et il a maintenant été corrigé.

https://bugs.webkit.org/show_bug.cgi?id=65324

24voto

Jakobovski Points 82

La réponse ci-dessus de TimDown ne fonctionne pas si le curseur se trouve dans un élément vide.

Le code ci-dessous résout le problème. Remarquez comment il est presque identique à la solution de TimDown, sauf que ce code vérifie si le tableau range.getClientRects() a une longueur>0 avant d'appeler range.getClientRects()[0]

function getSelectionCoords() {
    var sel = document.selection, range, rect;
    var x = 0, y = 0;
    if (sel) {
        if (sel.type != "Control") {
            range = sel.createRange();
            range.collapse(true);
            x = range.boundingLeft;
            y = range.boundingTop;
        }
    } else if (window.getSelection) {
        sel = window.getSelection();
        if (sel.rangeCount) {
            range = sel.getRangeAt(0).cloneRange();
            if (range.getClientRects) {
                range.collapse(true);
                if (range.getClientRects().length>0){
                    rect = range.getClientRects()[0];
                    x = rect.left;
                    y = rect.top;
                }
            }
            // Recours à l'insertion d'un élément temporaire
            if (x == 0 && y == 0) {
                var span = document.createElement("span");
                if (span.getClientRects) {
                    // Assurez-vous que le span a des dimensions et une position en
                    // ajoutant un caractère espace de largeur nulle
                    span.appendChild( document.createTextNode("\u200b") );
                    range.insertNode(span);
                    rect = span.getClientRects()[0];
                    x = rect.left;
                    y = rect.top;
                    var spanParent = span.parentNode;
                    spanParent.removeChild(span);

                    // Recoller les nœuds de texte cassés
                    spanParent.normalize();
                }
            }
        }
    }
    return { x: x, y: y };
}

7voto

sujenp Points 21

Le code ci-dessous est une version simplifiée et modernisée de la solution proposée par Tim Down. Il utilise également une API de sélection plus compatible avec les navigateurs (window.getSelection() au lieu de window.document.selection)

type Coord = {
  x: number;
  y: number;
};

// atStart: si vrai, retourne les coordonnées du début de la sélection,
// si faux, retourne les coordonnées de la fin de la sélection
function getSelectionCoords(atStart: boolean): Coord | null {
  const sel = window.getSelection();

  // vérifier si une sélection existe
  if (!sel.rangeCount) return null;

  // obtenir la plage
  let range = sel.getRangeAt(0).cloneRange();
  if (!range.getClientRects) return null;

  // obtenir le rectclient
  range.collapse(atStart);
  let rects = range.getClientRects();
  if (rects.length <= 0) return null;

  // retourner les coordonnées
  let rect = rects[0];
  return { x: rect.x, y: rect.y };
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X