文章内に折れ線グラフを挿入する

Ads

Result

非依存のvanillaなコードで動作します

データを元にグラフをcanvasで生成し、挿入します。データは配列で管理します

javascript

/**
 * データとclass
 */

let stonks = document.querySelectorAll(".stonk");

data = [
  [
    420,
    700,
    500,
    480,
    460,
    490,
    390,
    420,
    550,
    340,
    320,
    240,
    180,
    160,
    200,
    40,
    0
  ],
  [1, 3, 2, 3, 1, 2, 3],
  [13, 30, 12, 3, 51, 20, 31]
];

/*グラフのスタイル*/
const options = {
  lineWidth: 2,
  color: "#E3342F"
};

/**
 * Class
 */

class Stonk {
  constructor(wrapper, data, settings = {}) {
    const defaults = {
      width: 80,
      color: "#000000",
      lineWidth: 1
    };

    this.settings = Object.assign(defaults, settings);
    this.wrapper = wrapper;
    this.data = data;
    this.normalData = [];
    this.canvas = null;
    this.ctx = null;
    this.dimes = { w: 0, h: 0 };
  }

  draw() {
    this._buildCanvas();
    this._normalizeData(this.data);
    this._drawData();
  }

  _drawData() {
    let ctx = this.ctx;
    let { w, h } = this.dimes;
    w = w - this.settings.lineWidth / 2;
    h = h - this.settings.lineWidth / 2;
    let nd = this.normalData;
    let step = w / (this.data.length - 1);
    let tick = this.settings.lineWidth / 2;

    ctx.strokeStyle = this.settings.color;
    ctx.lineWidth = this.settings.lineWidth;

    ctx.beginPath();

    ctx.moveTo(tick, h - nd[0]);

    for (var i = 1; i <= nd.length - 1; i++) {
      tick += step;
      ctx.lineTo(tick, h - nd[i]);
    }

    ctx.stroke();
  }

  _buildCanvas() {
    let canvas = document.createElement("canvas");
    let absoluteDimes;

// canvasのグラフをinlineにして挿入する
    this.wrapper.style.cssText += `
      position: relative;
      display: inline-block;
      line-height: 1;
      height: 0.9em;
    `;

    // 高さを一時的に設定して、境界を計算できるようにする
    canvas.style.height = "100%";
    canvas.style.width = `${this.settings.width}px`;

    // ドキュメントに追加して、境界を返す
    this.canvas = canvas;
    this.ctx = this.canvas.getContext("2d");
    this.wrapper.appendChild(this.canvas);
    absoluteDimes = this.canvas.getBoundingClientRect();

    const { width: w, height: h } = absoluteDimes;
    this.dimes = { w, h: Math.floor(h) };

    // 属性を設定
    this.canvas.setAttribute("height", this.dimes.h);
    this.canvas.setAttribute("width", this.dimes.w);

    // 属性を削除する
    this.canvas.removeAttribute("style");
  }

  // ユーティリティ

  _normalizeData(array) {
    let min = Math.min(...array);
    let max = Math.max(...array);

    this.data.forEach((v) => {
      let percentage = this._scaleBetween(v, 0, 100, min, max);
      let h = (this.dimes.h - this.settings.lineWidth) * (percentage / 100);
      this.normalData.push(h);
    });
  }

  _scaleBetween(unscaledNum, minAllowed, maxAllowed, min, max) {
    return (
      ((maxAllowed - minAllowed) * (unscaledNum - min)) / (max - min) +
      minAllowed
    );
  }
}

/**
 * Mount
 */

stonks.forEach((s, idx) => {
  let stonk = new Stonk(s, data[idx], options).draw();
});

html

<p>文章内の任意の場所に<span class="stonk"></span>このように折れ線グラフを挿入する事が出来ます。折れ線グラフのデータは多次元配列で管理され、<span class="stonk"></span>指定のclassを付与した要素の順に割り当てられます。</p>

via

Stonks – Sparklines Renderer