Maison >interface Web >js tutoriel >Problèmes liés à l'évitement de texte dans les algorithmes front-end (tutoriel détaillé)

Problèmes liés à l'évitement de texte dans les algorithmes front-end (tutoriel détaillé)

亚连
亚连original
2018-06-12 14:34:142581parcourir

Cet article vous présente principalement les informations pertinentes sur l'évitement de texte dans l'algorithme frontal. Je pense que beaucoup d'amis ne connaissent pas cette connaissance, mais ils seront étonnés lorsqu'ils verront l'effet de l'utilisation principale du texte inMap. Pour obtenir cet effet, la fonction d'évitement est présentée en détail à travers un exemple de code dans cet article. Les amis qui en ont besoin peuvent s'y référer.

Avant-propos

inMap est une bibliothèque de visualisation Big Data basée sur Canvas, axée sur l'affichage visuel de points de direction, de lignes et de surfaces Big Data . Prend actuellement en charge les méthodes de dispersion, de clôture, thermique, de grille, d'agrégation et d'autres méthodes ; elle s'engage à rendre la visualisation Big Data simple et facile à utiliser.

Adresse GitHub : https://github.com/TalkingData/inmap (téléchargement local)

Adresse du document : http://inmap.talkingdata.com/

at Dans la visualisation d'informations géographiques, nous rencontrons souvent le besoin de marquer du texte sur la carte. Ce qui suit montre l'effet d'un cadre graphique populaire :

L'espace de texte à afficher. Lorsque cela ne suffit pas, cela entraînera un chevauchement de texte et un affichage confus, rendant l'expérience utilisateur très peu conviviale.

Comment résoudre ce problème ? Nous utilisons un algorithme d'évitement de texte pour résoudre ce problème de triche.

Ce qui suit montre l'effet d'évitement de texte inMap :

L'algorithme d'annotation de texte est l'un des problèmes les plus complexes des SIG (appartient au problème de complexité NP, donc la solution optimale ne peut généralement pas être trouvée, seulement la meilleure solution).

L'algorithme d'évitement inMap utilise l'algorithme du modèle quartile. Ensuite, je vais vous apprendre à écrire l'algorithme d'évitement étape par étape. Un pilote expérimenté vous aidera à vous montrer et à voler.

Préparer les données

inMap reçoit les données de latitude et de longitude et doit les mapper aux coordonnées en pixels du canevas, qui utilise la conversion Mercator , L'algorithme de Mercator est très compliqué. Nous aurons un article séparé pour expliquer ses principes à l'avenir. Après la conversion, les données que vous obtenez devraient ressembler à ceci :

[
 {
 "name": "海门",//要显示的文字
 "lng": 121.15,
 "lat": 31.89,
 "count": 7,
 "pixel": { //像素坐标
  "x": 968,
  "y": 736
 }
 },
 {
 "name": "鄂尔多斯",
 "lng": 109.781327,
 "lat": 39.608266,
 "count": 5,
 "pixel": {
  "x": 659,
  "y": 478
 }
 },
...
]

D'accord, maintenant que nous avons les données de coordonnées de pixels converties (x, y), nous pouvons procéder comme suit.

Trouver la taille réelle de chaque rectangle de texte

measureText() est une méthode intégrée de canevas, qui renvoie l'unité de pixel de la largeur de la police :

let ctx = this.container.getContext('2d'); // canvas 上下文
let width= ctx.measureText(name).width;

Nous obtenons la largeur de chaque texte via MeasureText. Canvas n'a pas de méthode directe pour obtenir le texte, alors comment obtenir la hauteur du texte ?

Nous avons constaté, grâce à des tests répétés, que lorsque la police du canevas est égale à la police "13px Arial" (les autres polices ne peuvent pas être garanties), la hauteur du texte est d'environ 1,1 fois la taille de la police.

Le code est donc le suivant :

let fontSize = parseInt(ctx.font);
let height = fontSize * 1.1;

Une fois la largeur et la hauteur du texte obtenues, nous pouvons créer le système de coordonnées du rectangle de texte.

Créer un modèle quartile

