2016年2月27日 星期六

不同量級的數值在同一個圖表上呈現

標題好難下,完整的標題應該是:

在 GXT Chart 中,如何把兩個不同量級的數值在同一個圖表中都用長條圖當中呈現。

拿這張圖表來舉例說明:

死亡人數的數值區間是 0~5、死亡率的數值區間是 0~0.00473,所以基本上這兩個數值不可能掛在同一個 axis 上,不然死亡率各個 bar 的高度很難超過 1px。

如果不堅持都用長條圖(BarSeries)顯示,那也沒啥問題,在 GXT Explorer 的 Mixed Chart 就有展示。作法就是死亡人數掛在左邊的 axis、死亡率掛在右邊的 axis,這樣高度就會各自獨立。但是,就像銅鑼灣只有一個浩男圖表上只有能一個 BarSeries,如果兩個都用 BarSeries,就會變成其中一個長條把另一個長條給蓋住的狀態。

這個時候就需要 SeriesRendererbbox 的協助。

首先,Series 有個 method setRenderer()、可以重新定義 Series 當中每個 sprite 的設定值,也就是傳入參數 SeriesRendererspriteRenderer() 的實作內容。光是拿到 Sprite 的 instance 不夠,還得知道他預期的寬度,這樣才有辦法讓他少上一半。雖然有 Sprite.getWidth(),不過我還是選擇使用 Sprite.getBBox().getWidth() 比較保險。所以死亡人數(左邊的 bar)讓它只剩下原來的一半寬, SeriesRender 實作會長的像這樣:

new SeriesRenderer<Model>() {
    @Override
    public void spriteRenderer(Sprite sprite, int index, ListStore<Model> store) {
        RectangleSprite rs = (RectangleSprite) sprite;
        PreciseRectangle bb = rs.getBBox();
        rs.setWidth(bb.getWidth() / 2);
        rs.redraw();
    }
}

而死亡率(右邊的 bar)則要多加上 X 的偏移量:

rs.setX(bb.getX() + bb.getWidth() / 2);

至於長條上頭的文字,這就有一些目前還不明所以的黑魔法了…… 囧>

要讓 series 出現文字,是透過 Series.setLabelConfig() 傳入一個 SeriesLabelConfig。而 SeriesLabelConfig 則是用 setSpriteConfig() 傳入一個 Sprite 來決定顯示樣貌(沒有限定一定要是 TextSprite,所以如果給 ImageSprite 就會出現圖片)。所以在還沒有亂搞之前,製造 SeriesLabelConfig 的程式碼會是:

TextSprite spriteConfig = new TextSprite();
//字體大小 14、顏色黑色
spriteConfig.setFill(RGB.BLACK);
spriteConfig.setFontSize(14);

SeriesLabelConfig<Model> slc = new SeriesLabelConfig<>();
slc.setSpriteConfig(spriteConfig);

SeriesLabelConfig 跟其他 GXT Chart class 的設計思維一致,有 setLabelProvider() 重新定義顯示值、以及 setSpriteRenderer() 重新決定 sprite 的設定值(setSpriteConfig() 是寫辛酸的...)。

原本以為用同樣招數再搞一次 SeriesRenderer 就好,但是…

TextSprite 當下取得的 bbox 完全沒有數值
TextSprite 當下取得的 bbox 完全沒有數值
TextSprite 當下取得的 bbox 完全沒有數值…… Orz

(註:這一點還沒有重新作 SSCCE,在趕 case 的測試結果… [逃])

目前發現的 workaround 是對 spriteConfigsetTextAnchor(),死亡人數(左邊的 bar)是

spriteConfig.setTextAnchor(TextAnchor.END);

死亡率(右邊的 bar)是

spriteConfig.setTextAnchor(TextAnchor.START);

這樣字串就會神奇地落在各自的長條區域內,只是無法置中…… XD

最後再重新畫一次重點,這篇要解決的問題是要同時滿足下面三個條件:

  • 兩組數值
  • 兩種不同的數值範圍
  • 都要用長條圖呈現

沒有留言:

張貼留言