Erstellen Sie mit Three.js eine 3D-Wortwolke

2D-Wortwolken werden häufig verwendet. Es ist Zeit für ein Upgrade und verwenden Sie die 3D-Wortwolke!

1. Kugelkoordinaten

Neben dem üblichen kartesischen Koordinatensystem, dem Polarkoordinatensystem, gibt es noch ein weiteres Koordinatensystem, das Kugelkoordinatensystem. Indem man den Koordinatenursprung als Bezugspunkt nimmt, wird eine dreidimensionale Koordinate aus Azimut, Höhe und Entfernung gebildet.

Bild.png

In der Mathe-Bibliothek three.js gibt es eine sphärische Koordinatethreejs.org/docs/#api/z…

Spherical( radius : Float, phi : Float, theta : Float )

  • radius: Radius oder vom Punkt zum Ursprung (euklidischer Abstand, also geradliniger Abstand). Der Standardwert ist 1,0. Umfang[0,无穷)
  • phi: Polarwinkel (im Bogenmaß) von der y-Achse (oben). Der Standardwert ist 0. Umfang[0,PI]
  • theta: Äquatorialwinkel (Azimut) um die y-Achse (oben) im Bogenmaß. Der Standardwert ist 0. Umfang[0,2*PI]

Der Polarwinkel (phi) ist der Winkel zwischen der positiven y-Achse und der negativen y-Achse. Der Äquatorwinkel (Azimut) (Theta) beginnt bei positivem z und kreist um ihn herum.

2. Lineare Interpolationsfunktion

Vom Startwert bis zum Endwert, [0,1]dem zugeordneten Intervall, [0,1]kann der Wert einer linearen Karte zwischen dem Startwert und dem Endwert durch den Wert des Bereichs ermittelt werden. Normalerweise schreiben wir so manuell

原始值val范围min,max
新值value范围newMin,newMax
value=newMin+ ((val-min)/(max-min))*(newMax-newMin)

In den Mathe-Tools von three.jshttps://threejs.org/docs/?q=Math#api/zh/math/MathUtils.lerp

lerp(x:Float,y:Float,t:Float):Float

  • x: Startwert.
  • y: Endwert.
  • t: [0,1]Interpolationsfaktor im geschlossenen Intervall.

Gibt einen Wert zurück, der linear aus zwei bekannten Punkten basierend auf dem angegebenen Intervall interpoliert wird – t=0 gibt x zurück und t=1 gibt y zurück.

verwenden

value=lerp(newMin,newMax,(val-min)/(max-min))

3. Zeichnen Sie Text

  • Leinwandtext
/**
 *canvas文本
 * @param {String} text 文本字符串
 * @param {Number} fontSize 字体大小
 * @param {String} color 颜色
 * @returns
 */
export function getCanvasText(text, fontSize, color, bg) {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  ctx.font = fontSize + 'px Arial';
  ctx.fillStyle = color;
  let padding = 5;
  //测量文本大小,并设置canvas宽高预留padding
  canvas.width = ctx.measureText(text + '').width + padding * 2;
  canvas.height = fontSize * 1.2 + padding * 2;
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  ctx.fillStyle = bg;

  ctx.rect(0, 0, canvas.width, canvas.height);
  ctx.fill();

  ctx.font = fontSize + 'px Arial';
  ctx.fillStyle = color;
  ctx.fillText(text, padding, fontSize + padding * 0.5);
  return canvas;
}
  • Textraster
/***
 * 文本网格
 * @param {String} text 文本字符串
 * @param {Number} fontSize 字体大小
 * @param {String} color 颜色
 */
export function getTextMesh(THREE, text, fontSize, color) {  
  const canvas = getCanvasText(text, fontSize * 10, color, 'rgba(0,0,0,0)');
  const map = new THREE.CanvasTexture(canvas);
  map.wrapS = THREE.RepeatWrapping;
  map.wrapT = THREE.RepeatWrapping;
  const material = new THREE.MeshBasicMaterial({
    map: map,
    transparent: true,
    side: THREE.DoubleSide
  });
 
  const geometry = new THREE.PlaneGeometry(canvas.width * 0.1, canvas.height * 0.1);
  const mesh = new THREE.Mesh(geometry, material);
  return { material, geometry, canvas, mesh };
}

