メインコンテンツへスキップ

🎓 Splunk図形作成コード 一行ずつ完全解説~新人エンジニア向け・全コード徹底解説~



    📚 この記事について

    前提知識: HTML/CSS/JavaScriptの基礎がわかる程度 目標: Splunkダッシュボードのコードを完全に理解する
    🎨 Splunkクラシックダッシュボード 図形作成チートシート

    ~ステータス連動で色が変わる!四角・丸・棒・三角を自由自在に配置~


    📚 この記事で学べること

    項目 内容 対象者 Splunk初心者・新人エンジニア 目標 HTML/CSS/SPLで図形を作成し、データに応じて色を変える 所要時間 約30分


    🏗️ 全体構成イメージ

    ┌─────────────────────────────────────────────────────┐
    │  Splunk クラシックダッシュボード                      │
    │  ┌─────────────────────────────────────────────┐   │
    │  │  HTML Panel(図形を描画するエリア)           │   │
    │  │                                              │   │
    │  │   ■ 四角    ● 丸    ▬ 棒    ▼ 三角        │   │
    │  │   (緑)     (黄)    (赤)    (青)            │   │
    │  │                                              │   │
    │  │  ← SPLで取得したステータスに応じて色が変化   │   │
    │  └─────────────────────────────────────────────┘   │
    │                                                     │
    │  [データ取得] → [ステータス判定] → [色の反映]      │
    └─────────────────────────────────────────────────────┘
    

    📂 Part 1: サンプルデータの準備

    1-1. テスト用インデックスとデータ作成

    まず、動作確認用のサンプルデータを作成します。

    | makeresults count=4
    | streamstats count as id
    | eval device_name = case(
        id==1, "サーバーA",
        id==2, "サーバーB", 
        id==3, "ネットワーク機器C",
        id==4, "データベースD"
      )
    | eval status = case(
        id==1, "正常",
        id==2, "警告",
        id==3, "異常",
        id==4, "停止"
      )
    | eval status_code = case(
        status=="正常", 0,
        status=="警告", 1,
        status=="異常", 2,
        status=="停止", 3
      )
    | table device_name, status, status_code
    

    🔍 SPL解説(一行ずつ)

    | makeresults count=4
    

    <!-- ▲ 4行の空データを生成する。テスト用データ作成の起点 -->

    | streamstats count as id
    

    <!-- ▲ 各行に連番(1,2,3,4)を「id」という名前で付与 -->

    | eval device_name = case(
        id==1, "サーバーA",
        id==2, "サーバーB", 
        id==3, "ネットワーク機器C",
        id==4, "データベースD"
      )
    

    <!-- ▲ idの値に応じて「device_name」フィールドに機器名を設定 --> <!-- ▲ case関数: 条件, 値, 条件, 値... の形式で条件分岐 -->

    | eval status = case(
        status=="正常", 0,
        status=="警告", 1,
        status=="異常", 2,
        status=="停止", 3
      )
    

    <!-- ▲ ステータス文字列に対応する数値コードを設定 --> <!-- ▲ 後でJavaScriptで色を判定する際に使用 -->

    | table device_name, status, status_code
    

    <!-- ▲ 最終的に表示するフィールドを指定 -->

    📊 出力結果イメージ

    device_name status status_code サーバーA 正常 0 サーバーB 警告 1 ネットワーク機器C 異常 2 データベースD 停止 3


    📂 Part 2: ダッシュボードXML基本構造

    2-1. ダッシュボードの骨格

    <dashboard>
      <!-- ダッシュボードのルート要素 -->
      
      <label>図形サンプルダッシュボード</label>
      <!-- ダッシュボード名(画面上部に表示) -->
      
      <row>
        <!-- 行(横並びのコンテナ) -->
        
        <panel>
          <!-- パネル(各コンテンツを格納する箱) -->
          
          <html>
            <!-- HTMLパネル(自由にHTML/CSS/JSを記述可能) -->
          </html>
          
        </panel>
      </row>
    </dashboard>
    

    📂 Part 3: 図形の作成(HTML/CSS)

    3-1. 🟦 四角形(Rectangle)

    <html>
      <style>
        /* ===== 四角形のスタイル定義 ===== */
        .shape-rectangle {
          /* 幅を100ピクセルに設定 */
          width: 100px;
          
          /* 高さを60ピクセルに設定 */
          height: 60px;
          
          /* 背景色(初期値:グレー) */
          background-color: #808080 ;
          
          /* 角を少し丸める(0pxで完全な四角) */
          border-radius: 5px;
          
          /* 枠線:1ピクセルの黒い実線 */
          border: 1px solid #333 ;
          
          /* テキストを中央揃え */
          display: flex;
          justify-content: center;  /* 横方向中央 */
          align-items: center;      /* 縦方向中央 */
          
          /* 文字色を白に */
          color: white;
          
          /* 文字サイズ */
          font-size: 12px;
          
          /* 太字 */
          font-weight: bold;
        }
      </style>
      
      <div class="shape-rectangle">
        四角形
      </div>
    </html>
    

    🔍 CSS解説ポイント

    プロパティ 役割 よく使う値 width / height サイズ px, %, em background-color 背景色 カラーコード, 色名 border-radius 角の丸み 0px=角張り, 50%=丸 display: flex 中央揃えの準備 -


    3-2. 🔴 丸(Circle)

    <html>
      <style>
        /* ===== 丸のスタイル定義 ===== */
        .shape-circle {
          /* 幅と高さを同じにする(正方形の土台) */
          width: 80px;
          height: 80px;
          
          /* 背景色(初期値:グレー) */
          background-color: #808080 ;
          
          /* ★重要★ border-radiusを50%にすると丸になる */
          border-radius: 50%;
          
          /* 枠線 */
          border: 2px solid #333 ;
          
          /* テキスト中央揃え */
          display: flex;
          justify-content: center;
          align-items: center;
          
          /* 文字スタイル */
          color: white;
          font-size: 12px;
          font-weight: bold;
        }
      </style>
      
      <div class="shape-circle">
        丸
      </div>
    </html>
    

    💡 丸を作るコツ

    ┌──────────────────────────────────────┐
    │  border-radius: 50%  →  正円になる  │
    │                                      │
    │  ★条件:width と height が同じ値    │
    │                                      │
    │   width: 80px  ─┬─→  ●              │
    │   height: 80px ─┘                   │
    └──────────────────────────────────────┘
    

    3-3. ▬ 棒(Bar / Rectangle)

    <html>
      <style>
        /* ===== 棒のスタイル定義 ===== */
        .shape-bar {
          /* 横長の形状:幅 > 高さ */
          width: 150px;
          height: 30px;
          
          /* 背景色 */
          background-color: #808080 ;
          
          /* 少しだけ角を丸める */
          border-radius: 3px;
          
          /* 枠線 */
          border: 1px solid #333 ;
          
          /* テキスト中央揃え */
          display: flex;
          justify-content: center;
          align-items: center;
          
          /* 文字スタイル */
          color: white;
          font-size: 11px;
          font-weight: bold;
        }
      </style>
      
      <div class="shape-bar">
        棒(ステータスバー)
      </div>
    </html>
    

    3-4. 🔻 三角形(Triangle)▽

    <html>
      <style>
        /* ===== 三角形のスタイル定義 ===== */
        .shape-triangle {
          /* ★重要★ 三角形はサイズを0にしてborderで形を作る */
          width: 0;
          height: 0;
          
          /* 左右の辺:透明 */
          border-left: 40px solid transparent;
          border-right: 40px solid transparent;
          
          /* 上辺:色を付ける(下向き三角 ▼) */
          border-top: 60px solid #808080 ;
          
          /* 下向き三角の底辺は不要なのでなし */
          /* border-bottom: なし */
        }
        
        /* ===== 上向き三角形 △ ===== */
        .shape-triangle-up {
          width: 0;
          height: 0;
          
          border-left: 40px solid transparent;
          border-right: 40px solid transparent;
          
          /* 下辺に色を付ける(上向き三角 △) */
          border-bottom: 60px solid #808080 ;
        }
      </style>
      
      <!-- 下向き三角 ▼ -->
      <div class="shape-triangle"></div>
      
      <!-- 上向き三角 △ -->
      <div class="shape-triangle-up"></div>
    </html>
    

    💡 三角形の仕組み(図解)

    【CSS三角形の原理】
    
      通常のborder:           三角形の作り方:
      ┌─────────────┐         
      │ ╲         ╱ │         border-top: 色付き
      │   ╲     ╱   │              ▼
      │     ╲ ╱     │         ┌─────────┐
      │     ╱ ╲     │         │╲       ╱│
      │   ╱     ╲   │         │  ╲   ╱  │
      │ ╱         ╲ │         │    ▼    │
      └─────────────┘         └─────────┘
                              ↑         ↑
                           transparent transparent
                           (左辺)      (右辺)
    

    📂 Part 4: ステータスに応じた色変更(JavaScript連携)

    4-1. 完全版コード(SPL + HTML + CSS + JavaScript)

    <dashboard>
      <label>ステータス連動図形ダッシュボード</label>
      
      <!-- ===== データ取得用サーチ ===== -->
      <search id="status_search">
        <query>
          | makeresults count=4
          | streamstats count as id
          | eval device_name = case(
              id==1, "サーバーA",
              id==2, "サーバーB", 
              id==3, "ネットワーク機器C",
              id==4, "データベースD"
            )
          | eval status = case(
              id==1, "正常",
              id==2, "警告",
              id==3, "異常",
              id==4, "停止"
            )
          | eval status_code = case(
              status=="正常", 0,
              status=="警告", 1,
              status=="異常", 2,
              status=="停止", 3
            )
          | table device_name, status, status_code
        </query>
        <earliest>-24h@h</earliest>
        <latest>now</latest>
      </search>
      
      <row>
        <panel>
          <title>ステータス連動図形</title>
          <html>
            <style>
              /* ===== コンテナ(図形を並べる箱) ===== */
              .shapes-container {
                /* 横並びにする */
                display: flex;
                
                /* 図形間の余白 */
                gap: 20px;
                
                /* 内側の余白 */
                padding: 20px;
                
                /* 折り返しを許可 */
                flex-wrap: wrap;
              }
              
              /* ===== 各図形の共通スタイル ===== */
              .shape-item {
                /* 縦並びにする(図形 + ラベル) */
                display: flex;
                flex-direction: column;
                
                /* 中央揃え */
                align-items: center;
                
                /* 図形間の余白 */
                gap: 8px;
              }
              
              /* ===== 四角形 ===== */
              .rectangle {
                width: 100px;
                height: 60px;
                background-color: #808080 ;
                border-radius: 5px;
                border: 2px solid #333 ;
                display: flex;
                justify-content: center;
                align-items: center;
                color: white;
                font-weight: bold;
                font-size: 14px;
                
                /* アニメーション(色が滑らかに変化) */
                transition: background-color 0.3s ease;
              }
              
              /* ===== 丸 ===== */
              .circle {
                width: 70px;
                height: 70px;
                background-color: #808080 ;
                border-radius: 50%;
                border: 2px solid #333 ;
                display: flex;
                justify-content: center;
                align-items: center;
                color: white;
                font-weight: bold;
                font-size: 12px;
                transition: background-color 0.3s ease;
              }
              
              /* ===== 棒 ===== */
              .bar {
                width: 120px;
                height: 25px;
                background-color: #808080 ;
                border-radius: 3px;
                border: 1px solid #333 ;
                display: flex;
                justify-content: center;
                align-items: center;
                color: white;
                font-weight: bold;
                font-size: 11px;
                transition: background-color 0.3s ease;
              }
              
              /* ===== 三角形(下向き)===== */
              .triangle {
                width: 0;
                height: 0;
                border-left: 35px solid transparent;
                border-right: 35px solid transparent;
                border-top: 50px solid #808080 ;
                transition: border-top-color 0.3s ease;
              }
              
              /* ===== ラベル(機器名) ===== */
              .device-label {
                font-size: 12px;
                color: #333 ;
                font-weight: bold;
              }
              
              /* ===== ステータスラベル ===== */
              .status-label {
                font-size: 11px;
                color: #666 ;
              }
              
              /* ===== 色の定義(ステータス別) ===== */
              .status-normal { background-color: #28a745 ; }  /* 緑:正常 */
              .status-warning { background-color: #ffc107 ; } /* 黄:警告 */
              .status-error { background-color: #dc3545 ; }   /* 赤:異常 */
              .status-stop { background-color: #6c757d ; }    /* グレー:停止 */
              
              /* 三角形用(border-topで色を指定) */
              .triangle.status-normal { border-top-color: #28a745 ; }
              .triangle.status-warning { border-top-color: #ffc107 ; }
              .triangle.status-error { border-top-color: #dc3545 ; }
              .triangle.status-stop { border-top-color: #6c757d ; }
            </style>
            
            <!-- 図形を配置するコンテナ -->
            <div class="shapes-container" id="shapesContainer">
              <!-- JavaScriptで動的に生成される -->
            </div>
            
            <script>
              // ===== Splunkのデータを取得してUIに反映 =====
              require([
                'splunkjs/mvc',
                'splunkjs/mvc/searchmanager',
                'splunkjs/mvc/simplexml/ready!'
              ], function(mvc) {
                
                // サーチマネージャーを取得
                // "status_search" は <search id="status_search"> と対応
                var searchManager = mvc.Components.get("status_search");
                
                // サーチ結果を取得
                var results = searchManager.data("results");
                
                // データが変更されたら実行
                results.on("data", function() {
                  
                  // 結果が存在するかチェック
                  if (results.hasData()) {
                    
                    // 結果をJSON形式で取得
                    var rows = results.data().rows;
                    var fields = results.data().fields;
                    
                    // コンテナを取得
                    var container = document.getElementById('shapesContainer');
                    
                    // コンテナを空にする(再描画のため)
                    container.innerHTML = '';
                    
                    // 各行のデータをループ処理
                    rows.forEach(function(row, index) {
                      
                      // フィールド名からインデックスを取得
                      var deviceIndex = fields.indexOf('device_name');
                      var statusIndex = fields.indexOf('status');
                      var codeIndex = fields.indexOf('status_code');
                      
                      // 値を取得
                      var deviceName = row[deviceIndex];
                      var status = row[statusIndex];
                      var statusCode = parseInt(row[codeIndex]);
                      
                      // ステータスコードに応じたCSSクラスを決定
                      var statusClass = '';
                      switch(statusCode) {
                        case 0: statusClass = 'status-normal'; break;   // 正常
                        case 1: statusClass = 'status-warning'; break;  // 警告
                        case 2: statusClass = 'status-error'; break;    // 異常
                        case 3: statusClass = 'status-stop'; break;     // 停止
                        default: statusClass = '';
                      }
                      
                      // 図形の種類を決定(例:インデックスで振り分け)
                      var shapeTypes = ['rectangle', 'circle', 'bar', 'triangle'];
                      var shapeType = shapeTypes[index % shapeTypes.length];
                      
                      // 図形のHTMLを生成
                      var shapeHtml = '';
                      
                      if (shapeType === 'rectangle') {
                        shapeHtml = '<div class="rectangle ' + statusClass + '">' + status + '</div>';
                      } else if (shapeType === 'circle') {
                        shapeHtml = '<div class="circle ' + statusClass + '">' + status + '</div>';
                      } else if (shapeType === 'bar') {
                        shapeHtml = '<div class="bar ' + statusClass + '">' + status + '</div>';
                      } else if (shapeType === 'triangle') {
                        shapeHtml = '<div class="triangle ' + statusClass + '"></div>';
                      }
                      
                      // 図形アイテム全体のHTMLを生成
                      var itemHtml = 
                        '<div class="shape-item">' +
                          shapeHtml +
                          '<div class="device-label">' + deviceName + '</div>' +
                          '<div class="status-label">' + status + '</div>' +
                        '</div>';
                      
                      // コンテナに追加
                      container.innerHTML += itemHtml;
                    });
                  }
                });
              });
            </script>
          </html>
        </panel>
      </row>
    </dashboard>
    

    📂 Part 5: JavaScript解説(一行ずつ)

    5-1. Splunk連携の基本構造

    require([
      'splunkjs/mvc',                    // SplunkのMVCフレームワーク
      'splunkjs/mvc/searchmanager',      // サーチ管理
      'splunkjs/mvc/simplexml/ready!'    // 準備完了を待つ
    ], function(mvc) {
      // この中にコードを書く
    });
    

    🔍 解説

    コード 意味 require([...], function) 必要なモジュールを読み込んでから実行 splunkjs/mvc SplunkのUI操作に必要 simplexml/ready! ダッシュボードの準備完了を待つ


    5-2. サーチ結果の取得

    // サーチマネージャーを取得
    var searchManager = mvc.Components.get("status_search");
    // └─ "status_search" は XMLの <search id="status_search"> と対応
    
    // サーチ結果を取得
    var results = searchManager.data("results");
    // └─ "results" は完了した結果を取得
    // └─ 他に "preview"(途中結果)もある
    

    5-3. データ変更時の処理

    results.on("data", function() {
      // データが更新されたら実行される
      
      if (results.hasData()) {
        // 結果がある場合のみ処理
        
        var rows = results.data().rows;     // 行データ(2次元配列)
        var fields = results.data().fields; // フィールド名の配列
        
        // 例: rows = [["サーバーA", "正常", "0"], ["サーバーB", "警告", "1"], ...]
        // 例: fields = ["device_name", "status", "status_code"]
      }
    });
    

    5-4. ステータスに応じた色クラスの決定

    // ステータスコードに応じたCSSクラスを決定
    var statusClass = '';
    
    switch(statusCode) {
      case 0:                           // status_code が 0 の場合
        statusClass = 'status-normal';  // → 緑色(正常)
        break;
        
      case 1:                           // status_code が 1 の場合
        statusClass = 'status-warning'; // → 黄色(警告)
        break;
        
      case 2:                           // status_code が 2 の場合
        statusClass = 'status-error';   // → 赤色(異常)
        break;
        
      case 3:                           // status_code が 3 の場合
        statusClass = 'status-stop';    // → グレー(停止)
        break;
        
      default:                          // それ以外
        statusClass = '';               // → デフォルト色
    }
    

    📂 Part 6: 図形の自由配置(CSS Grid / Flexbox)

    6-1. Flexboxで横並び

    .shapes-container {
      display: flex;        /* 横並びにする */
      flex-wrap: wrap;      /* 折り返しを許可 */
      gap: 20px;            /* 図形間の余白 */
      justify-content: flex-start; /* 左寄せ */
    }
    

    6-2. CSS Gridで自由配置

    .shapes-container {
      display: grid;
      
      /* 3列のグリッド */
      grid-template-columns: repeat(3, 1fr);
      
      /* 行と列の余白 */
      gap: 20px;
      
      /* パディング */
      padding: 20px;
    }
    

    6-3. 絶対位置指定(完全自由配置)

    .shapes-container {
      position: relative;   /* 基準点を設定 */
      width: 100%;
      height: 400px;
    }
    
    .shape-item {
      position: absolute;   /* 絶対位置指定 */
    }
    
    /* 個別の位置指定 */
    .shape-item:nth-child(1) { top: 20px; left: 50px; }
    .shape-item:nth-child(2) { top: 100px; left: 200px; }
    .shape-item:nth-child(3) { top: 50px; left: 350px; }
    .shape-item:nth-child(4) { top: 150px; left: 100px; }
    

    📂 Part 7: 実用カラーパレット

    7-1. ステータス別推奨カラー

    ステータス カラーコード 色名 用途 正常 #28a745 緑 問題なし 警告 #ffc107 黄 注意が必要 異常 #dc3545 赤 即時対応 停止 #6c757d グレー 稼働停止 情報 #17a2b8 水色 参考情報 不明 #343a40 濃灰 状態不明

    7-2. CSSクラス定義

    /* ===== ステータス別の色定義 ===== */
    
    /* 通常の図形用(background-color) */
    .status-normal  { background-color: #28a745  !important; }
    .status-warning { background-color: #ffc107  !important; color: #333  !important; }
    .status-error   { background-color: #dc3545  !important; }
    .status-stop    { background-color: #6c757d  !important; }
    .status-info    { background-color: #17a2b8  !important; }
    .status-unknown { background-color: #343a40  !important; }
    
    /* 三角形用(border-top-color) */
    .triangle.status-normal  { border-top-color: #28a745  !important; }
    .triangle.status-warning { border-top-color: #ffc107  !important; }
    .triangle.status-error   { border-top-color: #dc3545  !important; }
    .triangle.status-stop    { border-top-color: #6c757d  !important; }
    .triangle.status-info    { border-top-color: #17a2b8  !important; }
    .triangle.status-unknown { border-top-color: #343a40  !important; }
    

    📂 Part 8: よくあるエラーと対処法

    8-1. 図形が表示されない

    原因 対処法 サーチIDの不一致 <search id="xxx"> と mvc.Components.get("xxx") を確認 JavaScriptエラー ブラウザのF12 → Console でエラー確認 CSSが効いていない クラス名のスペルミスを確認

    8-2. 色が変わらない

    原因 対処法 statusClassが空 console.log(statusCode) でデバッグ CSSの優先度 !important を追加 データ型の違い parseInt() で数値に変換

    8-3. デバッグ用コード

    // コンソールに出力(F12で確認)
    console.log("=== デバッグ情報 ===");
    console.log("rows:", rows);
    console.log("fields:", fields);
    console.log("deviceName:", deviceName);
    console.log("status:", status);
    console.log("statusCode:", statusCode, typeof statusCode);
    console.log("statusClass:", statusClass);
    

    📂 Part 9: 完成版テンプレート(コピペ用)

    9-1. 最小構成(すぐ動く版)

    <dashboard>
      <label>図形ステータスダッシュボード</label>
      
      <search id="mySearch">
        <query>
          | makeresults count=4
          | streamstats count as id
          | eval name=case(id==1,"A",id==2,"B",id==3,"C",id==4,"D")
          | eval status=case(id==1,"正常",id==2,"警告",id==3,"異常",id==4,"停止")
          | eval code=case(status=="正常",0,status=="警告",1,status=="異常",2,status=="停止",3)
          | table name, status, code
        </query>
      </search>
      
      <row>
        <panel>
          <html>
            <style>
              .container{display:flex;gap:20px;padding:20px;flex-wrap:wrap;}
              .item{display:flex;flex-direction:column;align-items:center;gap:5px;}
              .rect{width:80px;height:50px;border-radius:5px;display:flex;justify-content:center;align-items:center;color:#fff;font-weight:bold;}
              .circle{width:60px;height:60px;border-radius:50%;display:flex;justify-content:center;align-items:center;color:#fff;font-weight:bold;}
              .bar{width:100px;height:20px;border-radius:3px;display:flex;justify-content:center;align-items:center;color:#fff;font-size:11px;}
              .tri{width:0;height:0;border-left:30px solid transparent;border-right:30px solid transparent;border-top:45px solid gray;}
              .c0{background-color:#28a745;}.c1{background-color:#ffc107;color:#333;}.c2{background-color:#dc3545;}.c3{background-color:#6c757d;}
              .tri.c0{border-top-color:#28a745;}.tri.c1{border-top-color:#ffc107;}.tri.c2{border-top-color:#dc3545;}.tri.c3{border-top-color:#6c757d;}
              .label{font-size:11px;color:#333;}
            </style>
            <div class="container" id="box"></div>
            <script>
              require(['splunkjs/mvc','splunkjs/mvc/simplexml/ready!'],function(mvc){
                var sm=mvc.Components.get("mySearch");
                sm.data("results").on("data",function(){
                  if(this.hasData()){
                    var r=this.data().rows,f=this.data().fields,box=document.getElementById('box');
                    box.innerHTML='';
                    var shapes=['rect','circle','bar','tri'];
                    r.forEach(function(row,i){
                      var n=row[f.indexOf('name')],s=row[f.indexOf('status')],c=parseInt(row[f.indexOf('code')]);
                      var cls='c'+c,sh=shapes[i%4];
                      var html='<div class="item">';
                      if(sh==='tri'){html+='<div class="tri '+cls+'"></div>';}
                      else{html+='<div class="'+sh+' '+cls+'">'+s+'</div>';}
                      html+='<div class="label">'+n+'</div></div>';
                      box.innerHTML+=html;
                    });
                  }
                });
              });
            </script>
          </html>
        </panel>
      </row>
    </dashboard>
    

    🎉 まとめ

    覚えておくべきポイント

    カテゴリ ポイント 四角 border-radius: 5px で少し丸く 丸 border-radius: 50% + 幅=高さ 棒 幅 > 高さ の四角形 三角 border のトリックで作成 色変更 CSSクラスを動的に付与 配置 Flexbox / Grid / 絶対位置

    次のステップ

    1. リアルデータに接続: index=your_index でサーチを変更

    2. リアルタイム更新: <refresh> タグを追加

    3. クリックイベント: 図形クリックでドリルダウン

    4. アニメーション: 点滅や拡大縮小を追加


    📖 参考リンク


    🔷 Part 1: XML構造の解説

    1-1. ダッシュボード宣言

    <dashboard>
    
    ↑ 【1行目】ダッシュボードの開始タグ
       - Splunkクラシックダッシュボードの最上位要素
       - すべての内容はこのタグの中に書く
       - HTMLでいう <html> タグのような役割
    
      <label>ステータス連動図形ダッシュボード</label>
    
    ↑ 【2行目】ダッシュボードのタイトル
       - 画面上部に表示される名前
       - ブラウザのタブにも表示される
       - 日本語OK
    

    1-2. サーチ定義(データ取得部分)

      <search id="status_search">
    
    ↑ 【3行目】サーチブロックの開始
       - id="status_search" → このサーチに名前を付ける
       - JavaScriptから mvc.Components.get("status_search") で参照できる
       - ★重要★ idは一意(ユニーク)でなければならない
    
        <query>
    
    ↑ 【4行目】SPLクエリの開始タグ
       - この中にSPL(Search Processing Language)を書く
    

    🔷 Part 2: SPLクエリの解説

          | makeresults count=4
    
    ↑ 【5行目】空のデータを4行生成
       
       ┌─ | ──────────────────────────────────────────────────────┐
       │  パイプ記号。SPLのコマンドを繋げる                        │
       │  「前のコマンドの結果を、次のコマンドに渡す」という意味   │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ makeresults ─────────────────────────────────────────────┐
       │  テスト用のダミーデータを生成するコマンド                 │
       │  実際のインデックスがなくても動作確認できる               │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ count=4 ─────────────────────────────────────────────────┐
       │  生成する行数を指定                                       │
       │  この場合、4行のデータが作られる                          │
       └───────────────────────────────────────────────────────────┘
       
       【この時点のデータ】
       ┌──────────────────┐
       │ _time            │
       ├──────────────────┤
       │ 2024-01-01 00:00 │  ← 自動で現在時刻が入る
       │ 2024-01-01 00:00 │
       │ 2024-01-01 00:00 │
       │ 2024-01-01 00:00 │
       └──────────────────┘
    
          | streamstats count as id
    
    ↑ 【6行目】各行に連番を振る
    
       ┌─ streamstats ─────────────────────────────────────────────┐
       │  「流れるように」統計を計算するコマンド                   │
       │  各行ごとに、その時点までの累計を計算                     │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ count ───────────────────────────────────────────────────┐
       │  行数をカウントする関数                                   │
       │  1行目→1、2行目→2、3行目→3... と増えていく             │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ as id ───────────────────────────────────────────────────┐
       │  カウント結果を「id」という名前のフィールドに保存         │
       │  as = 「〜として」という意味                              │
       └───────────────────────────────────────────────────────────┘
       
       【この時点のデータ】
       ┌──────────────────┬─────┐
       │ _time            │ id  │
       ├──────────────────┼─────┤
       │ 2024-01-01 00:00 │  1  │  ← 連番が振られた!
       │ 2024-01-01 00:00 │  2  │
       │ 2024-01-01 00:00 │  3  │
       │ 2024-01-01 00:00 │  4  │
       └──────────────────┴─────┘
    
          | eval device_name = case(
              id==1, "サーバーA",
              id==2, "サーバーB", 
              id==3, "ネットワーク機器C",
              id==4, "データベースD"
            )
    
    ↑ 【7〜12行目】デバイス名を条件分岐で設定
    
       ┌─ eval ────────────────────────────────────────────────────┐
       │  「evaluate(評価する)」の略                             │
       │  新しいフィールドを作成したり、値を計算したりする         │
       │  ★超重要★ Splunkで最もよく使うコマンド                  │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ device_name = ───────────────────────────────────────────┐
       │  「device_name」という新しいフィールドを作成              │
       │  = の右側の値が代入される                                 │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ case(条件1, 値1, 条件2, 値2, ...) ───────────────────────┐
       │  条件分岐を行う関数                                       │
       │  書き方: case(条件, その時の値, 条件, その時の値, ...)    │
       │                                                           │
       │  id==1 → "サーバーA"                                      │
       │  id==2 → "サーバーB"                                      │
       │  id==3 → "ネットワーク機器C"                              │
       │  id==4 → "データベースD"                                  │
       │                                                           │
       │  ★注意★ == は「等しい」の比較演算子(=は代入)          │
       └───────────────────────────────────────────────────────────┘
       
       【この時点のデータ】
       ┌─────┬─────────────────────┐
       │ id  │ device_name         │
       ├─────┼─────────────────────┤
       │  1  │ サーバーA           │
       │  2  │ サーバーB           │
       │  3  │ ネットワーク機器C   │
       │  4  │ データベースD       │
       └─────┴─────────────────────┘
    
          | eval status = case(
              id==1, "正常",
              id==2, "警告",
              id==3, "異常",
              id==4, "停止"
            )
    
    ↑ 【13〜18行目】ステータスを設定
    
       【この時点のデータ】
       ┌─────┬─────────────────────┬─────────┐
       │ id  │ device_name         │ status  │
       ├─────┼─────────────────────┼─────────┤
       │  1  │ サーバーA           │ 正常    │
       │  2  │ サーバーB           │ 警告    │
       │  3  │ ネットワーク機器C   │ 異常    │
       │  4  │ データベースD       │ 停止    │
       └─────┴─────────────────────┴─────────┘
    
          | eval status_code = case(
              status=="正常", 0,
              status=="警告", 1,
              status=="異常", 2,
              status=="停止", 3
            )
    
    ↑ 【19〜24行目】ステータスを数値コードに変換
    
       ┌─ なぜ数値コードが必要? ──────────────────────────────────┐
       │  JavaScriptのswitch文で使いやすくするため                 │
       │  文字列より数値の方が比較が高速                           │
       │  0=正常, 1=警告, 2=異常, 3=停止 という対応表              │
       └───────────────────────────────────────────────────────────┘
       
       【この時点のデータ】
       ┌─────┬─────────────────────┬─────────┬─────────────┐
       │ id  │ device_name         │ status  │ status_code │
       ├─────┼─────────────────────┼─────────┼─────────────┤
       │  1  │ サーバーA           │ 正常    │      0      │
       │  2  │ サーバーB           │ 警告    │      1      │
       │  3  │ ネットワーク機器C   │ 異常    │      2      │
       │  4  │ データベースD       │ 停止    │      3      │
       └─────┴─────────────────────┴─────────┴─────────────┘
    
          | table device_name, status, status_code
    
    ↑ 【25行目】表示するフィールドを選択
    
       ┌─ table ───────────────────────────────────────────────────┐
       │  指定したフィールドだけを表示する                         │
       │  カンマ区切りで複数指定可能                               │
       │  指定しないフィールド(id, _timeなど)は除外される        │
       └───────────────────────────────────────────────────────────┘
       
       【最終出力データ】
       ┌─────────────────────┬─────────┬─────────────┐
       │ device_name         │ status  │ status_code │
       ├─────────────────────┼─────────┼─────────────┤
       │ サーバーA           │ 正常    │      0      │
       │ サーバーB           │ 警告    │      1      │
       │ ネットワーク機器C   │ 異常    │      2      │
       │ データベースD       │ 停止    │      3      │
       └─────────────────────┴─────────┴─────────────┘
    
        </query>
    
    ↑ 【26行目】SPLクエリの終了タグ
    
        <earliest>-24h@h</earliest>
    
    ↑ 【27行目】検索期間の開始時刻
    
       ┌─ -24h ────────────────────────────────────────────────────┐
       │  「24時間前」という意味                                   │
       │  - = マイナス(過去方向)                                 │
       │  24h = 24時間                                             │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ @h ──────────────────────────────────────────────────────┐
       │  「時間の境界に丸める」という意味                         │
       │  例: 今が14:35なら → 14:00に丸められる                    │
       │  @d なら日の境界(00:00)に丸められる                     │
       └───────────────────────────────────────────────────────────┘
    
        <latest>now</latest>
    
    ↑ 【28行目】検索期間の終了時刻
    
       ┌─ now ─────────────────────────────────────────────────────┐
       │  「現在時刻」という意味                                   │
       │  つまり「24時間前〜今まで」のデータを検索                 │
       └───────────────────────────────────────────────────────────┘
    
      </search>
    
    ↑ 【29行目】サーチブロックの終了タグ
    

    🔷 Part 3: HTMLパネル構造

      <row>
    
    ↑ 【30行目】行の開始
    
       ┌─────────────────────────────────────────────────────────┐
       │  Splunkダッシュボードは「行 → パネル」の構造            │
       │                                                         │
       │  <row>                      ← 横方向のコンテナ          │
       │    <panel>...</panel>       ← 1つ目のパネル            │
       │    <panel>...</panel>       ← 2つ目のパネル(横並び)   │
       │  </row>                                                 │
       └─────────────────────────────────────────────────────────┘
    
        <panel>
    
    ↑ 【31行目】パネルの開始
       - パネル = コンテンツを表示する箱
       - 1つの<row>に複数の<panel>を入れると横並びになる
    
          <title>ステータス連動図形</title>
    
    ↑ 【32行目】パネルのタイトル
       - パネル上部に表示される見出し
    
          <html>
    
    ↑ 【33行目】HTMLパネルの開始
       - この中に自由にHTML/CSS/JavaScriptを書ける
       - ★重要★ クラシックダッシュボード最大の自由度ポイント
    

    🔷 Part 4: CSS(スタイル)の解説

            <style>
    
    ↑ 【34行目】スタイル定義の開始
       - CSSを書くためのタグ
       - <style>〜</style>の中にCSSルールを記述
    

    4-1. コンテナのスタイル

              /* ===== コンテナ(図形を並べる箱) ===== */
              .shapes-container {
    
    ↑ 【35〜36行目】コンテナクラスの定義開始
    
       ┌─ /* ... */ ───────────────────────────────────────────────┐
       │  CSSのコメント                                            │
       │  コードの説明を書くために使う(実行には影響しない)       │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ .shapes-container ───────────────────────────────────────┐
       │  クラスセレクタ                                           │
       │  . = クラスを指定する記号                                 │
       │  shapes-container = クラス名                              │
       │  HTML側で class="shapes-container" と書いた要素に適用     │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ { ────────────────────────────────────────────────────────┐
       │  CSSルールの開始                                          │
       │  この中にプロパティと値を書く                             │
       └───────────────────────────────────────────────────────────┘
    
                /* 横並びにする */
                display: flex;
    
    ↑ 【37〜38行目】Flexboxを有効化
    
       ┌─ display: flex; ──────────────────────────────────────────┐
       │  Flexbox(フレックスボックス)レイアウトを有効にする      │
       │                                                           │
       │  【Flexboxとは?】                                        │
       │  要素を柔軟に配置できるCSSの仕組み                        │
       │                                                           │
       │  display: flex なし:    display: flex あり:               │
       │  ┌─────┐               ┌─────┬─────┬─────┐               │
       │  │  A  │               │  A  │  B  │  C  │ ← 横並び      │
       │  ├─────┤               └─────┴─────┴─────┘               │
       │  │  B  │ ← 縦並び                                        │
       │  ├─────┤                                                  │
       │  │  C  │                                                  │
       │  └─────┘                                                  │
       └───────────────────────────────────────────────────────────┘
    
                /* 図形間の余白 */
                gap: 20px;
    
    ↑ 【39〜40行目】要素間の余白
    
       ┌─ gap: 20px; ──────────────────────────────────────────────┐
       │  Flexbox/Grid内の要素間の余白を設定                       │
       │                                                           │
       │  gap: 20px の効果:                                        │
       │  ┌─────┐     ┌─────┐     ┌─────┐                         │
       │  │  A  │←20px→│  B  │←20px→│  C  │                       │
       │  └─────┘     └─────┘     └─────┘                         │
       │                                                           │
       │  ★便利★ marginより簡単に余白を統一できる                │
       └───────────────────────────────────────────────────────────┘
    
                /* 内側の余白 */
                padding: 20px;
    
    ↑ 【41〜42行目】内側の余白
    
       ┌─ padding: 20px; ──────────────────────────────────────────┐
       │  要素の内側(枠線と内容の間)の余白                       │
       │                                                           │
       │  ┌─────────────────────────────┐                          │
       │  │  ← 20px padding →          │                          │
       │  │  ┌─────────────────────┐   │                          │
       │  │  │    コンテンツ       │   │                          │
       │  │  └─────────────────────┘   │                          │
       │  │         ↑ 20px padding     │                          │
       │  └─────────────────────────────┘                          │
       │                                                           │
       │  【margin vs padding】                                    │
       │  margin = 外側の余白(要素同士の間)                      │
       │  padding = 内側の余白(枠線と内容の間)                   │
       └───────────────────────────────────────────────────────────┘
    
                /* 折り返しを許可 */
                flex-wrap: wrap;
    
    ↑ 【43〜44行目】折り返し設定
    
       ┌─ flex-wrap: wrap; ────────────────────────────────────────┐
       │  要素が画面幅を超えたら折り返す                           │
       │                                                           │
       │  flex-wrap: nowrap(デフォルト):                         │
       │  ┌────────────────────────────────────────┐               │
       │  │ A │ B │ C │ D │ E │ F │→ はみ出る →    │               │
       │  └────────────────────────────────────────┘               │
       │                                                           │
       │  flex-wrap: wrap:                                         │
       │  ┌────────────────────────┐                               │
       │  │ A │ B │ C │ D │        │                               │
       │  │ E │ F │              │ ← 折り返される!               │
       │  └────────────────────────┘                               │
       └───────────────────────────────────────────────────────────┘
    
              }
    
    ↑ 【45行目】CSSルールの終了
    

    4-2. 各図形アイテムのスタイル

              /* ===== 各図形の共通スタイル ===== */
              .shape-item {
    
    ↑ 【46〜47行目】図形アイテムクラスの定義開始
       - 各図形(四角、丸など)を包むラッパー要素のスタイル
    
                /* 縦並びにする(図形 + ラベル) */
                display: flex;
                flex-direction: column;
    
    ↑ 【48〜50行目】縦並びのFlexbox
    
       ┌─ flex-direction: column; ─────────────────────────────────┐
       │  Flexboxの並び方向を「縦」に変更                          │
       │                                                           │
       │  flex-direction: row(デフォルト):                       │
       │  ┌─────┬─────┬─────┐                                     │
       │  │図形 │ラベル│ステ │ ← 横並び                           │
       │  └─────┴─────┴─────┘                                     │
       │                                                           │
       │  flex-direction: column:                                  │
       │  ┌───────────┐                                           │
       │  │   図形    │                                           │
       │  ├───────────┤                                           │
       │  │  ラベル   │ ← 縦並び                                  │
       │  ├───────────┤                                           │
       │  │ ステータス │                                           │
       │  └───────────┘                                           │
       └───────────────────────────────────────────────────────────┘
    
                /* 中央揃え */
                align-items: center;
    
    ↑ 【51〜52行目】要素を中央揃え
    
       ┌─ align-items: center; ────────────────────────────────────┐
       │  Flexboxの交差軸方向(縦並びなら横方向)で中央揃え        │
       │                                                           │
       │  align-items: flex-start:    align-items: center:         │
       │  ┌───────────┐              ┌───────────┐                │
       │  │■          │              │    ■      │                │
       │  │サーバーA  │              │ サーバーA │                │
       │  │正常       │              │   正常    │                │
       │  └───────────┘              └───────────┘                │
       │  ↑左寄せ                    ↑中央揃え                    │
       └───────────────────────────────────────────────────────────┘
    
                /* 図形間の余白 */
                gap: 8px;
              }
    
    ↑ 【53〜55行目】図形とラベルの間の余白
       - 8px = 適度な間隔(狭すぎず広すぎず)
    

    4-3. 四角形のスタイル

              /* ===== 四角形 ===== */
              .rectangle {
                width: 100px;
                height: 60px;
    
    ↑ 【56〜59行目】四角形のサイズ
    
       ┌─ width: 100px; ───────────────────────────────────────────┐
       │  横幅を100ピクセルに設定                                  │
       │  px = ピクセル(画面上の点の数)                          │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ height: 60px; ───────────────────────────────────────────┐
       │  高さを60ピクセルに設定                                   │
       │  横長の四角形になる(100 > 60)                           │
       └───────────────────────────────────────────────────────────┘
       
       【結果イメージ】
       ┌────────────────────┐
       │                    │ ← 100px × 60px
       │                    │
       └────────────────────┘
    
                background-color: #808080 ;
    
    ↑ 【60行目】背景色(初期値)
    
       ┌─ #808080  ─────────────────────────────────────────────────┐
       │  16進数カラーコード(グレー)                             │
       │                                                           │
       │  #RRGGBB  の形式:                                          │
       │  RR = 赤の強さ (00〜FF)                                   │
       │  GG = 緑の強さ (00〜FF)                                   │
       │  BB = 青の強さ (00〜FF)                                   │
       │                                                           │
       │  例: #808080  = 赤128 + 緑128 + 青128 = グレー             │
       │  例: #FF0000  = 赤255 + 緑0 + 青0 = 真っ赤                 │
       │  例: #28a745  = 緑色(正常ステータス用)                   │
       └───────────────────────────────────────────────────────────┘
    
                border-radius: 5px;
    
    ↑ 【61行目】角の丸み
    
       ┌─ border-radius: 5px; ─────────────────────────────────────┐
       │  角を丸くする(値が大きいほど丸くなる)                   │
       │                                                           │
       │  0px:         5px:         20px:        50%:              │
       │  ┌────┐      ╭────╮      ╭────╮       (●)               │
       │  │    │      │    │      │    │       円になる           │
       │  └────┘      ╰────╯      ╰────╯                          │
       │  角張り      少し丸い    かなり丸い                       │
       └───────────────────────────────────────────────────────────┘
    
                border: 2px solid #333 ;
    
    ↑ 【62行目】枠線
    
       ┌─ border: 2px solid #333 ; ─────────────────────────────────┐
       │  枠線を一括指定(太さ、スタイル、色)                     │
       │                                                           │
       │  2px = 枠線の太さ                                         │
       │  solid = 実線(他に dashed=破線, dotted=点線)            │
       │  #333  = 枠線の色(濃いグレー)                            │
       │                                                           │
       │  【枠線スタイルの例】                                     │
       │  solid:  ────────                                         │
       │  dashed: - - - - -                                        │
       │  dotted: ・・・・・                                       │
       └───────────────────────────────────────────────────────────┘
    
                display: flex;
                justify-content: center;
                align-items: center;
    
    ↑ 【63〜65行目】テキストを中央揃え
    
       ┌─ justify-content: center; ────────────────────────────────┐
       │  主軸方向(横並びなら横方向)で中央揃え                   │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ align-items: center; ────────────────────────────────────┐
       │  交差軸方向(横並びなら縦方向)で中央揃え                 │
       └───────────────────────────────────────────────────────────┘
       
       【組み合わせ効果】
       ┌─────────────────────┐
       │                     │
       │        正常         │ ← 完全に中央に配置
       │                     │
       └─────────────────────┘
    
                color: white;
                font-weight: bold;
                font-size: 14px;
    
    ↑ 【66〜68行目】文字スタイル
    
       ┌─ color: white; ───────────────────────────────────────────┐
       │  文字色を白に設定                                         │
       │  背景色が濃い色なので、白文字で見やすくする               │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ font-weight: bold; ──────────────────────────────────────┐
       │  文字を太字にする                                         │
       │  他の値: normal(普通), lighter(細い), 100〜900        │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ font-size: 14px; ────────────────────────────────────────┐
       │  文字サイズを14ピクセルに設定                             │
       │  ブラウザのデフォルトは約16px                             │
       └───────────────────────────────────────────────────────────┘
    
                /* アニメーション(色が滑らかに変化) */
                transition: background-color 0.3s ease;
              }
    
    ↑ 【69〜71行目】アニメーション効果
    
       ┌─ transition: background-color 0.3s ease; ─────────────────┐
       │  プロパティが変化するときのアニメーションを設定           │
       │                                                           │
       │  background-color = 変化を監視するプロパティ              │
       │  0.3s = 変化にかかる時間(0.3秒)                         │
       │  ease = 変化の速度曲線(最初と最後がゆっくり)            │
       │                                                           │
       │  【効果】                                                 │
       │  JavaScriptで色を変えると、パッと変わらずに              │
       │  0.3秒かけて滑らかに変化する!                            │
       │                                                           │
       │  グレー ───────→ 緑                                       │
       │        (0.3秒でじんわり変化)                              │
       └───────────────────────────────────────────────────────────┘
    

    4-4. 丸のスタイル

              /* ===== 丸 ===== */
              .circle {
                width: 70px;
                height: 70px;
    
    ↑ 【72〜75行目】丸のサイズ
    
       ┌─ ★重要★ 丸を作るコツ ────────────────────────────────────┐
       │  width と height を同じ値にする!                         │
       │                                                           │
       │  width: 70px  ┬                                          │
       │  height: 70px ┘ → 正方形になる                           │
       │                                                           │
       │  この正方形に border-radius: 50% を適用すると             │
       │  完全な円になる!                                         │
       └───────────────────────────────────────────────────────────┘
    
                background-color: #808080 ;
                border-radius: 50%;
    
    ↑ 【76〜77行目】丸を作る魔法
    
       ┌─ border-radius: 50%; ─────────────────────────────────────┐
       │  角の丸みを50%に設定                                      │
       │                                                           │
       │  【50%の意味】                                            │
       │  「幅と高さの半分の大きさで角を丸める」                   │
       │                                                           │
       │  70px × 70px の正方形で 50% = 35px                        │
       │  4つの角すべてが35pxで丸まる → 完全な円!                │
       │                                                           │
       │  border-radius: 0%    border-radius: 50%                  │
       │       ┌────┐              ╭────╮                         │
       │       │    │              │    │                         │
       │       │    │      →      │    │      →      ●          │
       │       │    │              │    │                         │
       │       └────┘              ╰────╯                         │
       └───────────────────────────────────────────────────────────┘
    
                border: 2px solid #333 ;
                display: flex;
                justify-content: center;
                align-items: center;
                color: white;
                font-weight: bold;
                font-size: 12px;
                transition: background-color 0.3s ease;
              }
    
    ↑ 【78〜86行目】その他のスタイル
       - 四角形とほぼ同じ(文字サイズだけ12pxと少し小さい)
    

    4-5. 棒のスタイル

              /* ===== 棒 ===== */
              .bar {
                width: 120px;
                height: 25px;
    
    ↑ 【87〜90行目】棒のサイズ
    
       ┌─ 横長の形状 ──────────────────────────────────────────────┐
       │  width: 120px (横幅)                                      │
       │  height: 25px (高さ)                                      │
       │                                                           │
       │  横幅 > 高さ → 横長の棒になる                             │
       │                                                           │
       │  ┌────────────────────────────────────┐                  │
       │  │              棒                    │ ← 120px × 25px   │
       │  └────────────────────────────────────┘                  │
       └───────────────────────────────────────────────────────────┘
    
                background-color: #808080 ;
                border-radius: 3px;
                border: 1px solid #333 ;
                display: flex;
                justify-content: center;
                align-items: center;
                color: white;
                font-weight: bold;
                font-size: 11px;
                transition: background-color 0.3s ease;
              }
    
    ↑ 【91〜101行目】その他のスタイル
       - border-radius: 3px → 角をほんの少しだけ丸める
       - font-size: 11px → 棒は細いので文字も小さめ
    

    4-6. 三角形のスタイル

              /* ===== 三角形(下向き)===== */
              .triangle {
                width: 0;
                height: 0;
    
    ↑ 【102〜105行目】三角形のベース
    
       ┌─ ★超重要★ なぜ幅と高さが0? ─────────────────────────────┐
       │  CSSの三角形は「枠線(border)のトリック」で作る          │
       │                                                           │
       │  通常、枠線は四角形の周りに描かれるが、                   │
       │  幅と高さを0にすると、枠線だけが残る!                    │
       │                                                           │
       │  そして、3辺を透明、1辺に色を付けると                     │
       │  三角形が現れる!                                         │
       └───────────────────────────────────────────────────────────┘
    
                border-left: 35px solid transparent;
                border-right: 35px solid transparent;
    
    ↑ 【106〜107行目】左右の辺(透明)
    
       ┌─ transparent ─────────────────────────────────────────────┐
       │  「透明」という意味                                       │
       │  色は付くが、見えない状態                                 │
       │                                                           │
       │  左右に35pxずつの透明な枠線 → 三角形の底辺幅が70pxに      │
       └───────────────────────────────────────────────────────────┘
    
                border-top: 50px solid #808080 ;
    
    ↑ 【108行目】上辺(色を付ける)
    
       ┌─ border-top: 50px solid #808080 ; ─────────────────────────┐
       │  上の枠線に色を付ける → 下向き三角形 ▼ が完成!          │
       │                                                           │
       │  【三角形の仕組み図解】                                   │
       │                                                           │
       │  幅0、高さ0の点を中心に、枠線が放射状に描かれる          │
       │                                                           │
       │           border-top(色付き)                            │
       │                 ▼                                         │
       │              ╱    ╲                                       │
       │            ╱   ●   ╲   ← 幅0、高さ0の中心点              │
       │          ╱          ╲                                     │
       │        透明        透明                                   │
       │   (border-left) (border-right)                            │
       │                                                           │
       │  結果: 色付きの部分だけが見える → ▼                      │
       └───────────────────────────────────────────────────────────┘
    
                transition: border-top-color 0.3s ease;
              }
    
    ↑ 【109〜110行目】三角形のアニメーション
    
       ┌─ border-top-color ────────────────────────────────────────┐
       │  三角形は background-color ではなく                       │
       │  border-top-color で色を変える!                          │
       │                                                           │
       │  ★注意★ 四角や丸とは違うプロパティ名                    │
       └───────────────────────────────────────────────────────────┘
    

    4-7. ラベルのスタイル

              /* ===== ラベル(機器名) ===== */
              .device-label {
                font-size: 12px;
                color: #333 ;
                font-weight: bold;
              }
    
    ↑ 【111〜116行目】機器名ラベル
       - font-size: 12px → 小さめの文字
       - color: #333  → 濃いグレー(黒に近い)
       - font-weight: bold → 太字で目立たせる
    
              /* ===== ステータスラベル ===== */
              .status-label {
                font-size: 11px;
                color: #666 ;
              }
    
    ↑ 【117〜121行目】ステータスラベル
       - font-size: 11px → さらに小さい
       - color: #666  → 中間グレー(サブ情報なので控えめに)
    

    4-8. ステータス別の色クラス

              /* ===== 色の定義(ステータス別) ===== */
              .status-normal { background-color: #28a745 ; }
              .status-warning { background-color: #ffc107 ; }
              .status-error { background-color: #dc3545 ; }
              .status-stop { background-color: #6c757d ; }
    
    ↑ 【122〜126行目】ステータス別の背景色
    
       ┌─ 色クラスの対応表 ────────────────────────────────────────┐
       │                                                           │
       │  クラス名         │ カラーコード │ 色   │ 用途           │
       │  ─────────────────┼──────────────┼──────┼────────────────│
       │  .status-normal   │ #28a745       │ 緑   │ 正常           │
       │  .status-warning  │ #ffc107       │ 黄   │ 警告           │
       │  .status-error    │ #dc3545       │ 赤   │ 異常           │
       │  .status-stop     │ #6c757d       │ 灰   │ 停止           │
       │                                                           │
       │  これらの色はBootstrapの標準色と同じ                      │
       │  (多くの人が見慣れている色)                             │
       └───────────────────────────────────────────────────────────┘
    
              /* 三角形用(border-topで色を指定) */
              .triangle.status-normal { border-top-color: #28a745 ; }
              .triangle.status-warning { border-top-color: #ffc107 ; }
              .triangle.status-error { border-top-color: #dc3545 ; }
              .triangle.status-stop { border-top-color: #6c757d ; }
    
    ↑ 【127〜131行目】三角形専用の色クラス
    
       ┌─ .triangle.status-normal ─────────────────────────────────┐
       │  複合セレクタ(両方のクラスを持つ要素に適用)             │
       │                                                           │
       │  class="triangle status-normal" を持つ要素に適用          │
       │                                                           │
       │  ★なぜ別に定義?★                                       │
       │  三角形は background-color ではなく                       │
       │  border-top-color で色を変える必要があるため              │
       └───────────────────────────────────────────────────────────┘
    
            </style>
    
    ↑ 【132行目】スタイル定義の終了
    

    🔷 Part 5: HTML本体の解説

            <!-- 図形を配置するコンテナ -->
            <div class="shapes-container" id="shapesContainer">
              <!-- JavaScriptで動的に生成される -->
            </div>
    
    ↑ 【133〜136行目】図形を入れる箱
    
       ┌─ <div> ───────────────────────────────────────────────────┐
       │  汎用のコンテナ要素                                       │
       │  中にコンテンツを入れるための箱                           │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ class="shapes-container" ────────────────────────────────┐
       │  CSSのスタイルを適用するためのクラス名                    │
       │  上で定義した .shapes-container のスタイルが適用される    │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ id="shapesContainer" ────────────────────────────────────┐
       │  JavaScriptから getElementById() で取得するためのID       │
       │  ★重要★ idは1ページに1つだけ(一意でなければならない)   │
       └───────────────────────────────────────────────────────────┘
       
       【最初は空っぽ → JavaScriptで図形が追加される】
       
       初期状態:                    JavaScript実行後:
       ┌─────────────────────┐     ┌─────────────────────────────┐
       │                     │     │ ■    ●    ▬    ▼         │
       │     (空っぽ)       │ →  │ A    B    C    D           │
       │                     │     │ 正常  警告  異常  停止      │
       └─────────────────────┘     └─────────────────────────────┘
    

    🔷 Part 6: JavaScript(Splunk連携)の解説

            <script>
    
    ↑ 【137行目】JavaScriptコードの開始
    

    6-1. モジュール読み込み

              // ===== Splunkのデータを取得してUIに反映 =====
              require([
                'splunkjs/mvc',
                'splunkjs/mvc/searchmanager',
                'splunkjs/mvc/simplexml/ready!'
              ], function(mvc) {
    
    ↑ 【138〜143行目】Splunk用モジュールの読み込み
    
       ┌─ require([...], function) ────────────────────────────────┐
       │  AMD(Asynchronous Module Definition)形式のモジュール読込│
       │  必要なライブラリが読み込まれてから、function内を実行     │
       │                                                           │
       │  【なぜrequireを使う?】                                   │
       │  Splunkの機能は別ファイルに分かれている                   │
       │  必要な部分だけを読み込むことで、効率的に動作             │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ 'splunkjs/mvc' ──────────────────────────────────────────┐
       │  SplunkのMVC(Model-View-Controller)フレームワーク       │
       │  ダッシュボードのコンポーネントを操作するために必要       │
       │  例: サーチ結果の取得、パネルの操作など                   │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ 'splunkjs/mvc/searchmanager' ────────────────────────────┐
       │  サーチを管理するモジュール                               │
       │  SPLクエリの実行や結果取得に使う                          │
       │  (実際には今回は直接使わないが、依存関係として必要)     │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ 'splunkjs/mvc/simplexml/ready!' ─────────────────────────┐
       │  ダッシュボードの準備完了を待つ特別なモジュール           │
       │  末尾の「!」は「待ってから実行」という意味                │
       │                                                           │
       │  【なぜ必要?】                                           │
       │  ダッシュボードの読み込みが完了する前に                   │
       │  JavaScriptが動くと、エラーになる可能性がある             │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ function(mvc) ───────────────────────────────────────────┐
       │  読み込んだモジュールを「mvc」という名前で受け取る        │
       │  この関数の中でSplunkの機能を使える                       │
       └───────────────────────────────────────────────────────────┘
    

    6-2. サーチマネージャーの取得

                // サーチマネージャーを取得
                // "status_search" は <search id="status_search"> と対応
                var searchManager = mvc.Components.get("status_search");
    
    ↑ 【144〜146行目】サーチへの参照を取得
    
       ┌─ var ─────────────────────────────────────────────────────┐
       │  変数を宣言するキーワード                                 │
       │  searchManager という名前の変数を作成                     │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ mvc.Components.get("status_search") ─────────────────────┐
       │  ダッシュボード上のコンポーネントを名前で取得             │
       │                                                           │
       │  mvc.Components = Splunkのコンポーネント管理オブジェクト  │
       │  .get("status_search") = "status_search"という名前のもの  │
       │                                                           │
       │  【対応関係】                                              │
       │  XML側:  <search id="status_search">                      │
       │  JS側:   mvc.Components.get("status_search")              │
       │                        ↑ 同じ名前!                       │
       │                                                           │
       │  ★注意★ idが一致しないとエラーになる                    │
       └───────────────────────────────────────────────────────────┘
    

    6-3. 結果データの取得

                // サーチ結果を取得
                var results = searchManager.data("results");
    
    ↑ 【147〜148行目】結果データへの参照を取得
    
       ┌─ searchManager.data("results") ───────────────────────────┐
       │  サーチの結果データを取得                                 │
       │                                                           │
       │  "results" = 完了した最終結果                             │
       │  "preview" = 途中経過の結果(リアルタイム用)             │
       │                                                           │
       │  【resultsオブジェクトの機能】                            │
       │  .hasData()    → データがあるかチェック                   │
       │  .data()       → 実際のデータを取得                       │
       │  .on("data")   → データ更新時のイベント登録               │
       └───────────────────────────────────────────────────────────┘
    

    6-4. イベントリスナーの設定

                // データが変更されたら実行
                results.on("data", function() {
    
    ↑ 【149〜150行目】データ更新時の処理を登録
    
       ┌─ .on("data", function() {...}) ───────────────────────────┐
       │  イベントリスナーの登録                                   │
       │                                                           │
       │  "data" = 「データが更新された」というイベント名          │
       │  function() = そのイベントが発生したら実行する関数        │
       │                                                           │
       │  【いつ発火する?】                                       │
       │  ・ページ読み込み時(最初のサーチ完了時)                 │
       │  ・自動更新時(<refresh>タグがある場合)                  │
       │  ・手動でサーチを再実行した時                             │
       │                                                           │
       │  【イベント駆動の流れ】                                   │
       │  SPLサーチ実行 → 結果取得 → "data"イベント発火           │
       │                              → function()が実行される     │
       └───────────────────────────────────────────────────────────┘
    

    6-5. データ存在チェック

                  // 結果が存在するかチェック
                  if (results.hasData()) {
    
    ↑ 【151〜152行目】データがあるか確認
    
       ┌─ if (results.hasData()) ──────────────────────────────────┐
       │  条件分岐: データがある場合のみ処理を実行                 │
       │                                                           │
       │  hasData() = true/false を返すメソッド                    │
       │  ・サーチ結果があれば true                                │
       │  ・結果が空、またはエラーなら false                       │
       │                                                           │
       │  【なぜチェックが必要?】                                 │
       │  データがない状態で処理すると、エラーになる               │
       │  例: 空のデータに対して .forEach() を実行 → エラー        │
       └───────────────────────────────────────────────────────────┘
    

    6-6. 結果データの取り出し

                    // 結果をJSON形式で取得
                    var rows = results.data().rows;
                    var fields = results.data().fields;
    
    ↑ 【153〜155行目】行データとフィールド名を取得
    
       ┌─ results.data() ──────────────────────────────────────────┐
       │  サーチ結果のデータオブジェクトを取得                     │
       │                                                           │
       │  返り値の構造:                                            │
       │  {                                                        │
       │    rows: [...],    // 行データの2次元配列                 │
       │    fields: [...]   // フィールド名の配列                  │
       │  }                                                        │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ .rows ───────────────────────────────────────────────────┐
       │  行データの2次元配列                                      │
       │                                                           │
       │  例:                                                      │
       │  [                                                        │
       │    ["サーバーA", "正常", "0"],     // 1行目               │
       │    ["サーバーB", "警告", "1"],     // 2行目               │
       │    ["ネットワーク機器C", "異常", "2"],                    │
       │    ["データベースD", "停止", "3"]                         │
       │  ]                                                        │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ .fields ─────────────────────────────────────────────────┐
       │  フィールド名(カラム名)の配列                           │
       │                                                           │
       │  例:                                                      │
       │  ["device_name", "status", "status_code"]                 │
       │                                                           │
       │  インデックス:  0           1        2                    │
       │               ↑           ↑        ↑                     │
       │  後で使う: fields.indexOf("status") → 1                   │
       └───────────────────────────────────────────────────────────┘
    

    6-7. コンテナの取得と初期化

                    // コンテナを取得
                    var container = document.getElementById('shapesContainer');
                    
                    // コンテナを空にする(再描画のため)
                    container.innerHTML = '';
    
    ↑ 【156〜160行目】描画先の準備
    
       ┌─ document.getElementById('shapesContainer') ──────────────┐
       │  HTML要素をIDで取得                                       │
       │                                                           │
       │  document = ウェブページ全体を表すオブジェクト            │
       │  getElementById() = 指定IDの要素を探して返す              │
       │  'shapesContainer' = 探すID名                             │
       │                                                           │
       │  【対応関係】                                              │
       │  HTML側: <div id="shapesContainer">                       │
       │  JS側:   document.getElementById('shapesContainer')       │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ container.innerHTML = '' ────────────────────────────────┐
       │  コンテナの中身を空にする                                 │
       │                                                           │
       │  innerHTML = 要素の中のHTMLを取得/設定するプロパティ      │
       │  '' = 空文字列(何もない状態)                            │
       │                                                           │
       │  【なぜ空にする?】                                       │
       │  データ更新のたびに図形を追加すると、                     │
       │  前の図形が残ったまま新しい図形が追加されてしまう         │
       │                                                           │
       │  空にしない場合:                                          │
       │  1回目: ■ ● ▬ ▼                                        │
       │  2回目: ■ ● ▬ ▼ ■ ● ▬ ▼  ← 倍に増える!              │
       │                                                           │
       │  空にする場合:                                            │
       │  1回目: ■ ● ▬ ▼                                        │
       │  2回目: ■ ● ▬ ▼  ← 正しく更新                          │
       └───────────────────────────────────────────────────────────┘
    

    6-8. データのループ処理

                    // 各行のデータをループ処理
                    rows.forEach(function(row, index) {
    
    ↑ 【161〜162行目】全行を1つずつ処理
    
       ┌─ .forEach(function(row, index) {...}) ────────────────────┐
       │  配列の各要素に対して関数を実行                           │
       │                                                           │
       │  rows.forEach() = rowsの各行に対してループ                │
       │                                                           │
       │  function(row, index) の引数:                             │
       │  ・row = 現在処理中の行(配列)                           │
       │  ・index = 現在のインデックス(0, 1, 2, 3...)            │
       │                                                           │
       │  【処理の流れ】                                           │
       │  1回目: row=["サーバーA","正常","0"], index=0              │
       │  2回目: row=["サーバーB","警告","1"], index=1              │
       │  3回目: row=["ネットワーク機器C","異常","2"], index=2      │
       │  4回目: row=["データベースD","停止","3"], index=3          │
       └───────────────────────────────────────────────────────────┘
    

    6-9. フィールドのインデックス取得

                      // フィールド名からインデックスを取得
                      var deviceIndex = fields.indexOf('device_name');
                      var statusIndex = fields.indexOf('status');
                      var codeIndex = fields.indexOf('status_code');
    
    ↑ 【163〜166行目】各フィールドの位置を特定
    
       ┌─ fields.indexOf('device_name') ───────────────────────────┐
       │  配列の中から指定した値の位置(インデックス)を探す       │
       │                                                           │
       │  fields = ["device_name", "status", "status_code"]        │
       │              ↑0番目         ↑1番目    ↑2番目             │
       │                                                           │
       │  fields.indexOf('device_name') → 0                        │
       │  fields.indexOf('status')      → 1                        │
       │  fields.indexOf('status_code') → 2                        │
       │                                                           │
       │  【なぜこの処理が必要?】                                 │
       │  フィールドの順番は保証されていない                       │
       │  SPLの書き方によって順番が変わる可能性がある              │
       │  インデックスで直接アクセスすると危険                     │
       │                                                           │
       │  危険な書き方:                                            │
       │  var deviceName = row[0];  // 0番目がdevice_nameとは限らない│
       │                                                           │
       │  安全な書き方:                                            │
       │  var deviceIndex = fields.indexOf('device_name');         │
       │  var deviceName = row[deviceIndex];  // 確実に正しい値    │
       └───────────────────────────────────────────────────────────┘
    

    6-10. 値の取得

                      // 値を取得
                      var deviceName = row[deviceIndex];
                      var status = row[statusIndex];
                      var statusCode = parseInt(row[codeIndex]);
    
    ↑ 【167〜170行目】各フィールドの値を取り出す
    
       ┌─ row[deviceIndex] ────────────────────────────────────────┐
       │  配列から指定位置の値を取得                               │
       │                                                           │
       │  例: row = ["サーバーA", "正常", "0"]                     │
       │      deviceIndex = 0                                      │
       │      row[deviceIndex] = row[0] = "サーバーA"              │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ parseInt(row[codeIndex]) ────────────────────────────────┐
       │  文字列を整数に変換                                       │
       │                                                           │
       │  row[codeIndex] = "0"  ← 文字列(String型)               │
       │  parseInt("0") = 0     ← 数値(Number型)                 │
       │                                                           │
       │  【なぜ変換が必要?】                                     │
       │  Splunkのサーチ結果は全て文字列として返される             │
       │  switch文で数値と比較するために変換が必要                 │
       │                                                           │
       │  文字列のまま比較すると:                                  │
       │  "0" === 0  → false  ← 型が違うので一致しない!           │
       │                                                           │
       │  数値に変換すると:                                        │
       │  0 === 0    → true   ← 正しく比較できる                   │
       └───────────────────────────────────────────────────────────┘
    

    6-11. ステータスに応じたクラス決定

                      // ステータスコードに応じたCSSクラスを決定
                      var statusClass = '';
                      switch(statusCode) {
                        case 0: statusClass = 'status-normal'; break;
                        case 1: statusClass = 'status-warning'; break;
                        case 2: statusClass = 'status-error'; break;
                        case 3: statusClass = 'status-stop'; break;
                        default: statusClass = '';
                      }
    
    ↑ 【171〜179行目】ステータスコードからCSSクラスを決定
    
       ┌─ var statusClass = '' ────────────────────────────────────┐
       │  変数の初期化(空文字で初期化)                           │
       │  後でswitch文で値を代入する                               │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ switch(statusCode) {...} ────────────────────────────────┐
       │  値に応じた分岐処理                                       │
       │                                                           │
       │  statusCode │ 実行される処理                              │
       │  ───────────┼──────────────────────────────────────────── │
       │      0      │ statusClass = 'status-normal'  (緑)        │
       │      1      │ statusClass = 'status-warning' (黄)        │
       │      2      │ statusClass = 'status-error'   (赤)        │
       │      3      │ statusClass = 'status-stop'    (灰)        │
       │    その他   │ statusClass = ''               (初期色)    │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ break; ──────────────────────────────────────────────────┐
       │  switch文を抜ける命令                                     │
       │                                                           │
       │  ★重要★ breakを書き忘れると、次のcaseも実行される       │
       │  (フォールスルーという)                                 │
       │                                                           │
       │  breakなし:                                               │
       │  case 0: → case 1: → case 2: → ... 全部実行されてしまう  │
       │                                                           │
       │  breakあり:                                               │
       │  case 0: → break → 終了 (正しい動作)                   │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ default: ────────────────────────────────────────────────┐
       │  どのcaseにも当てはまらない場合の処理                     │
       │                                                           │
       │  例: statusCode が 5 の場合 → default が実行される        │
       │  セーフティネットとして必ず書いておくと良い               │
       └───────────────────────────────────────────────────────────┘
    

    6-12. 図形の種類を決定

                      // 図形の種類を決定(例:インデックスで振り分け)
                      var shapeTypes = ['rectangle', 'circle', 'bar', 'triangle'];
                      var shapeType = shapeTypes[index % shapeTypes.length];
    
    ↑ 【180〜182行目】インデックスに応じた図形タイプの決定
    
       ┌─ var shapeTypes = ['rectangle', 'circle', 'bar', 'triangle'] ┐
       │  図形タイプの配列                                            │
       │                                                              │
       │  インデックス: 0          1        2      3                  │
       │               rectangle  circle   bar    triangle            │
       │               (四角)     (丸)     (棒)   (三角)              │
       └──────────────────────────────────────────────────────────────┘
       
       ┌─ index % shapeTypes.length ───────────────────────────────┐
       │  剰余演算子(%)を使ったループ技法                        │
       │                                                           │
       │  shapeTypes.length = 4(配列の要素数)                    │
       │                                                           │
       │  index │ index % 4 │ 結果                                 │
       │  ──────┼───────────┼────────────────────────────────────  │
       │    0   │  0 % 4    │ 0 → shapeTypes[0] = 'rectangle'     │
       │    1   │  1 % 4    │ 1 → shapeTypes[1] = 'circle'        │
       │    2   │  2 % 4    │ 2 → shapeTypes[2] = 'bar'           │
       │    3   │  3 % 4    │ 3 → shapeTypes[3] = 'triangle'      │
       │    4   │  4 % 4    │ 0 → shapeTypes[0] = 'rectangle'     │
       │    5   │  5 % 4    │ 1 → shapeTypes[1] = 'circle'        │
       │   ...  │   ...     │ ... (繰り返し)                     │
       │                                                           │
       │  【この技法のメリット】                                   │
       │  データが何行あっても、4種類の図形を順番に割り当てられる │
       └───────────────────────────────────────────────────────────┘
    

    6-13. 図形HTMLの生成

                      // 図形のHTMLを生成
                      var shapeHtml = '';
                      
                      if (shapeType === 'rectangle') {
                        shapeHtml = '<div class="rectangle ' + statusClass + '">' + status + '</div>';
                      } else if (shapeType === 'circle') {
                        shapeHtml = '<div class="circle ' + statusClass + '">' + status + '</div>';
                      } else if (shapeType === 'bar') {
                        shapeHtml = '<div class="bar ' + statusClass + '">' + status + '</div>';
                      } else if (shapeType === 'triangle') {
                        shapeHtml = '<div class="triangle ' + statusClass + '"></div>';
                      }
    
    ↑ 【183〜194行目】図形タイプに応じたHTML生成
    
       ┌─ '<div class="rectangle ' + statusClass + '">' ───────────┐
       │  文字列の連結                                             │
       │                                                           │
       │  例: statusClass = 'status-normal' の場合                 │
       │                                                           │
       │  '<div class="rectangle ' + 'status-normal' + '">'        │
       │  = '<div class="rectangle status-normal">'                │
       │                                                           │
       │  【生成されるHTML】                                       │
       │  <div class="rectangle status-normal">正常</div>          │
       │                                                           │
       │  このdivには2つのクラスが適用される:                      │
       │  ・rectangle → 四角形のスタイル                          │
       │  ・status-normal → 緑色の背景                            │
       └───────────────────────────────────────────────────────────┘
       
       ┌─ + status + ──────────────────────────────────────────────┐
       │  図形の中に表示するテキスト                               │
       │                                                           │
       │  status = "正常" の場合                                   │
       │  → <div class="rectangle status-normal">正常</div>        │
       │                                                           │
       │  ★三角形の場合は中身なし★                               │
       │  三角形はCSSのborderで形を作るため、                      │
       │  中にテキストを入れられない                               │
       │  → <div class="triangle status-normal"></div>             │
       └───────────────────────────────────────────────────────────┘
    

    6-14. 完成したアイテムのHTML生成

                      // 図形アイテム全体のHTMLを生成
                      var itemHtml = 
                        '<div class="shape-item">' +
                          shapeHtml +
                          '<div class="device-label">' + deviceName + '</div>' +
                          '<div class="status-label">' + status + '</div>' +
                        '</div>';
    
    ↑ 【195〜201行目】図形 + ラベルを組み合わせたHTML生成
    
       ┌─ 生成されるHTMLの構造 ────────────────────────────────────┐
       │                                                           │
       │  <div class="shape-item">           ← 外側の包み          │
       │    <div class="rectangle status-normal">正常</div>        │
       │                                      ↑ 図形              │
       │    <div class="device-label">サーバーA</div>              │
       │                                      ↑ 機器名ラベル      │
       │    <div class="status-label">正常</div>                   │
       │                                      ↑ ステータスラベル  │
       │  </div>                                                   │
       │                                                           │
       │  【表示イメージ】                                         │
       │  ┌───────────────┐                                       │
       │  │     正常      │  ← 四角形(緑色)                     │
       │  └───────────────┘                                       │
       │     サーバーA       ← 機器名                              │
       │       正常          ← ステータス                          │
       └───────────────────────────────────────────────────────────┘
    

    6-15. コンテナへの追加

                      // コンテナに追加
                      container.innerHTML += itemHtml;
    
    ↑ 【202〜203行目】生成したHTMLをコンテナに追加
    
       ┌─ container.innerHTML += itemHtml ─────────────────────────┐
       │  コンテナの中身にHTMLを追加                               │
       │                                                           │
       │  += は「既存の内容に追加」という意味                      │
       │  = だと「置き換え」になる                                 │
       │                                                           │
       │  【処理の流れ】                                           │
       │  1回目のループ後:                                         │
       │  container.innerHTML = "<div>...サーバーA...</div>"       │
       │                                                           │
       │  2回目のループ後:                                         │
       │  container.innerHTML = "<div>...サーバーA...</div>        │
       │                         <div>...サーバーB...</div>"       │
       │                                                           │
       │  ... (繰り返し)                                         │
       │                                                           │
       │  最終結果:                                                │
       │  container.innerHTML = "<div>A</div><div>B</div>..."      │
       │                         4つの図形がすべて追加される       │
       └───────────────────────────────────────────────────────────┘
    

    6-16. 閉じ括弧

                    });
                  }
                });
              });
            </script>
    
    ↑ 【204〜208行目】各ブロックの終了
    
       ┌─ 括弧の対応 ──────────────────────────────────────────────┐
       │                                                           │
       │  });  ← rows.forEach(function(row, index) { の終了       │
       │                                                           │
       │  }    ← if (results.hasData()) { の終了                  │
       │                                                           │
       │  });  ← results.on("data", function() { の終了           │
       │                                                           │
       │  });  ← require([...], function(mvc) { の終了            │
       │                                                           │
       │  </script>  ← JavaScriptコードの終了                      │
       │                                                           │
       │  【インデントで構造を把握】                               │
       │  require([                          │                     │
       │    results.on("data", function() {  │                     │
       │      if (results.hasData()) {       │ ← 対応する括弧     │
       │        rows.forEach(function() {    │                     │
       │        });                          │                     │
       │      }                              │                     │
       │    });                              │                     │
       │  });                                │                     │
       └───────────────────────────────────────────────────────────┘
    

    🔷 Part 7: XML終了部分

          </html>
        </panel>
      </row>
    </dashboard>
    
    ↑ 【209〜212行目】各ブロックの終了タグ
    
       </html>      ← HTMLパネルの終了
       </panel>     ← パネルの終了
       </row>       ← 行の終了
       </dashboard> ← ダッシュボードの終了
    

    🎯 まとめ: 処理の全体フロー

    【1. 読み込み時】
    ダッシュボード読み込み
            ↓
    XMLパース(<search>、<html>などを解析)
            ↓
    SPLサーチ実行: makeresults → eval → table
            ↓
    【2. JavaScript処理】
    require() でモジュール読み込み
            ↓
    mvc.Components.get() でサーチ参照取得
            ↓
    results.on("data") でイベント登録
            ↓
    【3. データ取得時】
    サーチ完了 → "data"イベント発火
            ↓
    hasData() でデータ確認
            ↓
    rows, fields 取得
            ↓
    【4. 描画処理】
    container.innerHTML = '' で初期化
            ↓
    forEach でループ
      ├─ フィールドインデックス取得
      ├─ 値取得(deviceName, status, statusCode)
      ├─ statusClass 決定(switch文)
      ├─ shapeType 決定(index % 4)
      ├─ HTML文字列生成
      └─ container に追加
            ↓
    【5. 完成!】
    ┌─────────────────────────────────┐
    │ ■緑    ●黄    ▬赤    ▼灰     │
    │ サーバーA サーバーB 機器C データベースD │
    │ 正常    警告    異常    停止    │
    └─────────────────────────────────┘
    

    📚 用語集

    用語 意味 SPL Search Processing Language(Splunkのクエリ言語) eval 値を計算・設定するSPLコマンド case() 条件分岐を行うSPL関数 MVC Model-View-Controller(設計パターン) DOM Document Object Model(HTML要素の操作) Flexbox CSSのレイアウト手法 addEventListener イベント処理の登録 parseInt 文字列→整数の変換 innerHTML 要素の中身のHTML


    お疲れ様でした!🎊

    これで全コードの一行一行の意味が理解できたはずです!

    あなたへのおすすめ