Skip to content

Konva

js
function createWordCloud_0(stage, cw, ch, data, showDetailPopover) {
  currentTemplate = 0;

  words = data;
  wordsTargetPos = new Array(words.length).fill(0);
  setWordsPosition_0();

  containerW = cw;
  containerH = ch;

  const layer = new Konva.Layer();
  for (let i = 0; i < words.length; i++) {
    const text = words[i].name;
    const wordW = 38 + text.length * fontsize;

    const wordGroup = new Konva.Group({
      x: wordsTargetPos[i].cx,
      y: wordsTargetPos[i].cy,
      scale: {
        x: 0.4,
        y: 0.4,
      },
      opacity: 0,
    });

    const wordRect = new Konva.Rect({
      x: 0,
      y: 0,
      width: wordW,
      height: 36,
      fill: "#FFF",
      opacity: 0.76,
    });
    const prefixRect = new Konva.Rect({
      x: 12,
      y: 15,
      width: 6,
      height: 6,
      fill: "#FEA41D",
    });
    const wordText = new Konva.Text({
      x: 26,
      y: 12,
      text,
      fontSize: 14,
      fontFamily: "PingFang SC",
      fill: "#1135F1",
    });

    wordGroup.add(wordRect);
    wordGroup.add(prefixRect);
    wordGroup.add(wordText);
    layer.add(wordGroup);

    const period = 10000;
    const halfPeriod = 5000;
    const anim = new Konva.Animation(function ({ time, timeDiff, frameRate }) {
      if (currentTemplate !== 0 || time < wordsTargetPos[i].delay) return;

      const t = (time - wordsTargetPos[i].delay) % period;
      if (t <= halfPeriod) {
        // 50%的时间用来运动
        const ratio = t / halfPeriod;

        let scale =
          ratio * wordsTargetPos[i].scale < 0.2
            ? 0.2
            : ratio * wordsTargetPos[i].scale;

        wordGroup.scale({
          x: scale,
          y: scale,
        });
        wordGroup.position({
          x:
            wordsTargetPos[i].cx +
            ratio * wordsTargetPos[i].x +
            wordRect.width() / 2,
          y:
            wordsTargetPos[i].cy +
            ratio * wordsTargetPos[i].y +
            wordRect.height() / 2,
        });
        wordGroup.opacity(1);
      } else if (t >= period * 0.9) {
        // 最后一秒用来渐变隐藏
        wordGroup.opacity((period - t) / (period - period * 0.9));
      }
    }, layer);
    anim.start();

    wordGroup.on("mouseenter", function (e) {
      stage.container().style.cursor = "pointer";
      if (store.theme === "default") {
        wordRect.opacity(1);
      } else {
        wordRect.opacity(0.5);
      }
      anim.stop();
      wordGroup.zIndex(words.length - 1);
    });

    wordGroup.on("mouseleave", function (e) {
      stage.container().style.cursor = "default";
      if (store.theme === "default") {
        wordRect.opacity(0.76);
      } else {
        wordRect.opacity(0.2);
      }

      if (selectedWord.word !== words[i]) {
        anim.start();
      }
    });

    wordGroup.on("pointerclick", function (e) {
      e.cancelBubble = true;
      wordGroup.zIndex(words.length - 1);

      let visible = !selectedWord.word;

      if (!selectedWord.word) {
        selectedWord.word = words[i];
        anim.stop();
        selectedWord.animation = anim;
        visible = true;
      } else if (selectedWord.word == words[i]) {
        selectedWord.word = null;
        selectedWord.animation.start();
        visible = false;
      } else {
        selectedWord.animation.start();
        selectedWord.word = words[i];
        anim.stop();
        selectedWord.animation = anim;
        visible = true;
      }


      showDetailPopover(e.evt, visible, wordW);
    });

    wordsGroup[i] = {
      wordText,
      wordRect,
    };
    wordsAnim[i] = anim;
  }

  stage.add(layer);
}

function updateWordCloud_0(cw, ch) {
  containerW = cw;
  containerH = ch;

  setWordsPosition_0();
}

function setWordsPosition_0() {
  let d = [1, -1];
  let w, h;
  let scaleLimit;

  if (store.mobile) {
    scaleLimit = {
      min: 0.4,
      max: 1.2,
    };
    w = (containerW - 40) / 2;
    h = (containerH - 40) / 2;
  } else {
    scaleLimit = {
      min: 0.6,
      max: 1.4,
    };

    w = (containerW - 100) / 2;
    h = (containerH - 60) / 2;
  }

  for (let i = 0; i < words.length; i++) {
    let ts = Math.min(
      (Math.random() + scaleLimit.min).toFixed(2),
      scaleLimit.max
    ); //  target scale

    let th = d[Math.round(Math.random())]; // x/y轴上的移动方向 + -

    let x = Math.ceil(Math.random() * w); // x 水平移动距离
    let x1 = x;
    x1 = th === 1 && x + 200 > w ? x - 200 : x;
    let tx = th * x1; // target x

    let y = Math.ceil(Math.random() * h).toFixed(2); // 垂直移动距离
    let y1 = y - 36 * ts > h ? h : y;
    let ty = d[Math.round(Math.random())] * y1 - 10; // target y

    let td = (Math.random() * 10).toFixed(2) * 1000; // delay

    let text = words[i].name;
    let wordW = 38 + text.length * fontsize;
    let cx = containerW / 2 - wordW / 2;
    let cy = containerH / 2 - 18;

    wordsTargetPos[i] = {
      scale: ts,
      x: tx,
      y: ty,
      delay: td,
      cx,
      cy,
    };
  }
}

苏ICP备2025160170号-1 | 前端进化之路 | Released under the MIT License.