Le modèle dit quartile, chaque point marqueur a Il y a quatre emplacements pour le texte en haut, en bas, à gauche et à droite. Si vous ne pouvez pas le mettre sur le côté gauche, essayez de le mettre sur le côté droit. Si cela ne fonctionne toujours pas, essayez de le mettre en bas. ainsi de suite. Le principe est aussi simple que cela, haha.

Créer une description des coordonnées du rectangle virtuel de droite :

La description des coordonnées du rectangle virtuel de droite comprend également des points pour éviter que le texte et les points ne se chevauchent.

Il existe quelques pièges lors du calcul de la hauteur du rectangle virtuel. La taille du point n'est pas fixe, mais est configurée dynamiquement en fonction de l'utilisateur. Le diamètre du point peut être supérieur à la hauteur du point. texte, nous définissons donc la hauteur du rectangle virtuel pour qu'elle soit toujours. C'est le plus grand et nécessite une manipulation spéciale.

Le code est le suivant :

_getLeftAnchor() {
  let x = this.center.x - this.radius - this.textReact.width,
    y = this.center.y - this.textReact.height / 2,
    diam = this.radius * 2,
    maxH = diam > this.textReact.height ? diam : this.textReact.height; //矩形的高度
  return {
    x,
    y,
    minX: x,
    maxX: this.center.x + this.radius,
    minY: this.center.y - maxH / 2,
    maxY: this.center.y + maxH / 2
  };
}

Et ainsi de suite, décrivant les coordonnées du rectangle virtuel en bas, à gauche et en haut.

Jugez la collision

Jugez si deux rectangles se couvrent et se croisent L'intersection est jugée en fonction du minX, maxX, minY, maxY du. rectangle. Le principe est relativement simple, le code est le suivant :

/**
 * 判断分位是否相交
 * @param {*} target 
 */ 
isAnchorMeet(target) {
  let react = this.getCurrentRect(),
    targetReact = target.getCurrentRect();
  if ((react.minX < targetReact.maxX) && (targetReact.minX < react.maxX) &&
    (react.minY < targetReact.maxY) && (targetReact.minY < react.maxY)) {
    return true;
  }
  return false;
}

Créer un objet de collection de texte virtuel

let labels = pixels.map((val) => {
  let radius = val.pixel.radius + this.style.normal.borderWidth; //圆点半径
  return new Label(val.pixel.x, val.pixel.y, radius, fontSize, byteWidth, val.name);
});
Parcourez récursivement la collection de texte virtuel et déterminez si elle croise d'autres objets. S'il y a une intersection, déplacez la position actuelle du texte jusqu'à ce qu'il n'y ait plus d'intersection. Lorsque vous ne trouvez pas d'emplacement approprié, choisissez de masquer le texte actuel.

Le code est le suivant :

do {
  var meet = false; //本轮是否有相交
  for (let i = 0; i < labels.length; i++) {
    let temp = labels[i];
    for (let j = 0; j < labels.length; j++) {
      if (i != j && temp.show && temp.isAnchorMeet(labels[j])) {
        temp.next();
        meet = true;
        break;
      }
    }
  }
} while (meet);

Peindre le texte

labels.forEach(function (item) {
  if (item.show) { //是否显示
    let pixel = item.getCurrentRect();
    ctx.beginPath();
    ctx.fillText(item.text, pixel.x, pixel.y);
    ctx.fill();
  }
});
L'algorithme d'évitement de texte a été introduit jusqu'à présent, et l'adresse du fichier inMap correspondante est https://github.com/TalkingData/inmap/blob/master/src/worker/helper/Label.js. Je continuerai à partager des informations utiles avec vous à l'avenir. .

Ce qui précède est ce que j'ai compilé pour vous. J'espère que cela vous sera utile à l'avenir.

Articles connexes :

Comment implémenter un en-tête de tableau fixe et une première colonne dans Vue

Comment express+multer implémente la fonction de téléchargement d'image

Natif Comment implémenter un lecteur de musique dans JS

Comment définir les autorisations utilisateur dans VueJS

Comment utiliser le composant ScrollTab de YDUI dans l'applet WeChat

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn