    001/*
    002 * Copyright (c) 2009 The openGion Project.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *     http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    013 * either express or implied. See the License for the specific language
    014 * governing permissions and limitations under the License.
    015 */
    016package org.opengion.hayabusa.io;
    017
    018import java.awt.Graphics2D;
    019import java.awt.Stroke;
    020import java.awt.Paint;
    021import java.awt.geom.Rectangle2D;
    022import java.util.List;
    023import java.util.Map;
    024import java.util.HashMap;
    025import java.util.Iterator;
    026
    027import org.jfree.chart.plot.CategoryPlot;
    028import org.jfree.chart.plot.PlotRenderingInfo;
    029import org.jfree.chart.urls.CategoryURLGenerator;
    030import org.jfree.chart.axis.CategoryAxis;
    031import org.jfree.chart.axis.ValueAxis;
    032import org.jfree.chart.axis.ValueTick;
    033import org.jfree.chart.renderer.category.CategoryItemRenderer;
    034import org.jfree.chart.renderer.category.CategoryItemRendererState;
    035import org.jfree.chart.renderer.category.StackedBarRenderer;
    036import org.jfree.data.category.CategoryDataset;
    037import org.jfree.data.general.DatasetUtilities;
    038
    039/**
    040 * HybsCategoryPlot は、CategoryPlot を拡張したカスタマイズクラスです。
    041 * これは、シリーズの表示色を変更する箇所で、描画順により、きれいに表示されない
    042 * 現象への対応案です。
    043 * 描画順を、最も最後に行うように、修正しています。
    044 *
    045 * renders each data item using a {@link CategoryItemRenderer}.
    046 *
    047 * @og.rev 3.8.9.2 (2007/07/28) 新規作成
    048 *
    049 * @version  0.9.0  2001/05/05
    050 * @author   Kazuhiko Hasegawa
    051 * @since    JDK1.1,
    052 */
    053public class HybsCategoryPlot extends CategoryPlot {
    054        private static final long serialVersionUID = 519020100801L ;
    055
    056        private final Map<Integer,Double> barWidths = new HashMap<Integer,Double>();    // 4.3.1.1 (2008/08/23) final化
    057        private int             serNo     = -1;
    058        private int             rangeSkip = 1;                  // 4.1.1.0 (2008/02/04) 縦軸のグリッドをスキップする間隔
    059        private final int hsCode = Long.valueOf( System.nanoTime() ).hashCode() ;       // 5.1.9.0 (2010/08/01) equals,hashCode
    060
    061        /**
    062         * デフォルトコンストラクター
    063         * シリーズ番号を、初期化しておきます。
    064         *
    065         **/
    066        public HybsCategoryPlot() {
    067                // 4.3.4.4 (2009/01/01)
    068                this( -1 );
    069        }
    070
    071        /**
    072         * シリーズ番号 を、指定して、オブジェクトを作成するコンストラクター
    073         *
    074         * @param       serNo   ピックアップするシリーズ番号
    075         **/
    076        protected HybsCategoryPlot( final int serNo ) {
    077                // 4.3.4.4 (2009/01/01)
    078                this.serNo = serNo;
    079        }
    080
    081        /**
    082         * ピックアップするシリーズ番号を設定します。
    083         *
    084         * @og.rev 4.1.1.0 (2008/02/04) データの値(itemText)表示の継承
    085         *
    086         * @param       newSerNo        ピックアップするシリーズ番号
    087         **/
    088        protected void setSeriesPikup( final int newSerNo ) {
    089                int oldSerNo = serNo ;
    090                serNo = newSerNo;
    091                CategoryItemRenderer rend = getRenderer();
    092                CategoryURLGenerator urlGen = rend.getSeriesItemURLGenerator( oldSerNo );
    093                if( urlGen != null ) {
    094                        rend.setSeriesItemURLGenerator( oldSerNo,null );
    095                        rend.setSeriesItemURLGenerator( serNo   ,urlGen );
    096                }
    097
    098                // 4.1.1.0 (2008/02/04) データの値(itemText)表示の継承
    099                if( rend.isSeriesItemLabelsVisible( oldSerNo ) ) {
    100                        rend.setSeriesItemLabelsVisible( oldSerNo,false );
    101                        rend.setSeriesItemLabelsVisible( serNo   ,true  );
    102                }
    103        }
    104
    105        /**
    106         * 縦軸のグリッド線(水平線)をスキップする間隔を指定します。
    107         *
    108         * 縦軸のグリッド線を表示する際に、スキップする間隔を指定します。
    109         * 通常は、ラベルと同じだけのグリッド線が掛かれますが、ラベルよりも
    110         * 少ない数のグリッド線(例えば、２つおき)を出す場合に、値を設定します。
    111         * "1" (初期値)では、１つづつ表示(つまり、すべて表示する)します。
    112         * "2" とすると、１つおきに、"3" とすると、２つおきに表示します。
    113         * 初期値は、"1" (すべて表示)です。
    114         * なお、先頭から表示を開始します。
    115         *
    116         * @og.rev 4.1.1.0 (2008/02/04) 新規追加
    117         *
    118         * @param       rngSkip 縦軸のグリッド線(水平線)をスキップする間隔
    119         */
    120        protected void setRangeSkip( final int rngSkip ) {
    121                rangeSkip = rngSkip;
    122        }
    123
    124        /**
    125         * BarChart のバーの幅を直接指定します。
    126         * 通常は、maxBarWidth や itemMargin で比率指定しますが、
    127         * ここでは、CategoryItemRendererState オブジェクトに直接設定する為の
    128         * データセット単位のマップを作成します。
    129         *
    130         * @param       index   データセット番号
    131         * @param       width   バーの幅
    132         **/
    133        protected void setBarWidth( final int index,final Double width ) {
    134                barWidths.put( index,width );
    135        }
    136
    137        /**
    138         * Draws a representation of a dataset within the dataArea region using the
    139         * appropriate renderer.
    140         *
    141         * @param g2  the graphics device.
    142         * @param dataArea      the region in which the data is to be drawn.
    143         * @param index  the dataset and renderer index.
    144         * @param info  an optional object for collection dimension information.
    145         *
    146         * @return      描画するデータが見つかった場合は、true
    147         */
    148        public boolean render( final Graphics2D g2, final Rectangle2D dataArea, final int index,
    149                                                  final PlotRenderingInfo info ) {
    150                boolean foundData = false;
    151                CategoryDataset currentDataset = getDataset(index);
    152                CategoryItemRenderer renderer = getRenderer(index);
    153                // 4.3.1.0 (2008/08/19) 軸とデータセットのマッピング
    154                this.mapDatasetToRangeAxis( index, index );
    155
    156                CategoryAxis domainAxis = null ;
    157                if( renderer instanceof StackedBarRenderer ) {
    158                        domainAxis = getDomainAxis(index);
    159                }
    160                else {
    161                        domainAxis = getDomainAxisForDataset(index);
    162                }
    163
    164                ValueAxis rangeAxis = getRangeAxis(index);
    165                boolean hasData = !DatasetUtilities.isEmptyOrNull(currentDataset);
    166                if(hasData && renderer != null) {
    167                        foundData = true;
    168                        CategoryItemRendererState state = renderer.initialise(g2, dataArea,
    169                                        this, index, info);
    170
    171                        // 4.0.3.0 (2008/01/07) 棒グラフのバー幅指定
    172                        Double bwidth = barWidths.get( index );
    173                        if( bwidth != null ) { state.setBarWidth( bwidth.doubleValue() ); }
    174
    175                        if( renderer instanceof HybsDrawItem ) {
    176                                ((HybsDrawItem)renderer).drawItem2(g2, state, dataArea, this,
    177                                                domainAxis, rangeAxis, currentDataset , serNo );
    178                        }
    179                        else {
    180                                int columnCount = currentDataset.getColumnCount();
    181                                int rowCount = currentDataset.getRowCount();
    182                                int passCount = renderer.getPassCount();
    183                                for( int pass=0; pass<passCount; pass++ ) {
    184                                        for( int column=0; column<columnCount; column++ ) {
    185                                                for( int row=0; row<rowCount; row++ ) {
    186                                                        if( row == serNo ) { continue; }        // Mis Add 2007/07/23
    187                                                        renderer.drawItem(g2, state, dataArea, this,
    188                                                                        domainAxis, rangeAxis, currentDataset,
    189                                                                        row, column, pass);
    190                                                }
    191                                                // 指定のシリーズと一致する場合は、最後に描画する。 Mis Add 2007/07/23
    192                                                if( serNo >= 0 ) {
    193                                                        renderer.drawItem(g2, state, dataArea, this,
    194                                                                        domainAxis, rangeAxis, currentDataset,
    195                                                                        serNo, column, pass);
    196                                                }
    197                                        }
    198                                }
    199                        }
    200                }
    201                return foundData;
    202        }
    203
    204        /**
    205         * Draws the gridlines for the plot.
    206         *
    207         * @param g2  the graphics device.
    208         * @param dataArea      the area inside the axes.
    209         * @param ticks  the ticks.
    210         *
    211         * @see #drawDomainGridlines(Graphics2D, Rectangle2D)
    212         */
    213        @SuppressWarnings("rawtypes")
    214        protected void drawRangeGridlines( final Graphics2D g2, final Rectangle2D dataArea,
    215                                                                           final List ticks ) {
    216                // draw the range grid lines, if any...
    217
    218                if (isRangeGridlinesVisible()) {
    219                        Stroke gridStroke = getRangeGridlineStroke();
    220                        Paint gridPaint = getRangeGridlinePaint();
    221                        if ( gridStroke != null && gridPaint != null ) {
    222                                ValueAxis axis = getRangeAxis();
    223                                CategoryItemRenderer renderer1 = getRenderer();
    224                                if (axis != null && renderer1 != null) {
    225                                        Iterator<?> iterator = ticks.iterator();
    226                                        int cnt = 0;
    227                                        while (iterator.hasNext()) {
    228                                                ValueTick tick = (ValueTick) iterator.next();
    229                                                if( cnt % rangeSkip == 0 ) {
    230                                                        renderer1.drawRangeGridline(g2, this,
    231                                                                                axis, dataArea, tick.getValue());
    232                                                }
    233                                                cnt++ ;
    234                                        }
    235                                }
    236                        }
    237                }
    238        }
    239
    240        /**
    241         * この文字列と指定されたオブジェクトを比較します。
    242         *
    243         * 親クラスで、equals メソッドが実装されているため、警告がでます。
    244         *
    245         * @og.rev 5.1.8.0 (2010/07/01) findbug対応
    246         * @og.rev 5.1.9.0 (2010/08/01) findbug対応
    247         *
    248         * @param       object  比較するオブジェクト
    249         *
    250         * @return      Objectが等しい場合は true、そうでない場合は false
    251         */
    252        @Override
    253        public boolean equals( final Object object ) {
    254                if( super.equals( object ) ) {
    255                        return hsCode == ((HybsCategoryPlot)object).hsCode;
    256                }
    257                return false;
    258        }
    259
    260        /**
    261         * このオブジェクトのハッシュコードを取得します。
    262         *
    263         * @og.rev 5.1.8.0 (2010/07/01) findbug対応
    264         * @og.rev 5.1.9.0 (2010/08/01) findbug対応
    265         *
    266         * @return      ハッシュコード
    267         */
    268        @Override
    269        public int hashCode() { return hsCode ; }
    270}