2026年4月1日水曜日

HTML>折れ線グラフ雛形

折れ線グラフ雛形

tableタグで折れ線グラフを実現するもの。
グラフを増やす時は、tableタグ部分コピペする。
グラフの設定は、主にCSS変数を変える事である程度可能。
後は、ソースコードを直接変更する。
jsは、svgのx軸の表示位置を調整・設定、及び、svgとhtmlの座標を合致させるもの。

<style>
  /* グラフtable */
  .ogt-tb {border-collapse: collapse; font-size: small;}
  /* 縦軸ラベル */
  .ogt-tb .ogt-tr {padding: 1px; text-align: center; vertical-align: middle; writing-mode: vertical-rl; }
  /* 縦軸目盛 */
  .ogt-tb .ogt-tm {
    height: var(--ogt-hei);
    border-right: 1px solid black;
    text-align: right;
    vertical-align: top; /* 上端合わせにして目盛の間隔を調整 */
    padding-right: 5px;
  }
  /* グラフ描画エリア */
  .ogt-tb .graph-area {
    position: relative;
    width: calc( var(--ogt-mas) * var(--ogt-komoku) + var(--ogt-ofs) );
    height: var(--ogt-hei);
    background-color: var(--ogt-bco);
    background-image: linear-gradient(gray 1px, transparent 1px);
    background-size: 100% var(--ogt-mem); /* 縦軸補助線 */
    border-bottom: 1px solid black;
    border-right: 1px solid black;
    padding: 0;
  }
  .ogt-tb .graph-area::after {
    background-image: linear-gradient(to right, gray 1px, transparent 1px);
    background-repeat: repeat-x;
    background-size: var(--ogt-mas) 100%; /* 横軸補助線 */
    content: "";
    height: 100%;
    left: var(--ogt-ofs);
    position: absolute;
    top: 0;
    width: 100%;
  }  
  /* SVGの設定 */
  .ogt-tb svg {width:100%; height:100%; display:block;}
  /* 折れ線のスタイル */
  .ogt-tb .line {fill: none; stroke-width: 2;}
  /* 点(プロット)のスタイル */
  .ogt-tb .dot {}
  /* 横軸ラベル */
  .ogt-tb .ogt-yr{text-align: center; padding-top: 5px;}
  /* 横軸目盛り */
  .ogt-tb .ogt-ym{width: calc(var(--ogt-mas) * var(--ogt-komoku) + var(--ogt-ofs));position:relative;height:3em; top:0px;}
  /*横軸ラベル文字のspan*/
  .ogt-tb .ogt-ka{
    position: absolute;
    transform: translateX(-50%); /* 文字の真ん中を基準点にする*/
    text-align: center;
    white-space: nowrap;
    left:calc( var(--ogt-mas) * var(--data-kan) + var(--ogt-ofs) );
  }
  /*文字の上に線を出す*/
  .ogt-tb .ogt-ka::after {
    content: "";
    position: absolute;
    top: -8px;/* 文字の何px上に線を出すか */
    left: 50%;/* 文字の中央から */
    width: 1px;/* 線の太さ */
    height: 10px;/* 線の長さ */
    background: black;/* 線の色gray */
  }
  /*縦書き-spanに加える*/
  .ogt-tb .ogt-ymt{text-align: center; vertical-align: middle; writing-mode: vertical-rl;}
</style>

