5.20241.9

OLAP:ピボットグリッドのカスタム表示

カスタムセル

PivotGridFlexGridコントロールの拡張です。したがって、formatItemイベントを使用し、各セルのコンテンツを完全に自由に変更して、グリッドセルの表示をカスタマイズできます。

下のPivotGridは、Microsoft Excelのアイコンセットと同様の色とアイコンを使用して、四半期ごとの売上高の変化を示しています。

PivotGridセルのカスタマイズ

var pivotGrid = new wjOlap.PivotGrid('#pivotGrid', {
    isReadOnly: true,
    itemsSource: ngFmt,
    formatItem: formatItem // グリッドセルをカスタマイズします
});

function formatItem(s, e) {

    // セルパネルに注目します
    if (e.panel == s.cells) {

        // デフォルトでカスタム色を削除します
        var color = '';

        // カスタム書式設定がオンのときに、差の列を書式設定します
        if (e.col % 2 == 1 && customCells.checked) {
            var value = s.getCellData(e.row, e.col),
            glyph = 'circle',
            span = ' <span style="font-size:120%" class="wj-glyph-{glyph}"></span>';
            color = '#d8b400';
            if (value != null) {
                if (value < 0) { // 負の場合
                    color = '#9f0000';
                    glyph = 'down';
                } else if (value > 0.05) { // 正の場合
                    color = '#4c8f00';
                    glyph = 'down';
                }
                e.cell.innerHTML += span.replace('{glyph}', glyph);
            }
        }

        // セルの色を適用します
        e.cell.style.color = color;
    }
}

スパークライン

formatItemイベントを使用して、スパークラインやスパークバーなどのカスタムコンテンツをグリッドセルに追加することもできます。

この例では、PivotEngineに2つのフィールドを追加し、formatItemイベントを使用し、これらのフィールドにスパークラインとスパークバーを追加します。

このために、サンプルはエンジンのgetDetailメソッドを使用して、各セルの詳細レコードを取得し、そのデータを使用して各セルに表示されるSVG要素を構築します。セルの詳細は、グリッドをスクロールしたときに再利用できるように、データ項目に保存されます。

ピボットグリッドのスパークライン

例については、ピボットグリッドスパークラインのデモを参照してください。

var pivotGrid = new wjOlap.PivotGrid('#pivotGrid', {
    isReadOnly: true,
    itemsSource: ng,
    formatItem: formatItem // グリッドセルをカスタマイズします
});

// formatItemを使用して、スパークライン/スパークバーを追加します
var maxSparkLength = 25;
function formatItem(s, e) {

    // セルパネルに注目します
    if (e.panel == s.cells) {

        // 'スパークライン'および'スパークバー'値フィールドが必要です
        var ng = s.engine,
            field = ng.valueFields[e.col % ng.valueFields.length],
            item = s.rows[e.row].dataItem,
            binding = s.columns[e.col].binding,
            spark = field.header == 'スパークライン' || field.header == 'スパークバー';

        // sparkクラスを追加/削除します
        wijmo.toggleClass(e.cell, 'spark', spark);

        // スパークラインを追加します
        if (spark) {

            // データがある場合は表示します
            if (item.sparkData) {
                var data = item.sparkData,
                    delta = data[data.length -1] - data[0];
                e.cell.innerHTML = field.header == 'スパークライン' ? getSparklines(item.sparkData) : getSparkbars(item.sparkData);
                wijmo.toggleClass(e.cell, 'spark-up', delta > 0);
                wijmo.toggleClass(e.cell, 'spark-down', delta < 0);
            }

            // まだデータがない場合は取得します
            if (!item.sparkData) {
                e.cell.innerHTML = '';
                setTimeout(function() {
                    var detail = s.engine.getDetail(item, binding),
                        len = detail.length;
                    if (len > maxSparkLength) {
                        detail = detail.slice(len - maxSparkLength);
                    }
                    item.sparkData = detail.map(function(dataItem) {
                        return dataItem.sales;
                    });
                    s.invalidate(); // 無効化してスパークラインを表示します
                });
            }
        }
    }
}

// スパークラインを表すSVGを生成します
function getSparklines(data) {
    var svg = '<svg width="100%" height="100%">',
        min = Math.min.apply(Math, data),
        max = Math.max.apply(Math, data),
        x1 = 0,
        y1 = scaleY(data[0], min, max);
    for (var i = 1; i < data.length; i++) {
        var x2 = Math.round((i) / (data.length - 1) * 100),
            y2 = scaleY(data[i], min, max);
        svg += '<line x1=' + x1 + '% y1=' + y1 + '% x2=' + x2 + '% y2=' + y2 + '% />';
        x1 = x2;
        y1 = y2;
    }
    svg += '</svg>';
    return svg;
}
function getSparkbars(data) {
    var svg = '<svg width="100%" height="100%">',
        min = Math.min.apply(Math, data),
        max = Math.max.apply(Math, data),
        base = Math.min(max, Math.max(min, 0)),
        basey = scaleY(base, min, max),
        w = Math.round(100 / data.length) - 2;
    for (var i = 0; i < data.length; i++) {
        var x = i * Math.round(100 / data.length) + 1,
            y = scaleY(data[i], min, max);
        svg += '<rect x=' + x + '% width=' + w + '% y=' + Math.min(y, basey) + '% height=' + Math.abs(y - basey) + '% />';
    }
    svg += '<rect x=0% width=100% height=1 y=' + basey + '% opacity=.5 />';
    svg += '</svg>';
    return svg;
}
function scaleY(value, min, max) {
    return 100 - Math.round((value - min) / (max - min) * 100);
}

HTMLコンテンツ

PivotFieldisContentHtmlプロパティを使用して、プレーンテキストの代わりにHTMLを含むフィールドをレンダリングします。

たとえば、以下の「担当者」フィールドと「分類」フィールドは、HTMLテキストを含むプロパティに連結されます。

[
    {
        date: new Date(2019, 0, 1),
        buyer: '<span class="initial">N</span>成宮 真紀',
        type: '<span class="initial">V</span>ビデオ',
        amount: 74
    },
    {
        date: new Date(2019, 0, 15),
        buyer: '<span class="initial">N</span>成宮 真紀',
        type: '<span class="initial">F</span>食品',
        amount: 235
    },
    {
        date: new Date(2019, 0, 17),
        buyer: '<span class="initial">Y</span>山本 雅治',
        type: '<span class="initial">H</span>家電',
        amount: 20
    },
    {
        date: new Date(2019, 0, 21),
        buyer: '<span class="initial">K</span>加藤 泰江',
        type: '<span class="initial">B</span>本',
        amount: 125
    },
    {
        date: new Date(2019, 1, 2),
        buyer: '<span class="initial">N</span>成宮 真紀',
        type: '<span class="initial">F</span>食品',
        amount: 235
    },
    {
        date: new Date(2019, 1, 20),
        buyer: '<span class="initial">K</span>加藤 泰江',
        type: '<span class="initial">M</span>音楽',
        amount: 20
    },
    {
        date: new Date(2019, 1, 25),
        buyer: '<span class="initial">K</span>加藤 泰江',
        type: '<span class="initial">P</span>パソコン',
        amount: 125
    },
];

コンテンツでHTMLをレンダリングするには、isContentHTMLtrueに設定します。

var ng = new wjOlap.PivotEngine({
    itemsSource: getData(), // 生データ
    valueFields: ['金額'], // 金額を集計します
    rowFields: ['担当者', '分類'] // 金額を集計します
});

ng.fields.getField('担当者').isContentHtml = true;
ng.fields.getField('分類').isContentHtml = true;
Result

isContentHTML