🌟

WebFOCUS拡張グラフ開発に役立つpvオブジェクト

2025/03/07に公開

pvオブジェクト仕様書

pvオブジェクトはWebFOCUSの拡張グラフ開発で使用されるユーティリティライブラリです。このオブジェクトは、グラフの描画やデータ操作を支援する様々なプロパティとメソッドを提供します。

プロパティ

pv.version

バージョン情報を格納するオブジェクト。

{
    major: 3,
    minor: 2
}

pv.color

色の処理を行うユーティリティ関数。tdgchart.util.colorへの参照。
WebFOCUSグラフの色を操作する際に使用します。

// 色を取得し明るくする例
var color = pv.color("blue");
var lighterColor = color.lighter(0.2);

pv.Scene

SVGシーン(描画領域)を操作するためのオブジェクト。pv.SvgSceneへの参照。

pv.Mark

視覚的な要素(マーク)を描画するためのベースクラス。
グラフ要素(棒、線、点など)の基本クラスとして機能します。

pv.Transform

座標変換を行うためのユーティリティクラス。

pv.Scale

データ値をビジュアル属性(位置や色など)にマッピングするためのスケール関数を提供します。

// スケール関数を作成して使用する例
var x = pv.Scale.ordinal().domain(pv.range(seriesCount)).rangeRoundBands([0, w], 0.2);
var y = pv.Scale.linear().domain([0, ymax]).range([25, h]);

pv.Behavior

マウスイベントなどのインタラクション動作を定義するためのユーティリティオブジェクト。

メソッド

pv.range(start, stop, step)

連続した数値の配列を生成します。

パラメータ

  • start (number, オプション): 開始値。省略した場合は0から開始。
  • stop (number): 終了値(この値は結果に含まれない)
  • step (number, オプション): ステップ幅。省略した場合は1。

戻り値

(Array): 連続した数値の配列

使用例

// 0から9までの配列を生成
var array = pv.range(10);
// 結果: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

// 5から10までの配列を生成
var array = pv.range(5, 10);
// 結果: [5, 6, 7, 8, 9]

// 0から10までの2刻みの配列を生成
var array = pv.range(0, 10, 2);
// 結果: [0, 2, 4, 6, 8]

pv.extend(functionObj)

指定したコンストラクタ関数のプロトタイプを拡張します。
継承の仕組みを実現するためのメソッドです。

パラメータ

  • functionObj (Function): 拡張するコンストラクタ関数

戻り値

(Object): 拡張されたプロトタイプオブジェクト

使用例

// カスタム棒グラフ要素を作成する例
var CustomBar = function() {};
CustomBar.prototype = pv.extend(pv.Bar);
CustomBar.prototype.customMethod = function() {
    // カスタム機能を実装
};

pv.blend(arrays)

複数の配列を1つの配列に結合します。特に多次元配列を1次元配列に平坦化するために使用されます。

パラメータ

  • arrays (Array[]): 結合する配列の配列

戻り値

(Array): 結合された単一の配列

使用例

// 複数のデータ配列を1つに結合する
var array1 = [1, 2, 3];
var array2 = [4, 5, 6];
var array3 = [7, 8, 9];

var blended = pv.blend([array1, array2, array3]);
// 結果: [1, 2, 3, 4, 5, 6, 7, 8, 9]

// WebFOCUS拡張グラフでの使用例(一意なラベルの取得)
var axisLabels = pv.blend(data).map(function(el) {return el.labels;}).filter(function() {
    var seen = {};
    return function(el) {
        return el != null && !(el in seen) && (seen[el] = 1);
    };
}());

pv.search(array, value)

ソート済み配列内で指定した値の位置を二分探索で検索します。

パラメータ

  • array (Array): ソート済みの配列
  • value (any): 検索する値

戻り値

(number): 見つかった場合はその位置のインデックス、見つからなかった場合は挿入すべき位置を示す負の数

使用例

// ソート済み配列から値を検索する
var array = [10, 20, 30, 40, 50];
var index = pv.search(array, 30);
// 結果: 2(値30は配列の3番目の要素)

var index = pv.search(array, 35);
// 結果: -4(値35は配列の要素3と4の間に挿入すべき)

pv.vector(x, y)

2Dベクトルを作成します。

パラメータ

  • x (number): X座標
  • y (number): Y座標

戻り値

(pv.VectorClass): 新しいベクトルオブジェクト

使用例

// ベクトルを作成して操作する
var v1 = pv.vector(3, 4);
var length = v1.length();  // 5

// 別のベクトルとの演算
var v2 = pv.vector(1, 2);
var sum = v1.plus(v2);  // {x: 4, y: 6}

pv.log(x, b)

指定した底による対数を計算します。

パラメータ

  • x (number): 対数を計算する値
  • b (number, オプション): 底。省略した場合は10

