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 static org.opengion.fukurou.system.HybsConst.CR ; // 6.1.0.0 (2014/12/26) 019import org.opengion.fukurou.util.StringUtil; 020import org.opengion.hayabusa.common.HybsSystemException; 021import org.opengion.hayabusa.db.DBTableModel; 022 023import java.sql.Connection; 024import java.sql.SQLException; 025import java.util.Map; 026import java.util.HashMap; 027import java.util.Arrays; 028 029import org.jfree.data.jdbc.JDBCPieDataset; 030import org.jfree.data.jdbc.JDBCXYDataset; 031import org.jfree.data.general.Dataset; 032import org.jfree.data.general.DefaultValueDataset; 033 034import org.jfree.data.xy.CategoryTableXYDataset; 035import org.jfree.data.general.DefaultPieDataset; 036import org.jfree.data.DefaultKeyedValues; 037 038import org.jfree.data.category.CategoryDataset; // 6.9.7.0 (2018/05/14) 039import org.jfree.data.xy.XYDataset; // 6.9.7.0 (2018/05/14) 040import org.jfree.data.Values; // 6.9.7.0 (2018/05/14) 041import org.jfree.data.Value; // 6.9.7.0 (2018/05/14) 042 043/** 044 * ChartFactory は、Dataset および、Renderer のオブジェクトを構築するファクトリクラスです。 045 * JFreeChart では、各種オブジェクトの組み合わせで、色々なグラフを作成できます。 046 * ここでは、簡易的にオブジェクトを構築できるように、一つのキーワードによって、各種作成する 047 * オブジェクトのキーワードを関連付けておきます。 048 * 049 * <table border="1" frame="box" rules="all" > 050 * <caption>各種オブジェクトの組み合わせ一覧</caption> 051 * <tr><th> チャートタイプ </th><th> レンデラー(org.jfree.chart.renderer.) </th><th> Dataset </th></tr> 052 * <tr><td> HybsLine </td><td> HybsLineRenderer </td><td> Category </td></tr> 053 * <tr><td> LineAndShape </td><td> category.LineAndShapeRenderer </td><td> Category </td></tr> 054 * <tr><td> Line3D </td><td> category.LineRenderer3D </td><td> Category </td></tr> 055 * <tr><td> StatisticalLineAndShape </td><td> category.StatisticalLineAndShapeRenderer </td><td> Category </td></tr> 056 * <tr><td> HybsParetoLine </td><td> HybsLineRenderer </td><td> ParetoCategory </td></tr> 057 * <tr><td> HybsBar </td><td> HybsBarRenderer </td><td> Category </td></tr> 058 * <tr><td> HybsColorBar </td><td> HybsBarRenderer </td><td> Category </td></tr> 059 * <tr><td> Bar </td><td> category.BarRenderer </td><td> Category </td></tr> 060 * <tr><td> Bar3D </td><td> category.BarRenderer3D </td><td> Category </td></tr> 061 * <tr><td> HybsColorBar3D </td><td> HybsBarRenderer3D </td><td> Category </td></tr> 062 * <tr><td> Area </td><td> category.AreaRenderer </td><td> Category </td></tr> 063 * <tr><td> HybsStackedBar </td><td> HybsStackedBarRenderer </td><td> Category </td></tr> 064 * <tr><td> StackedBar </td><td> category.StackedBarRenderer </td><td> Category </td></tr> 065 * <tr><td> StackedBar3D </td><td> category.StackedBarRenderer3D </td><td> Category </td></tr> 066 * <tr><td> StackedArea </td><td> category.StackedAreaRenderer </td><td> Category </td></tr> 067 * <tr><td> GroupedStackedBar </td><td> category.GroupedStackedBarRenderer </td><td> Category </td></tr> 068 * <tr><td> LayeredBar </td><td> category.LayeredBarRenderer </td><td> Category </td></tr> 069 * <tr><td> CategoryStep </td><td> category.CategoryStepRenderer </td><td> Category </td></tr> 070 * <tr><td> Level </td><td> category.LevelRenderer </td><td> Category </td></tr> 071 * <tr><td> MinMax </td><td> category.MinMaxCategoryRenderer </td><td> Category </td></tr> 072 * <tr><td> WaterfallBar </td><td> category.WaterfallBarRenderer </td><td> Category </td></tr> 073 * <tr><td> MultiplePie </td><td> null </td><td> Category </td></tr> 074 * <tr><td> SpiderWeb </td><td> null </td><td> Category </td></tr> 075 * <tr><td> Pie </td><td> null </td><td> Pie </td></tr> 076 * <tr><td> Pie3D </td><td> null </td><td> Pie </td></tr> 077 * <tr><td> Ring </td><td> null </td><td> Pie </td></tr> 078 * <tr><td> XYArea </td><td> xy.XYAreaRenderer </td><td> XY </td></tr> 079 * <tr><td> XYArea2 </td><td> xy.XYAreaRenderer2 </td><td> XY </td></tr> 080 * <tr><td> XYBlock </td><td> xy.XYBlockRenderer </td><td> XY </td></tr> 081 * <tr><td> CyclicXYItem </td><td> xy.CyclicXYItemRenderer </td><td> XY </td></tr> 082 * <tr><td> HighLow </td><td> xy.HighLowRenderer </td><td> XY </td></tr> 083 * <tr><td> StackedXYArea </td><td> xy.StackedXYAreaRenderer </td><td> XY </td></tr> 084 * <tr><td> StackedXYArea2 </td><td> xy.StackedXYAreaRenderer2 </td><td> XY </td></tr> 085 * <tr><td> StandardXYItem </td><td> xy.StandardXYItemRenderer </td><td> XY </td></tr> 086 * <tr><td> XYBubble </td><td> xy.XYBubbleRenderer </td><td> XY </td></tr> 087 * <tr><td> XYDifference </td><td> xy.XYDifferenceRenderer </td><td> XY </td></tr> 088 * <tr><td> XYDot </td><td> xy.XYDotRenderer </td><td> XY </td></tr> 089 * <tr><td> XYError </td><td> xy.XYErrorRenderer </td><td> XY </td></tr> 090 * <tr><td> XYLine3D </td><td> xy.XYLine3DRenderer </td><td> XY </td></tr> 091 * <tr><td> XYLineAndShape </td><td> xy.XYLineAndShapeRenderer </td><td> XY </td></tr> 092 * <tr><td> XYStepArea </td><td> xy.XYStepAreaRenderer </td><td> XY </td></tr> 093 * <tr><td> XYStep </td><td> xy.XYStepRenderer </td><td> XY </td></tr> 094 * <tr><td> PolarItem </td><td> DefaultPolarItemRenderer </td><td> XY </td></tr> 095 * <tr><td> Meter </td><td> null </td><td> Value </td></tr> 096 * <tr><td> Thermometer </td><td> null </td><td> Value </td></tr> 097 * <tr><td> Compass </td><td> null </td><td> Value </td></tr> 098 * <tr><td> Gantt </td><td> category.GanttRenderer </td><td> TaskSeries </td></tr> 099 * <tr><td> XYBarV </td><td> xy.XYBarRenderer </td><td> TimeSeries </td></tr> 100 * <tr><td> ClusteredXYBarV </td><td> xy.ClusteredXYBarRenderer </td><td> TimeSeries </td></tr> 101 * <tr><td> YIntervalV </td><td> xy.YIntervalRenderer </td><td> TimeSeries </td></tr> 102 * <tr><td> DeviationV </td><td> xy.DeviationRenderer </td><td> TimeSeries </td></tr> 103 * <tr><td> TimeSeriesLineV </td><td> xy.StandardXYItemRenderer </td><td> TimeSeries </td></tr> 104 * <tr><td> TimeSeriesLineH </td><td> xy.StandardXYItemRenderer </td><td> TimeSeries </td></tr> 105 * <tr><td> TimeSeriesBarV </td><td> xy.XYBarRenderer </td><td> TimeSeries </td></tr> 106 * <tr><td> TimeSeriesBarH </td><td> xy.XYBarRenderer </td><td> TimeSeries </td></tr> 107 * <tr><td> StackedTimeSeriesLineV </td><td> xy.StandardXYItemRenderer </td><td> TimeSeries </td></tr> 108 * <tr><td> StackedTimeSeriesLineH </td><td> xy.StandardXYItemRenderer </td><td> TimeSeries </td></tr> 109 * <tr><td> TimeStepV </td><td> xy.XYStepRenderer </td><td> TimeSeries </td></tr> 110 * <tr><td> TimeStepH </td><td> xy.XYStepRenderer </td><td> TimeSeries </td></tr> 111 * </table> 112 * 113 * @version 0.9.0 2007/06/21 114 * @author Kazuhiko Hasegawa 115 * @since JDK1.1, 116 */ 117public final class ChartFactory { 118 119 private static final String PLOT_SUB = "org.opengion.hayabusa.io.ChartPlot_" ; 120 121 // ChartPlot オブジェクトはマルチスレッドで使用可能なため、キャッシュして使いまわします。 122 123 private static ChartPlot plotCAT ; 124 private static ChartPlot plotXY ; 125 private static ChartPlot plotPIE ; 126 private static ChartPlot plotTIM ; // 5.6.1.0 (2013/02/01) 127 private static ChartPlot plotXTIM ; // 5.6.1.0 (2013/02/01) 128 129 private static final Object LOCK = new Object(); // 6.4.1.1 (2016/01/16) lock → LOCK refactoring 130 131 /** 132 * 引数タイプに応じたレンデラーやデータセットを規定します。 133 */ 134 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */ 135 private static final Map<String,TypeRenderer> TYPE_RENDERER_MAP = new HashMap<>(); 136 137 // 4.1.1.0 (2008/02/04) HybsBar 追加 138 // 5.3.0.0 (2010/12/01) xxxPlot 追加、データ内容修正、コメント部対応 139 static { 140 final String[][] data = new String[][] { 141 // キーワード xxxRenderer xxxDataset xxxPlot 142 { "HybsLine" , "HybsLineRenderer" , "Category" , "Category" } 143 , { "LineAndShape" , "category.LineAndShapeRenderer" , "Category" , "Category" } 144 , { "Line3D" , "category.LineRenderer3D" , "Category" , "Category" } 145 , { "StatisticalLineAndShape", "category.StatisticalLineAndShapeRenderer", "Category" , "Category" } 146 , { "HybsParetoLine" , "HybsLineRenderer" , "ParetoCategory" , "Category" } // 6.0.2.1 (2014/09/26) パレート図 147 148 , { "HybsBar" , "HybsBarRenderer" , "Category" , "Category" } 149 , { "HybsColorBar" , "HybsBarRenderer" , "Category" , "Category" } // 6.0.2.1 (2014/09/26) カテゴリカラー 150 , { "Bar" , "category.BarRenderer" , "Category" , "Category" } 151 , { "Bar3D" , "category.BarRenderer3D" , "Category" , "Category" } 152 , { "HybsColorBar3D" , "HybsBarRenderer3D" , "Category" , "Category" } // 6.0.2.2 (2014/10/03) カテゴリカラー 153 , { "Area" , "category.AreaRenderer" , "Category" , "Category" } 154 155 , { "HybsStackedBar" , "HybsStackedBarRenderer" , "Category" , "Category" } 156 , { "StackedBar" , "category.StackedBarRenderer" , "Category" , "Category" } 157 , { "StackedBar3D" , "category.StackedBarRenderer3D" , "Category" , "Category" } 158 , { "StackedArea" , "category.StackedAreaRenderer" , "Category" , "Category" } 159 , { "GroupedStackedBar" , "category.GroupedStackedBarRenderer" , "Category" , "Category" } 160 161 , { "LayeredBar" , "category.LayeredBarRenderer" , "Category" , "Category" } 162 163 , { "CategoryStep" , "category.CategoryStepRenderer" , "Category" , "Category" } 164 , { "Level" , "category.LevelRenderer" , "Category" , "Category" } 165 166 , { "MinMax" , "category.MinMaxCategoryRenderer" , "Category" , "Category" } 167 168 , { "WaterfallBar" , "category.WaterfallBarRenderer" , "Category" , "Category" } 169 170 , { "MultiplePie" , null , "Category" , "MultiplePie" } 171 , { "SpiderWeb" , null , "Category" , "SpiderWeb" } 172 173 // , { "BoxAndWhisker" , "category.BoxAndWhiskerRenderer" , "BoxAndWhisker" , "Category" } 174 // , { "IntervalBar" , "category.IntervalBarRenderer" , "IntervalCategory" , "Category" } 175 // , { "StatisticalBar" , "category.StatisticalBarRenderer" , "StatisticalCategory" , "Category" } 176 // , { "Candlestick" , "xy.CandlestickRenderer" , "OHLC" , "XY" } 177 // , { "StackedXYBarV" , "xy.StackedXYBarRenderer" , "TableXY" , "XY" } 178 // , { "WindItem" , "xy.WindItemRenderer" , "Wind" , "XY" } 179 // , { "XYBoxAndWhisker" , "xy.XYBoxAndWhiskerRenderer" , "BoxAndWhiskerXY" , "XY" } 180 // , { "WaferMap" , "WaferMapRenderer" , "WaferMap" , "WaferMap" } 181 // , { "Contour" , null , "Contour" , "Contour" } 182 // , { "FastScatter" , null , "float2" , "FastScatter" } 183 184 , { "Pie" , null , "Pie" , "Pie" } 185 , { "Pie3D" , null , "Pie" , "Pie" } 186 , { "Ring" , null , "Pie" , "Ring" } 187 188 , { "XYArea" , "xy.XYAreaRenderer" , "XY" , "XY" } 189 , { "XYArea2" , "xy.XYAreaRenderer2" , "XY" , "XY" } 190 , { "XYBlock" , "xy.XYBlockRenderer" , "XY" , "XY" } 191 , { "CyclicXYItem" , "xy.CyclicXYItemRenderer" , "XY" , "XY" } 192 , { "HighLow" , "xy.HighLowRenderer" , "XY" , "XY" } 193 , { "StackedXYArea" , "xy.StackedXYAreaRenderer" , "XY" , "XY" } 194 , { "StackedXYArea2" , "xy.StackedXYAreaRenderer2" , "XY" , "XY" } 195 , { "StandardXYItem" , "xy.StandardXYItemRenderer" , "XY" , "XY" } 196 , { "XYBubble" , "xy.XYBubbleRenderer" , "XY" , "XY" } 197 , { "XYDifference" , "xy.XYDifferenceRenderer" , "XY" , "XY" } 198 , { "XYDot" , "xy.XYDotRenderer" , "XY" , "XY" } 199 , { "XYError" , "xy.XYErrorRenderer" , "XY" , "XY" } 200 , { "XYLine3D" , "xy.XYLine3DRenderer" , "XY" , "XY" } 201 , { "XYLineAndShape" , "xy.XYLineAndShapeRenderer" , "XY" , "XY" } 202 , { "XYStepArea" , "xy.XYStepAreaRenderer" , "XY" , "XY" } 203 , { "XYStep" , "xy.XYStepRenderer" , "XY" , "XY" } 204 , { "PolarItem" , "DefaultPolarItemRenderer" , "XY" , "Polar" } 205 206 , { "Meter" , null , "Value" , "Meter" } 207 , { "Thermometer" , null , "Value" , "Thermometer" } 208 , { "Compass" , null , "Value" , "Compass" } 209 210 , { "Gantt" , "category.GanttRenderer" , "TaskSeries" , "Time" } 211 212 , { "XYBarV" , "xy.XYBarRenderer" , "TimeSeries" , "XYTime" } 213 , { "ClusteredXYBarV" , "xy.ClusteredXYBarRenderer" , "TimeSeries" , "XYTime" } 214 , { "YIntervalV" , "xy.YIntervalRenderer" , "TimeSeries" , "XYTime" } 215 , { "DeviationV" , "xy.DeviationRenderer" , "TimeSeries" , "XYTime" } 216 , { "TimeSeriesBarV" , "xy.XYBarRenderer" , "TimeSeries" , "XYTime" } // 5.6.1.0 (2013/02/01) 時間軸を持つチャート 217 , { "TimeSeriesBarH" , "xy.XYBarRenderer" , "TimeSeries" , "XYTime" } // 5.6.1.0 (2013/02/01) 時間軸を持つチャート 218 , { "TimeSeriesLineV" , "xy.StandardXYItemRenderer" , "TimeSeries" , "XYTime" } // 5.6.1.0 (2013/02/01) 時間軸を持つチャート 219 , { "TimeSeriesLineH" , "xy.StandardXYItemRenderer" , "TimeSeries" , "XYTime" } // 5.6.1.0 (2013/02/01) 時間軸を持つチャート 220 , { "StackedTimeSeriesLineV" , "xy.StandardXYItemRenderer" , "TimeSeries" , "XYTime" } // 5.6.1.0 (2013/02/01) 時間軸を持つチャート 221 , { "StackedTimeSeriesLineH" , "xy.StandardXYItemRenderer" , "TimeSeries" , "XYTime" } // 5.6.1.0 (2013/02/01) 時間軸を持つチャート 222 , { "TimeStepV" , "xy.XYStepRenderer" , "TimeSeries" , "XYTime" } // 5.9.17.1 (2017/02/10) step追加 223 , { "TimeStepH" , "xy.XYStepRenderer" , "TimeSeries" , "XYTime" } // 5.9.17.1 (2017/02/10) step追加 224 }; 225 226 for( int i=0; i<data.length; i++ ) { 227 TYPE_RENDERER_MAP.put( data[i][0],new TypeRenderer( data[i][0],data[i][1],data[i][2],data[i][3] ) ); 228 } 229 } 230 231 /** 232 * デフォルトコンストラクタを private 化しておきます。 233 * 234 */ 235 private ChartFactory() {} 236 237 /** 238 * Connection と query 文字列から、Dataset オブジェクトを作成します。 239 * 240 * 引数のtypeは、内部定義の TYPE_RENDERER_MAP マップで関連付けられたキーワード 241 * より、対象とするチャート特性を取得します。(getTypeRenderer) 242 * その TypeRenderer#getDatasetType() メソッドの値を元に、Dataset クラスは、 243 * "org.jfree.data.jdbc.JDBC****Dataset" の **** の箇所を特定します。 244 * 現状は、Category , ParetoCategory , Pie , XY の3種類 + Valueデータセットが選択されます。 245 * 246 * @og.rev 3.8.9.2 (2007/07/28) HybsJDBCCategoryDataset 追加 247 * @og.rev 5.3.0.0 (2010/12/01) その他のDataset 追加 248 * @og.rev 5.6.1.0 (2013/02/01) 時間軸を持つチャート TimeSeries 追加 249 * @og.rev 6.0.2.0 (2014/09/19) シリーズのラベル名配列追加 250 * @og.rev 6.0.2.1 (2014/09/26) パレート図用のDataset ParetoCategory 追加 251 * @og.rev 6.0.2.2 (2014/10/03) カテゴリのカラー名指定 useCategoryColor 追加 252 * 253 * @param conn Dataset の取得先のコネクション 254 * @param query 取得するクエリー文字列 255 * @param type Dataset オブジェクトの作成元を求めるキーワード 256 * @param lbls シリーズのラベル名配列 257 * @param useCateColor カテゴリのカラー名指定 [false:指定しない/true:指定する] 258 * 259 * @return Datasetオブジェクト 260 * 261 * @see #getTypeRenderer( String ) 262 * @see #newDataset( DBTableModel ,String ,String[] ,boolean ) 263 * @throws SQLException データベースアクセスエラー 264 */ 265 public static Dataset newDataset( final Connection conn,final String query, 266 final String type,final String[] lbls,final boolean useCateColor ) 267 throws SQLException { 268 final Dataset dataset ; 269 270 final TypeRenderer rend = getTypeRenderer( type ); 271 272 final String dsType = rend.getDatasetType(); 273 // 6.0.2.1 (2014/09/26) パレート図用のDataset ParetoCategory 追加 274 final boolean isPareto = "ParetoCategory".equalsIgnoreCase( dsType ); 275 if( "Category".equalsIgnoreCase( dsType ) || isPareto ) { 276 final HybsCategoryDataset hData = new HybsCategoryDataset(); 277 hData.initParam( lbls,useCateColor,isPareto ); 278 hData.execute( conn, query ); 279 dataset = hData ; 280 } 281 else if( "XY".equalsIgnoreCase( dsType ) ) { 282 dataset = new JDBCXYDataset( conn, query ); 283 } 284 else if( "Pie".equalsIgnoreCase( dsType ) ) { 285 dataset = new JDBCPieDataset( conn, query ); 286 } 287 else if( "Value".equalsIgnoreCase( dsType ) ) { 288 dataset = new DefaultValueDataset(); 289 } 290 // 5.3.0.0 (2010/12/01) その他のDataset 追加 291 // else if( "GanttCategory".equalsIgnoreCase( dsType ) ) { 292 // dataset = new HybsJDBCCategoryDataset2( conn, query ); // 代替 293 // } 294 // else if( "IntervalCategory".equalsIgnoreCase( dsType ) ) { 295 // dataset = new HybsJDBCCategoryDataset2( conn, query ); // 代替 296 // } 297 // else if( "StatisticalCategory".equalsIgnoreCase( dsType ) ) { 298 // dataset = new HybsJDBCCategoryDataset2( conn, query ); // 代替 299 // } 300 else if( "TimeSeries".equalsIgnoreCase( dsType ) ) { 301 dataset = new HybsTimeSeriesCollection( type ); // 5.6.1.0 (2013/02/01) 時間軸を持つチャート 302 ((HybsTimeSeriesCollection)dataset).executeQuery( conn, query ); 303 } 304 else if( "TaskSeries".equalsIgnoreCase( dsType ) ) { 305 dataset = new HybsTaskSeriesCollection(); // 5.6.1.0 (2013/02/01) タスク情報を持つチャート 306 ((HybsTaskSeriesCollection)dataset).executeQuery( conn, query ); 307 } 308 else { 309 final String errMsg = "Category,ParetoCategory,Pie,XY,Value,TimeSeries 以外のDataset はサポートしていません。[" + dsType + "]"; 310 throw new HybsSystemException( errMsg ); 311 } 312 313 return dataset ; 314 } 315 316 /** 317 * DBTableModelオブジェクトから、Dataset オブジェクトを作成します。 318 * 319 * 引数のtypeは、内部定義の TYPE_RENDERER_MAP マップで関連付けられたキーワード 320 * より、対象とするチャート特性を取得します。(getTypeRenderer) 321 * その TypeRenderer#getDatasetType() メソッドの値を元に、Dataset クラスを作成します。 322 * 323 * 現状は、Category , ParetoCategory , Pie , XY の3種類 + Valueデータセットが選択されます。 324 * 325 * ※ DBTableModel の row,col と、Dataset の row,col は、逆になっています。 326 * 327 * @og.rev 5.3.0.0 (2010/12/01) 新規追加 328 * @og.rev 6.0.2.0 (2014/09/19) シリーズのラベル名配列追加 329 * @og.rev 6.0.2.1 (2014/09/26) パレート図用のDataset ParetoCategory 追加 330 * @og.rev 6.0.2.2 (2014/10/03) カテゴリのカラー名指定 useCategoryColor 追加 331 * 332 * @param table Dataset の取得先のテーブルモデル 333 * @param type Dataset オブジェクトの作成元を求めるキーワード 334 * @param lbls シリーズのラベル名配列 335 * @param useCateColor カテゴリのカラー名指定 [false:指定しない/true:指定する] 336 * 337 * @return Datasetオブジェクト 338 * 339 * @see #getTypeRenderer( String ) 340 * @see #newDataset( Connection ,String ,String ,String[] ,boolean ) 341 */ 342 public static Dataset newDataset( final DBTableModel table , 343 final String type,final String[] lbls,final boolean useCateColor ) { 344 final Dataset dataset ; 345 346 final TypeRenderer rend = getTypeRenderer( type ); 347 final int clmNo = table.getColumnCount(); 348 final int rowNo = table.getRowCount(); 349 350 final String dsType = rend.getDatasetType(); 351 // 6.0.2.1 (2014/09/26) パレート図用のDataset ParetoCategory 追加 352 final boolean isPareto = "ParetoCategory".equalsIgnoreCase( dsType ); 353 if( "Category".equalsIgnoreCase( dsType ) || isPareto ) { 354 // select key,val1,val2,val3 ・・・ from ・・・ 355 356 final String[] seri = getSeriesLabels( table,lbls ); // 6.0.2.0 (2014/09/19) シリーズのラベル名配列追加 357 358 final HybsCategoryDataset hData = new HybsCategoryDataset(); 359 hData.initParam( seri,useCateColor,isPareto ); 360 hData.execute( table ); 361 dataset = hData ; 362 363 } 364 else if( "XY".equalsIgnoreCase( dsType ) ) { 365 // select valx,valy from ・・・ 366 367 final CategoryTableXYDataset xyDataset = new CategoryTableXYDataset() ; 368 // 6.0.2.0 (2014/09/19) シリーズのラベル名配列追加 369 final String[] seri = getSeriesLabels( table,lbls ); // 6.0.2.0 (2014/09/19) シリーズのラベル名配列追加 370 371 for( int row=0; row<rowNo; row++ ) { 372 final String[] vals = table.getValues( row ); 373 final double rval = vals[0] == null || vals[0].isEmpty() ? 0.0d : Double.parseDouble( vals[0] ); // 6.4.2.1 (2016/02/05) PMD refactoring. Useless parentheses. 374 for( int clm=1; clm<clmNo; clm++ ) { // 2番目(アドレス=1)からカラムデータを取得 375 final String sval = vals[clm]; 376 final double val = sval == null || sval.isEmpty() ? 0.0d : Double.parseDouble( sval ) ; // 6.4.2.1 (2016/02/05) PMD refactoring. Useless parentheses. 377 xyDataset.add( rval,val,seri[clm] ); 378 } 379 } 380 381 dataset = xyDataset; 382 } 383 else if( "Pie".equalsIgnoreCase( dsType ) ) { 384 // select key,val from ・・・ 385 386 final DefaultKeyedValues keyVal = new DefaultKeyedValues(); 387 for( int row=0; row<rowNo; row++ ) { 388 final String[] vals = table.getValues( row ); 389 390 final String key = vals[0]; // KEY項目 391 final String sval = vals[1]; // VALUE項目 392 final double val = sval == null || sval.isEmpty() ? 0.0d : Double.parseDouble( sval ) ; // 6.4.2.1 (2016/02/05) PMD refactoring. Useless parentheses. 393 keyVal.addValue( key ,val ); 394 } 395 dataset = new DefaultPieDataset( keyVal ); 396 } 397 else if( "Value".equalsIgnoreCase( dsType ) ) { 398 // Value は、オブジェクトを作成するだけ。値は、markValues を ChartDataset.java で設定 399 dataset = new DefaultValueDataset(); 400 } 401 // 5.3.0.0 (2010/12/01) その他のDataset 追加 402 // else if( "GanttCategory".equalsIgnoreCase( dsType ) ) { 403 // dataset = new TaskSeriesCollection(); 404 // } 405 // else if( "IntervalCategory".equalsIgnoreCase( dsType ) ) { 406 // dataset = new DefaultIntervalCategoryDataset( String[] seriesNames, Number[][] starts, Number[][] ends) ; 407 // } 408 // else if( "StatisticalCategory".equalsIgnoreCase( dsType ) ) { 409 // dataset = new DefaultStatisticalCategoryDataset(); 410 // } 411 // else if( "Wind".equalsIgnoreCase( dsType ) ) { 412 // dataset = new DefaultWindDataset(java.lang.String[] seriesNames, java.lang.Object[][][] data); 413 // } 414 // else if( "OHLC".equalsIgnoreCase( dsType ) ) { 415 // dataset = new DefaultOHLCDataset(java.lang.Comparable key, OHLCDataItem[] data); 416 // } 417 // else if( "BoxAndWhiskerXY".equalsIgnoreCase( dsType ) ) { 418 // dataset = new org.jfree.data.statistics.DefaultBoxAndWhiskerXYDataset(java.lang.Comparable seriesKey); 419 // } 420 // else if( "WaferMap".equalsIgnoreCase( dsType ) ) { 421 // dataset = new JDBCXYDataset( conn, query ); 422 // } 423 // else if( "float2".equalsIgnoreCase( dsType ) ) { 424 // float[][] を返すので、ここでは使えない。 425 // } 426 else { 427 final String errMsg = "Category,ParetoCategory,Pie,XY,Value 以外のDataset はサポートしていません。[" + dsType + "]"; 428 throw new HybsSystemException( errMsg ); 429 } 430 431 return dataset ; 432 } 433 434 /** 435 * Datasetオブジェクトのデータ件数を返します。 436 * 437 * org.jfree.data.general.Dataset には、共通に利用できる件数取得のメソッドが定義されていません。 438 * なので、個々のクラスごとに、取得します。 439 * ChartFactory に持っているのは、このクラスで、Dataset の実態を作成している関係上、 440 * 新しいクラスを追加時に、このメソッドの手直しが必要になるからです。 441 * 442 * @og.rev 6.9.7.0 (2018/05/14) データ0件の対応。 443 * 444 * @param dataset Datasetオブジェクト 445 * @return データ件数 446 */ 447 public static int getRowCount( final Dataset dataset ) { 448 if( dataset == null ) { 449 return 0; 450 } 451 else if( dataset instanceof CategoryDataset ) { 452 return ((CategoryDataset)dataset).getRowCount(); 453 } 454 else if( dataset instanceof XYDataset ) { 455 final XYDataset xyData = (XYDataset)dataset; 456 int cnt = 0; 457 for( int i=0; i<xyData.getSeriesCount(); i++ ) { 458 for( int j=0; j<xyData.getItemCount( i ); j++ ) { 459 cnt++ ; 460 } 461 } 462 463 return cnt; 464 } 465 else if( dataset instanceof Values ) { 466 return ((Values)dataset).getItemCount(); 467 } 468 else if( dataset instanceof Value ) { 469 return ((Value)dataset).getValue() == null ? 0 : 1 ; 470 } 471 else { 472 final String errMsg = "Category,ParetoCategory,Pie,XY,Value 以外のDataset はサポートしていません。" + dataset.getClass(); 473 throw new HybsSystemException( errMsg ); 474 } 475 } 476 477 /** 478 * シリーズのラベル名配列を作成します。 479 * 480 * シリーズのラベル名配列が null でない場合は、その配列から、そうでない場合は、 481 * DBTableModelオブジェクトから、ラベル名配列を作成します。 482 * 483 * シリーズのラベル名配列追加引数は、DBTableModelオブジェクトのカラム数ー1 でなければなりません。 484 * シリーズのラベルは、以前は、テーブルのカラムそのものでしたが、リソースを経由したラベルに変更します。 485 * また、ここで返すラベルの配列は、ゼロ番目が、カラム順の1番目になります。 486 * カラムの0番目は、カテゴリなので、シリーズのラベル名としては使用しません。 487 * COLOR対応の場合は、最後のカラムが、色コードになり、ラベルとしては使いませんが、 488 * ここで作成する配列には、含まれます。利用する側で、COLORの場合は、無視するだけです。 489 * 490 * @og.rev 6.0.2.0 (2014/09/19) 新規追加 491 * 492 * @param table Datasetの取得先のテーブルモデル 493 * @param lbls 0から始まるシリーズのラベル名配列(可変長引数) 494 * 495 * @return カラム名の配列(0...)(ラベル化されている) 496 */ 497 private static String[] getSeriesLabels( final DBTableModel table , final String... lbls ) { 498 final int clmNo = table.getColumnCount(); 499 500 // 6.0.2.0 (2014/09/19) シリーズのラベル名配列を使うときは、必ずカラム数ー1以上必要 501 // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。 502 if( lbls != null && lbls.length < clmNo-1 ) { 503 final String errMsg = "seriesLabels を使用する場合は、必ず(カラム数ー1)以上にしてください。" 504 + CR 505 + " seriesLabels.length=" + lbls.length 506 + " columnCount=" + clmNo 507 + CR 508 + " seriesLabels=" + Arrays.toString( lbls ) 509 + CR ; 510 throw new IllegalArgumentException( errMsg ); 511 } 512 513 String[] series = new String[clmNo-1]; 514 for( int i=0; i<clmNo-1; i++ ) { 515 // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。 516 // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..; 517 series[i] = lbls == null || lbls[i] == null ? table.getColumnLabel(i+1) : lbls[i]; 518 } 519 return series; 520 } 521 522 /** 523 * TypeRenderer オブジェクトを作成します。 524 * 525 * 引数のtypeは、内部定義の TYPE_RENDERER_MAP マップで関連付けられたキーワード 526 * より、対象とするチャート特性を取得します。 527 * typeは、org.jfree.chart.renderer.XXXX.YYYYRenderer のYYYY とほぼ一致します。 528 * TYPE_RENDERER_MAP マップには、XXXX.YYYYRenderer 部分が定義されています。 529 * XXXX は、category と xy が定義されており、それ以外のレンデラーは null に 530 * なっています。Pie 関係は、レンデラーではなく、Plot と対応します。 531 * ただし、個々に設定情報が異なる為、ChartPlot_Pie クラスで個別対応しています。 532 * 533 * @param type Rendererオブジェクトの作成元を求めるキーワード 534 * 535 * @return TypeRendererオブジェクト 536 */ 537 public static TypeRenderer getTypeRenderer( final String type ) { 538 final TypeRenderer rend = TYPE_RENDERER_MAP.get( type ); 539 540 if( rend == null ) { 541 final String errMsg = "指定のタイプに該当する Renderer はサポートしていません。[" + type + "]" 542 + CR 543 + "Key=" + Arrays.toString( TYPE_RENDERER_MAP.keySet().toArray( new String[TYPE_RENDERER_MAP.size()] ) ); 544 throw new HybsSystemException( errMsg ); 545 } 546 547 return rend ; 548 } 549 550 /** 551 * ChartPlot オブジェクトを作成します。 552 * 553 * ChartPlot オブジェクトは、ChartPlot インターフェースを継承した 554 * サブクラスで、"org.opengion.hayabusa.io.ChartPlot_**** になります。 555 * **** には、Category , Pie , XY が指定できます。 556 * 557 * @og.rev 4.0.0.0 (2007/11/29) ChartPlot のサブクラスを動的に作成、キャッシュします。 558 * @og.rev 5.3.0.0 (2010/12/01) xxxPlot対応 559 * @og.rev 5.6.1.0 (2013/02/01) 時間軸を持つチャート TimeSeries 追加 560 * 561 * @param type Rendererオブジェクトの作成元を求めるキーワード 562 * 563 * @return ChartPlotオブジェクト 564 */ 565 public static ChartPlot newChartPlot( final String type ) { 566 567 final ChartPlot plot ; 568 569 final TypeRenderer rend = TYPE_RENDERER_MAP.get( type ); 570 571 final String pltType = rend.getPlotType(); // 5.3.0.0 (2010/12/01) xxxPlot対応 572 if( "Category".equalsIgnoreCase( pltType ) ) { 573 synchronized( LOCK ) { 574 if( plotCAT == null ) { 575 plotCAT = (ChartPlot)StringUtil.newInstance( PLOT_SUB + pltType ) ; 576 } 577 } 578 plot = plotCAT; 579 } 580 else if( "XY".equalsIgnoreCase( pltType ) ) { 581 synchronized( LOCK ) { 582 if( plotXY == null ) { 583 plotXY = (ChartPlot)StringUtil.newInstance( PLOT_SUB + pltType ) ; 584 } 585 } 586 plot = plotXY; 587 } 588 // 5.6.1.0 (2013/02/01) 時間軸を持つチャート 589 else if( "Time".equalsIgnoreCase( pltType ) ) { 590 synchronized( LOCK ) { 591 if( plotTIM == null ) { 592 plotTIM = (ChartPlot)StringUtil.newInstance( PLOT_SUB + pltType ) ; 593 } 594 } 595 plot = plotTIM; 596 } 597 // 5.6.1.0 (2013/02/01) 時間軸を持つチャート 598 else if( "XYTime".equalsIgnoreCase( pltType ) ) { 599 synchronized( LOCK ) { 600 if( plotXTIM == null ) { 601 plotXTIM = (ChartPlot)StringUtil.newInstance( PLOT_SUB + pltType ) ; 602 } 603 } 604 plot = plotXTIM; 605 } 606 else { 607 synchronized( LOCK ) { 608 if( plotPIE == null ) { 609 plotPIE = (ChartPlot)StringUtil.newInstance( PLOT_SUB + "Pie" ) ; 610 } 611 } 612 plot = plotPIE; 613 } 614 615 return plot ; 616 } 617}