Hinweis: Die Leinwandtextur muss vergrößert werden, da sie sonst bei Nahaufnahmen unscharf wird. Um die Größe beizubehalten, kann bei der Erstellung eines zweidimensionalen Flachbildschirms das entsprechende Verkleinerungsverhältnis reduziert werden

4. Legen Sie los

  • Berechnen Sie die Textkoordinaten und teilen Sie die Koordinatenpunkte auf der Kugeloberfläche that.data.lengthin
const vector = new THREE.Vector3();

const phi = Math.acos(THREE.MathUtils.lerp(-1, 1, idx / (that.data.length - 1)));

const theta = Math.sqrt(that.data.length * Math.PI) * phi;

vector.setFromSphericalCoords(that.radius, phi, theta);

Da der Wertebereich der Arkuskosinusfunktion genau ist [0,PI]und der Domänenbereich ist [-1,1], können wir lerp(-1,1,t)den entsprechenden Polarwinkel durch die lineare Interpolationsfunktion erhalten, und hier wird der Datenindex idx verwendet

setFromSphericalCoordsKonvertieren Sie sphärische Koordinaten in dreidimensionale Koordinaten

//文本大小线性插值,根据数据值大小做映射
 let s = THREE.MathUtils.lerp(
                that.minFontSize,
                that.maxFontSize,
                (item.value - min) / size
              );

              let { mesh, geometry } = getTextMesh(THREE, text, s, that.color);

              mesh.name = 'text' + idx;
              
              mesh.position.set(vector.x, vector.y, vector.z);             

              textGroup.add(mesh);

20230806_155258.gif

  • Stellen Sie die Textkoordinaten auf kartesische dreidimensionale Koordinaten ein, die aus sphärischen Koordinaten konvertiert wurden. Wir werden feststellen, dass der Text vollständig vertikal ist. Obwohl er sich auf den Koordinaten befindet, die einer Kugel entsprechen, bildet er keine freundliche Kugel. Der Effekt, den wir benötigen, besteht darin, die Schriftart entlang der sphärischen Oberfläche zu platzieren
 geometry.lookAt(vector);
geometry.translate(vector.x, vector.y, vector.z);

Betrachten Sie die zweidimensionale Ebenengeometrie zum Koordinatenpunkt und bewegen Sie sich dann entsprechend dem Koordinatenpunkt. Sie erhalten eine Textkugel

20230806_160049.gif

  • Sie können einen Nebel hinzufügen, um die Schichtung zu verstärken
this.scene.fog = new THREE.FogExp2(new THREE.Color('#000000'), 0.003);

20230806_160850.gif

  • Die 3D-Wortwolke sieht gut aus, wenn viele Daten vorhanden sind, aber sie sieht leer aus, wenn nur wenige Daten vorhanden sind. Zu diesem Zeitpunkt können Sie einen Kugelrahmen hinzufügen
  const g = new THREE.IcosahedronGeometry(that.radius * 2, 2);
            const m = new THREE.MeshBasicMaterial({
              color: that.color,
              transparent: true,
              opacity: 0.2,
              wireframe: true
            });
            const mm = new THREE.Mesh(g, m);
            this.objGroup.add(mm);

20230806_160442.gif

  • Fügen Sie eine automatische Drehung hinzu
   animateAction() {
          if (this.objGroup) {
            if (this.objGroup.rotation.y >= Math.PI * 2) {
              this.objGroup.rotation.y = 0;
            } else {
              this.objGroup.rotation.y += 0.001;
            }
          }
        }

20230806_163540.gif

  • Fügen Sie eine zufällige Farbe hinzu
   const color = `rgb(${Math.random() * 255},${Math.random() * 255},${
                Math.random() * 255
              })`;
              
              let { mesh, geometry } = getTextMesh(THREE, text, s, color);

20230806_164601.gif

GitHub

https://github.com/xiaolidan00/my-three

Supongo que te gusta

Origin juejin.im/post/7263878008615944248
Recomendado
Clasificación