0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

重なったポイントのうち一つだけラベルを表示して、それ以外のラベルを非表示にする方法

Posted at

重なりが発生した場合に、重なったポイントのうち一つだけラベルを表示して、それ以外のラベルを非表示にする方法について説明します。このような処理を実現するには、ポイント間の距離を計算して重なりを検出し、特定の条件に基づいてラベルを表示するかどうかを制御します。

以下に、JavaScriptとWijmoのFlexChartを使用した実装例を示します。


解法:ラベルの重なりを検出して表示を制御する

  1. ポイント間の距離を計算
    各データポイントのx座標とy座標を取得し、距離を計算します。

  2. 近すぎるポイントを検出
    計算した距離が特定の閾値以下の場合、それを「重なり」とみなします。

  3. ラベルを制御
    重なりが発生したポイントの中で、1つだけラベルを表示します。


コード例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Label Overlap Handling</title>
    <link rel="stylesheet" href="https://cdn.grapecity.com/wijmo/5.latest/styles/wijmo.min.css" />
    <script src="https://cdn.grapecity.com/wijmo/5.latest/controls/wijmo.min.js"></script>
    <script src="https://cdn.grapecity.com/wijmo/5.latest/controls/wijmo.chart.min.js"></script>
</head>
<body>
    <div id="chart" style="width: 800px; height: 400px;"></div>
    <script>
        // サンプルデータ
        var data = [
            { x: 10, y: 20 },
            { x: 15, y: 25 },
            { x: 15, y: 25.5 }, // 重なるデータポイント
            { x: 20, y: 30 },
            { x: 25, y: 35 },
        ];

        // FlexChartの作成
        var chart = new wijmo.chart.FlexChart('#chart', {
            itemsSource: data,       // データソース
            bindingX: 'x',           // X軸のデータ
            series: [
                { name: 'Data Points', binding: 'y', chartType: 'Scatter' }
            ],
            axisX: { title: 'X Axis' },
            axisY: { title: 'Y Axis' },
            dataLabel: {
                content: function (ht) {
                    // 重なり検出ロジック
                    const threshold = 5; // 重なり検出の閾値(ピクセル単位)
                    const isOverlapping = checkOverlap(ht, threshold);

                    // 重なっていない、または最初のポイントの場合のみラベルを表示
                    return isOverlapping ? '' : `(${ht.x}, ${ht.y})`;
                },
                position: 'Top', // ラベルの位置を指定
                style: {
                    fontSize: '10px',
                    fill: 'blue'
                }
            }
        });

        // 重なり検出関数
        function checkOverlap(ht, threshold) {
            const series = chart.series[0]; // チャートのシリーズ
            const index = ht.pointIndex;    // 現在のデータポイントのインデックス
            const data = chart.itemsSource; // データソース
            const current = data[index];    // 現在のデータポイント

            for (let i = 0; i < data.length; i++) {
                if (i === index) continue; // 自分自身を比較しない
                const point = data[i];
                const dx = Math.abs(current.x - point.x); // X座標の差
                const dy = Math.abs(current.y - point.y); // Y座標の差
                const distance = Math.sqrt(dx * dx + dy * dy); // 距離を計算

                if (distance < threshold) {
                    // 距離が閾値未満の場合、重なりが発生
                    return true;
                }
            }
            return false;
        }
    </script>
</body>
</html>

コード解説

  1. ラベルのカスタム関数

    • dataLabel.content内で、ポイントごとに重なりをチェックします。
    • 重なりが検出された場合、ラベルを非表示('')にします。
  2. checkOverlap関数

    • 指定された閾値(threshold)未満の距離で、ポイント間の重なりを判定します。
    • 他のポイントとの距離を計算し、重なっているかどうかを返します。
  3. 閾値の設定

    • thresholdは、重なりの感度を調整するためのピクセル単位の距離です。
    • この値を調整することで、重なりの検出範囲を広げたり狭めたりできます。
  4. データポイントごとの表示制御

    • return isOverlapping ? '' : 'ラベル内容'で、重なりがある場合にはラベルを非表示にします。

改善のポイント

  • 最初のデータポイントを優先して表示

    • 同じ距離のポイントが複数あった場合、最初のポイントのラベルのみ表示するロジックを実装する。
  • カスタム引き出し線を使用

    • ラベルを少し離して配置し、データポイントとラベルを引き出し線で接続することで見やすさを向上。

応用

  • このロジックを複数シリーズ(series)に適用可能。
  • 動的にデータを変更しても、自動的にラベルの重なりを回避できます。

不明点や追加のカスタマイズについて、遠慮なくお知らせください!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?