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

Wijmo(FlexChart)の標準機能として「ラベル同士の重なりを自動的に検知して非表示にする」ための直接的なプロパティはありません。

しかし、dataLabel.positionAuto に設定することで、ある程度自動的にラベル位置を調整することが可能です。さらに、rendered イベントなどを用いてラベルの座標を取得・判定することで、重なりを検知して個別に非表示にするカスタマイズが実現できます。


以下、要件を満たすためのステップを順に解説します。


1. ラベル位置をデータポイントの位置に応じて変える方法

1.1 dataLabel.position プロパティでの自動配置

Wijmoの FlexChart には、ラベルの表示位置を指定するための列挙型 Position が用意されています。主な値は以下のとおりです。

  • None
  • Left
  • Top
  • Right
  • Bottom
  • Center
  • Auto ← これを指定すると、チャート自身がラベルの位置をある程度調整してくれる

まずは、散布図の Series に対して dataLabel を有効にし、positionAuto に設定する例です:

// 例)FlexChartを生成して series を設定する場合
var chart = new wijmo.chart.FlexChart('#theChart', {
  itemsSource: myData,
  chartType: wijmo.chart.ChartType.Scatter,
  bindingX: 'x',
  series: [
    {
      name: 'SampleSeries',
      binding: 'y',
      dataLabel: {
        content: '{y}',        // ラベルに表示するテキスト
        position: wijmo.chart.Position.Auto, // 自動調整
      }
    }
  ]
});

Auto を指定すると、ある程度ラベルの重なりが軽減される場合があります。しかし、非常に近いデータポイントが多いと、完全には重なりを避けられないケースも出てきます。

1.2 ラベルの表示内容を動的に切り替える

散布図の場合、たとえば X 座標が一定以上ならラベルを右側、それ以下なら左側に寄せたいというような使い分けをしたいときがあります。その場合は、dataLabel.content にコールバック関数を指定して、各データポイントの値によってラベルの表示位置を切り替えます。

ただし「ラベル位置(Top/Left 等)」自体は dataLabel.position 単位でしか設定できず、データポイントごとに切り替える標準APIはありません。代わりに

  1. dataLabel.positionAutoTop 等に設定しておく
  2. もしくは後述の「renderingイベントで自前カスタマイズ」を行う

のいずれかになります。

もし「特定の条件下ではラベルそのものを表示しない」だけなら、content 関数内で null を返せば対応できます。

dataLabel: {
  content: function (ht) {
    // ht はヒットテスト情報
    if (ht.item.x > 50) {
      return ht.item.y; // 例えばデータが大きい時だけ y 値を表示
    } else {
      return null;      // それ以外は表示しない
    }
  },
  position: wijmo.chart.Position.Auto,
}

2. 近くにあるデータポイントのラベル同士が重なる場合に非表示にする方法

2.1 結論

標準API (プロパティ) だけで「自動的に重なりを検知して非表示にする」仕組みは提供されていません。
ラベルが非常に多い、あるいはデータポイントが密集しているケースでは、rendered イベント もしくは rendering イベント で SVG 要素を直接操作し、重なりを検知して個別にラベルを隠す(または配置を修正する)という実装が必要です。

2.2 rendered イベントでのカスタム実装例

rendered イベントは、チャート描画完了後に呼ばれるイベントです。ここで、描画済みのラベル (SVG の <text> 要素) を取得し、各ラベルのバウンディングボックスが重なるかを判定して重なるものを非表示にできます。

chart.rendered.addHandler(function(sender, args) {
  // 全てのデータラベル(text要素)を取得
  var labels = sender.hostElement.querySelectorAll('text.wj-data-label');
  
  // ラベルのバウンディングボックスを格納する配列
  var labelRects = [];

  labels.forEach(function(lbl) {
    // 現在の <text> 要素の位置とサイズを取得 (getBBoxはSVG専用)
    var rect = lbl.getBBox();
    
    // 2つのラベルが重なっているかを判定する関数
    var isOverlap = labelRects.some(function(r) {
      return !(
        r.x + r.width  < rect.x        ||
        rect.x + rect.width  < r.x     ||
        r.y + r.height < rect.y        ||
        rect.y + rect.height < r.y
      );
    });
    
    // 重なっていれば非表示にする
    if (isOverlap) {
      lbl.setAttribute('visibility', 'hidden');
    } else {
      // 重なっていなければ、後続の判定用に追加
      labelRects.push(rect);
    }
  });
});

上記はシンプルなサンプルですが、次のような注意が必要です。

  1. 重なり判定を厳密にする
    たとえばラベルの余白を考慮したり、多少の近接は許容したりする場合は工夫が必要になります。

  2. 配置自体を動かす場合
    今回は「重なったらラベルを隠す」だけですが、位置をずらす場合は <text> 要素の x, y 属性をいじる必要があり、さらに相互に影響し合うため実装が複雑になります。

  3. rendering イベントとの使い分け
    rendering イベントだと、まだ描画処理の途中段階になるため、engine オブジェクトを使ってラベルを出力するタイミングで制御できます。ただし自力で描画する処理を書くことになりがちなので、より高度な実装になります。
    シンプルにやるなら、すでに生成された SVG 要素に対して最終調整を行う rendered イベントのほうがわかりやすいことが多いです。


まとめ

  1. ラベルの位置調整

    • dataLabel.position = Position.Auto を利用すれば、ある程度チャート側で自動的にラベル位置を振り分けてくれます。
    • それ以上にデータごとにきめ細かく位置を切り替えたい場合は、rendered イベントでラベルを直接操作するなどのカスタマイズが必要になります。
  2. 重なり防止

    • 標準プロパティ(例: chart.dataLabel.overlapping)のようなものは用意されていないため、自力で重なりを判定して非表示にする仕組みを組むのが現状の方法です。
    • サンプルのように rendered イベントで SVG <text> 要素の位置関係を調べ、重なったラベルを非表示にする実装例が典型です。
  3. 複雑さを抑えるポイント

    • まずは position: 'Auto' と必要に応じて content コールバックを使い、ある程度の位置調整や不要ラベルの非表示を行う。
    • ラベルの重なりが顕著になった場合のみ、rendered イベントでさらに制御するアプローチを検討する。

こうした手順で、できるだけ Wijmo の標準機能を活かしつつ要件に近い挙動を実現できます。

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?