<table class="ogt-tb" style="--ogt-hei: 300px; --ogt-mem:25%;  --ogt-bco:bisque; --ogt-str:blue; --ogt-kan:6; --ogt-ofs:0px; --ogt-mas:80px; --ogt-komoku:6;" border="0">
  <tbody>
    <tr>
      <!-- 縦軸ラベル -->
      <td class="ogt-tr">縦軸コメント</td>
      <!-- 縦軸目盛 -->
      <td class="ogt-tm">
        <div style="height: var(--ogt-mem);">100</div>
        <div style="height: var(--ogt-mem);">75</div>
        <div style="height: var(--ogt-mem);">50</div>
        <div style="height: var(--ogt-mem);">25</div>
        <div>0</div>
      </td>
      <!-- グラフ本体 (SVG) -->
      <td class="graph-area">
        <svg viewBox="0 0 500 300" preserveAspectRatio="none">
          <!-- 
            points属性の解説: x,y_ の順で指定
            x: 左からの距離 (0〜500)--ogt-mas * --ogt-komoku + --ogt-ofs 毎にjsでとるので記入は適当
            y: 上からの距離 (0〜300) ※0が100%、300が0%に相当
          -->
          <polyline class="line" style="stroke: var(--ogt-str);" points=" 
            0,250 
            1,200 
            2,220 
            3,100 
            4,120 
            5,50
            "/>
          <!--<line x1="20" y1="10" x2="600" y2="280" style="stroke:blue ;stroke-width:1;stroke-dasharray="2 2" />-->
          <!-- 各ポイントに丸を表示する場合 F12→座標が表示されるので手入力 いらなければ削除 -->
          <circle class="dot" cx="0" cy="250" r="4" style="fill: var(--ogt-str);" /><text x="4" y="240">20</text>
          <circle class="dot" cx="1" cy="200" r="4" style="fill: var(--ogt-str);" />
          <circle class="dot" cx="2" cy="220" r="4" style="fill: var(--ogt-str);" />
          <circle class="dot" cx="3" cy="100" r="4" style="fill: var(--ogt-str);" />
          <circle class="dot" cx="4" cy="120" r="4" style="fill: var(--ogt-str);" />
          <circle class="dot" cx="5" cy="50"  r="4" style="fill: var(--ogt-str);" />
        </svg>
      </td>
    </tr>
    <!-- 横軸目盛 数は--ogt-komokuの数値に合わせる-->
    <tr class="ogt-yr">
      <td></td>
      <td></td>
      <td class="ogt-ym">
          <span class="ogt-ka" style="--data-kan:0;"></span>
          <span class="ogt-ka" style="--data-kan:1;">a</span>
          <span class="ogt-ka" style="--data-kan:2;">b</span>
          <span class="ogt-ka" style="--data-kan:3;">c</span>
          <span class="ogt-ka" style="--data-kan:4;">d</span>
          <span class="ogt-ka" style="--data-kan:5;">e</span>
          <br>横軸コメント
      </td>
    </tr>
  </tbody>
</table>

<script>
const ogttbs = document.querySelectorAll('.ogt-tb');

ogttbs.forEach(ogtTb => {
  const style = getComputedStyle(ogtTb);
// CSS変数から値を取得
  const offset = parseFloat(style.getPropertyValue('--ogt-ofs')) || 0;
  const mas = parseFloat(style.getPropertyValue('--ogt-mas')) || 0;
  const komoku = parseFloat(style.getPropertyValue('--ogt-komoku')) || 0;
  const totalWidth = mas * komoku + offset;
// 1. そのテーブル内の SVG の表示範囲を修正
  const svg = ogtTb.querySelector('svg');
  if (svg) {svg.setAttribute('viewBox', `0 0 ${totalWidth} 300`);}
// 2. そのテーブル内の polyline (折れ線) の座標修正
  const lines = ogtTb.querySelectorAll('.line');
  lines.forEach(line => {
    console.log("****");
    const pointsAttr = line.getAttribute('points').trim();
    if (!pointsAttr) return;
    
    const coords = pointsAttr.split(/[\s,]+/).filter(v => v !== "");
    const newPoints = [];
    
    for (let i = 0; i < coords.length; i += 2) {
      const index = i / 2;
      const x = (index * mas) + offset;
      const y = coords[i + 1];
      newPoints.push(`${x},${y}`);
      console.log("x=",x," y=",y);
    }
    line.setAttribute('points', newPoints.join(' '));
  });
// 3. そのテーブル内の circle (点) の座標修正
  const dots = ogtTb.querySelectorAll('.dot');
  dots.forEach((dot, i) => {
    const j = i % komoku; 
    dot.setAttribute('cx', (j * mas) + offset);
  });
});
</script>