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.Color; 022import java.awt.geom.Rectangle2D; 023import java.util.List; 024import java.util.concurrent.ConcurrentMap; // 6.4.3.3 (2016/03/04) 025import java.util.concurrent.ConcurrentHashMap; // 6.4.3.1 (2016/02/12) refactoring 026import java.util.Iterator; 027 028import org.jfree.chart.plot.CategoryPlot; 029import org.jfree.chart.plot.PlotRenderingInfo; 030import org.jfree.chart.plot.CategoryCrosshairState; 031import org.jfree.chart.urls.CategoryURLGenerator; 032import org.jfree.chart.axis.CategoryAxis; 033import org.jfree.chart.axis.ValueAxis; 034import org.jfree.chart.axis.ValueTick; 035import org.jfree.chart.renderer.category.CategoryItemRenderer; 036import org.jfree.chart.renderer.category.CategoryItemRendererState; 037import org.jfree.chart.renderer.category.StackedBarRenderer; 038import org.jfree.data.category.CategoryDataset; 039import org.jfree.data.general.DatasetUtilities; 040 041/** 042 * HybsCategoryPlot は、CategoryPlot を拡張したカスタマイズクラスです。 043 * これは、シリーズの表示色を変更する箇所で、描画順により、きれいに表示されない 044 * 現象への対応案です。 045 * 描画順を、最も最後に行うように、修正しています。 046 * 047 * renders each data item using a {@link CategoryItemRenderer}. 048 * 049 * @og.rev 3.8.9.2 (2007/07/28) 新規作成 050 * 051 * @version 0.9.0 2001/05/05 052 * @author Kazuhiko Hasegawa 053 * @since JDK1.1, 054 */ 055public class HybsCategoryPlot extends CategoryPlot { 056 private static final long serialVersionUID = 602020140919L ; 057 058 /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。 */ 059 private final ConcurrentMap<Integer,Double> barWdMap = new ConcurrentHashMap<>(); // 6.4.3.1 (2016/02/12) 060 private int serNo = -1; 061 private int rangeSkip = -1; // 4.1.1.0 (2008/02/04) 縦軸のグリッドをスキップする間隔(初期値:-1) 062 private final int hsCode = Long.valueOf( System.nanoTime() ).hashCode() ; // 5.1.9.0 (2010/08/01) equals,hashCode 063 064 /** 065 * デフォルトコンストラクター 066 * シリーズ番号を、初期化しておきます。 067 * 068 **/ 069 public HybsCategoryPlot() { 070 // 4.3.4.4 (2009/01/01) 071 this( -1 ); 072 } 073 074 /** 075 * シリーズ番号 を、指定して、オブジェクトを作成するコンストラクター 076 * 077 * @param serNo ピックアップするシリーズ番号 078 **/ 079 protected HybsCategoryPlot( final int serNo ) { 080 super(); // 6.4.1.1 (2016/01/16) PMD refactoring. It is a good practice to call super() in a constructor 081 // 4.3.4.4 (2009/01/01) 082 this.serNo = serNo; 083 } 084 085 /** 086 * ピックアップするシリーズ番号を設定します(独自メソッド)。 087 * 088 * @og.rev 4.1.1.0 (2008/02/04) データの値(itemText)表示の継承 089 * 090 * @param newSerNo ピックアップするシリーズ番号 091 **/ 092 protected void setSeriesPikup( final int newSerNo ) { 093 final int oldSerNo = serNo ; 094 serNo = newSerNo; 095 final CategoryItemRenderer rend = getRenderer(); 096 final CategoryURLGenerator urlGen = rend.getSeriesItemURLGenerator( oldSerNo ); 097 if( urlGen != null ) { 098 rend.setSeriesItemURLGenerator( oldSerNo,null ); 099 rend.setSeriesItemURLGenerator( serNo ,urlGen ); 100 } 101 102 // 4.1.1.0 (2008/02/04) データの値(itemText)表示の継承 103 if( rend.isSeriesItemLabelsVisible( oldSerNo ) ) { 104 rend.setSeriesItemLabelsVisible( oldSerNo,false ); 105 rend.setSeriesItemLabelsVisible( serNo ,true ); 106 } 107 } 108 109 /** 110 * 縦軸のグリッド線(水平線)をスキップする間隔を指定します(初期値:-1)。 111 * 112 * 縦軸のグリッド線を表示する際に、スキップする間隔を指定します。 113 * 通常は、ラベルと同じだけのグリッド線が掛かれますが、ラベルよりも 114 * 少ない数のグリッド線(例えば、2つおき)を出す場合に、値を設定します。 115 * "1" (初期値)では、1つづつ表示(つまり、すべて表示する)します。 116 * "2" とすると、1つおきに、"3" とすると、2つおきに表示します。 117 * なお、先頭から表示を開始します。 118 * (独自メソッド) 119 * 120 * 6.0.2.0 (2014/09/19) 前回の JFreeChart のVerUpで、グリッド線の表示が 121 * 5個おきに変わったようです。設定する値を マイナスにすると、初期設定の値を 122 * 使用するように変更します。微調整は、個々にお願いします。 123 * 124 * 初期値は、"-1" (設定しない)です。 125 * 126 * @og.rev 4.1.1.0 (2008/02/04) 新規追加 127 * 128 * @param rngSkip 縦軸のグリッド線(水平線)をスキップする間隔 129 */ 130 protected void setRangeSkip( final int rngSkip ) { 131 rangeSkip = rngSkip; 132 } 133 134 /** 135 * BarChart のバーの幅を直接指定します。 136 * 通常は、maxBarWidth や itemMargin で比率指定しますが、 137 * ここでは、CategoryItemRendererState オブジェクトに直接設定する為の 138 * データセット単位のマップを作成します。 139 * (独自メソッド) 140 * 141 * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。 142 * 143 * @param index データセット番号 144 * @param width バーの幅 145 **/ 146 protected void setBarWidth( final int index,final Double width ) { 147 // 6.4.3.1 (2016/02/12) ConcurrentMap 系は、key,val ともに not null 制限です。 148 if( width != null ) { barWdMap.put( index,width ); } 149 } 150 151 /** 152 * CategoryPlot の render メソッドをオーバーライドしています。 153 * 154 * Draws a representation of a dataset within the dataArea region using the 155 * appropriate renderer. 156 * 157 * @param g2 the graphics device. 158 * @param dataArea the region in which the data is to be drawn. 159 * @param index the dataset and renderer index. 160 * @param info an optional object for collection dimension information. 161 * @param crosshairState a state object for tracking crosshair info (null permitted). 162 * 163 * @return 描画するデータが見つかった場合は、true 164 */ 165 @Override 166 public boolean render( final Graphics2D g2, final Rectangle2D dataArea, final int index, 167 final PlotRenderingInfo info , final CategoryCrosshairState crosshairState) { 168 169 boolean foundData = false; 170 final CategoryDataset currentDataset = getDataset(index); 171 final CategoryItemRenderer renderer = getRenderer(index); 172 // 4.3.1.0 (2008/08/19) 軸とデータセットのマッピング 173 this.mapDatasetToRangeAxis( index, index ); 174 175 CategoryAxis domainAxis = null ; 176 if( renderer instanceof StackedBarRenderer ) { 177 domainAxis = getDomainAxis(index); 178 } 179 else { 180 domainAxis = getDomainAxisForDataset(index); 181 } 182 183 final ValueAxis rangeAxis = getRangeAxis(index); 184 final boolean hasData = !DatasetUtilities.isEmptyOrNull(currentDataset); 185 if( hasData && renderer != null ) { 186 foundData = true; 187 final CategoryItemRendererState state = renderer.initialise(g2, dataArea, this, index, info); 188 189 // 4.0.3.0 (2008/01/07) 棒グラフのバー幅指定 190 final Double bwidth = barWdMap.get( index ); 191 if( bwidth != null ) { state.setBarWidth( bwidth.doubleValue() ); } 192 193 if( renderer instanceof HybsDrawItem ) { 194 // 6.0.2.1 (2014/09/26) categoryカラー配列 195 if( currentDataset instanceof HybsDataset ) { 196 final Color[] categoryColor = ((HybsDataset)currentDataset).getCategoryColor(); 197 ((HybsDrawItem)renderer).setCategoryColor( categoryColor ); 198 } 199 200 ((HybsDrawItem)renderer).drawItem2(g2, state, dataArea, this, 201 domainAxis, rangeAxis, currentDataset , serNo ); 202 } 203 else { 204 final int clmCount = currentDataset.getColumnCount(); 205 final int rowCount = currentDataset.getRowCount(); 206 final int passCount = renderer.getPassCount(); 207 for( int pass=0; pass<passCount; pass++ ) { 208 for( int column=0; column<clmCount; column++ ) { 209 for( int row=0; row<rowCount; row++ ) { 210 if( row == serNo ) { continue; } // Mis Add 2007/07/23 211 renderer.drawItem(g2, state, dataArea, this, 212 domainAxis, rangeAxis, currentDataset, 213 row, column, pass); 214 } 215 // 指定のシリーズと一致する場合は、最後に描画する。 Mis Add 2007/07/23 216 if( serNo >= 0 ) { 217 renderer.drawItem(g2, state, dataArea, this, 218 domainAxis, rangeAxis, currentDataset, 219 serNo, column, pass); 220 } 221 } 222 } 223 } 224 } 225 return foundData; 226 } 227 228 /** 229 * CategoryPlot の drawRangeGridlines メソッドをオーバーライドします。 230 * 231 * Draws the gridlines for the plot. 232 * 233 * @og.rev 6.0.2.0 (2014/09/19) rangeSkip 属性 の初期値を、-1(設定なし)に変更 234 * 235 * @param g2 the graphics device. 236 * @param dataArea the area inside the axes. 237 * @param ticks the ticks. 238 * @see #drawDomainGridlines(Graphics2D, Rectangle2D) 239 */ 240 @SuppressWarnings("rawtypes") 241 @Override 242 protected void drawRangeGridlines( final Graphics2D g2, final Rectangle2D dataArea, 243 final List ticks ) { 244 // draw the range grid lines, if any... 245 // 6.0.2.0 (2014/09/19) rangeSkip 属性 の初期値を、-1(設定なし)に変更 246 if( rangeSkip <= 0 ) { super.drawRangeGridlines( g2,dataArea,ticks ); } 247 else { 248 if( isRangeGridlinesVisible() ) { 249 final Stroke gridStroke = getRangeGridlineStroke(); 250 final Paint gridPaint = getRangeGridlinePaint(); 251 if( gridStroke != null && gridPaint != null ) { 252 final ValueAxis axis = getRangeAxis(); 253 final CategoryItemRenderer renderer1 = getRenderer(); 254 if( axis != null && renderer1 != null ) { 255 final Iterator<?> iterator = ticks.iterator(); 256 int cnt = 0; 257 while( iterator.hasNext() ) { 258 final ValueTick tick = (ValueTick) iterator.next(); 259 if( cnt % rangeSkip == 0 ) { 260 renderer1.drawRangeGridline(g2, this, 261 axis, dataArea, tick.getValue()); 262 } 263 cnt++ ; 264 } 265 } 266 } 267 } 268 } 269 } 270 271 /** 272 * この文字列と指定されたオブジェクトを比較します。 273 * 274 * 親クラスで、equals メソッドが実装されているため、警告がでます。 275 * 276 * @og.rev 5.1.8.0 (2010/07/01) findbug対応 277 * @og.rev 5.1.9.0 (2010/08/01) findbug対応 278 * 279 * @param object 比較するオブジェクト 280 * 281 * @return Objectが等しい場合は true、そうでない場合は false 282 */ 283 @Override 284 public boolean equals( final Object object ) { 285 // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method 286 return super.equals( object ) && hsCode == ((HybsCategoryPlot)object).hsCode; 287 } 288 289 /** 290 * このオブジェクトのハッシュコードを取得します。 291 * 292 * @og.rev 5.1.8.0 (2010/07/01) findbug対応 293 * @og.rev 5.1.9.0 (2010/08/01) findbug対応 294 * 295 * @return ハッシュコード 296 */ 297 @Override 298 public int hashCode() { return hsCode ; } 299}