戻り値

(number): 計算された対数値

使用例

// 対数スケールの計算
var log10 = pv.log(100);      // 2
var log2 = pv.log(8, 2);      // 3

pv.functor(v)

値または関数を関数として扱えるようにラップします。
値が関数ならそのまま返し、そうでなければ値を返す関数を作成します。

パラメータ

  • v (any): 値または関数

戻り値

(Function): 引数を無視して値を返す関数、またはそのまま渡された関数

使用例

// 定数または関数としてサイズを定義
var staticSize = pv.functor(5);
staticSize();  // 5が返る

var dynamicSize = pv.functor(function(d) { return d.size; });
dynamicSize({size: 10});  // 10が返る

pv.listener(f)

イベントリスナー関数をラップして標準化します。

パラメータ

  • f (Function): ラップする関数

戻り値

(Function): 標準化されたイベントリスナー関数

使用例

// イベントリスナーを作成する
var clickHandler = pv.listener(function(event) {
    console.log("クリックされました:", event);
});

// 作成したリスナーを要素に追加
pv.listen(someElement, "click", clickHandler);

高度な使用例

カスタムマーカーの作成と使用

// カスタム六角形マーカーを作成
function createHexagonMarker(container, size, color) {
  const dot = container.append("path")
    .attr("d", function() {
      const r = size;
      // 六角形の頂点を計算
      return "M" + r + ",0" + 
             "L" + r * Math.cos(Math.PI/3) + "," + r * Math.sin(Math.PI/3) + 
             "L" + r * Math.cos(2*Math.PI/3) + "," + r * Math.sin(2*Math.PI/3) + 
             "L" + (-r) + ",0" + 
             "L" + r * Math.cos(4*Math.PI/3) + "," + r * Math.sin(4*Math.PI/3) + 
             "L" + r * Math.cos(5*Math.PI/3) + "," + r * Math.sin(5*Math.PI/3) + 
             "Z";
    })
    .attr("fill", color);
    
  return dot;
}

// 使用例
const container = d3.select(renderConfig.container);
const markers = container.selectAll("g")
  .data(data)
  .enter().append("g")
  .attr("transform", function(d) { return "translate(" + x(d.x) + "," + y(d.y) + ")"; });

markers.each(function(d) {
  createHexagonMarker(d3.select(this), d.size, pv.color(d.color).darker(0.2));
});

データの変換と操作

// データを転置して処理する
function processData(data) {
  // 2次元配列を転置する
  const transposed = pv.blend(data).map(function(el) {
    return el.labels;
  }).filter(function() {
    // 重複を除去
    const seen = {};
    return function(el) {
      return el != null && !(el in seen) && (seen[el] = 1);
    };
  }());
  
  return transposed;
}

スケールの使用

// カスタム座標軸スケールの作成
function createCustomScale(data, width, height) {
  // X軸の順序スケール
  const x = pv.Scale.ordinal()
    .domain(pv.range(data.length))
    .rangeRoundBands([0, width], 0.2);
    
  // Y軸の線形スケール
  const ymax = pv.blend(data).reduce(function(max, d) {
    return Math.max(max, d.value);
  }, 0);
  
  const y = pv.Scale.linear()
    .domain([0, ymax])
    .range([0, height]);
    
  return {x: x, y: y};
}

カラー操作

// グレーを取得し、より明るいバージョンを作成する
var grey = renderConfig.baseColor;
renderConfig.moonbeamInstance.getSeries(0).color = grey;
renderConfig.moonbeamInstance.getSeries(1).color = pv.color(grey).lighter(0.18).color;

データの変換と集計

// データを収集して処理する
splitYData.forEach(function(el) {
    el.forEach(function(stack) {
        var acc = 0;
        stack.forEach(function(d) {
            d.y0 = acc;
            d.y1 = acc + d.value;
            acc += d.value;
        });
    });
});

一意な値のフィルタリング

// データセットから一意なラベルを抽出する
var axisLabels = pv.blend(data).map(function(el) {return el.labels;}).filter(function() {
    var seen = {};
    return function(el) {
        return el != null && !(el in seen) && (seen[el] = 1);
    };
}());

ビジュアル要素の位置計算

// スケールを使用して位置を計算
var xLabelHeight = 25;
var yHeight = (h - xLabelHeight) / splitYCount;
var x = d3.scale.ordinal().domain(axisLabels).rangeRoundBands([xLabelHeight, w - 25], 0.2);
var yScaleList = splitYData.map(function(el) {
    var ymax = d3.max(el.map(function(a) { return d3.sum(a, function(d) {return d.value;}); }));
    return d3.scale.linear().domain([0, ymax]).range([yHeight, 20]);
});

これらのメソッドを使用することで、WebFOCUSの拡張グラフを効率的かつ柔軟に開発することができます。

Discussion