    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.GradientPaint;
    019import java.awt.Graphics2D;
    020import java.awt.Paint;
    021import java.awt.geom.Rectangle2D;
    022
    023import org.jfree.chart.entity.EntityCollection;
    024import org.jfree.chart.renderer.category.StackedBarRenderer;
    025import org.jfree.chart.renderer.category.CategoryItemRendererState;
    026import org.jfree.chart.axis.CategoryAxis;
    027import org.jfree.chart.axis.ValueAxis;
    028import org.jfree.chart.labels.CategoryItemLabelGenerator;
    029import org.jfree.chart.plot.CategoryPlot;
    030import org.jfree.chart.plot.PlotOrientation;
    031import org.jfree.data.category.CategoryDataset;
    032import org.jfree.ui.GradientPaintTransformer;
    033import org.jfree.ui.RectangleEdge;
    034import org.jfree.data.DataUtilities;
    035
    036/**
    037 * HybsStackedBarRenderer は、org.jfree.chart.renderer.category.StackedBarRenderer を
    038 * 拡張したカスタマイズクラスです。
    039 * これは、グラフの書き出し位置の調整比率(domainMargin)を設定できます。
    040 *
    041 * @og.rev 4.1.1.0 (2008/02/16) 新規作成
    042 *
    043 * @version  0.9.0      2001/05/05
    044 * @author       Kazuhiko Hasegawa
    045 * @since        JDK1.1,
    046 */
    047public class HybsStackedBarRenderer extends StackedBarRenderer  {
    048        private static final long serialVersionUID = 519020100801L ;
    049
    050        private double  domainMargin    ;               // 4.1.1.0 (2008/02/14) グラフの書き出し位置の調整比率
    051
    052        private final int hsCode = Long.valueOf( System.nanoTime() ).hashCode() ;       // 5.1.9.0 (2010/08/01) equals,hashCode
    053
    054        /**
    055         * デフォルトコンストラクター
    056         *
    057         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    058         */
    059        public HybsStackedBarRenderer() { super(); }            // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    060
    061        /**
    062         * グラフの書き出し位置の調整比率を指定します。
    063         *
    064         * グラフを描画する場合の、書き出し位置を少しずらします。
    065         * これは、グラフの幅に対して、比率で指定します。
    066         * 0.0(初期値)の場合は、初期描画位置である、CategoryAnchor.Middle と
    067         * 同じ箇所から、書き出されます。
    068         * 1.0 の場合、中心から、グラフ幅の半分が加算され、END位置に寄ります。
    069         * 同様に、-1.0 の場合は、グラフ幅の半分が減算され、START 位置になります。
    070         * つまり、中心から、グラフ幅の半分単位で、前方/後方にずらす事が出来ます。
    071         *   書き出し位置 ＝ 中心(Middle) + (domainMargin)＊幅/２
    072         * 初期値は、0.0(真ん中:MIDDLE)です。
    073         * (独自メソッド)
    074         *
    075         * @og.rev 4.1.1.0 (2008/02/14) 新規追加
    076         *
    077         * @param       margin  グラフの書き出し位置の調整比率
    078         */
    079        public void setDomainMargin( final double margin ) {
    080                domainMargin = margin;
    081        }
    082
    083        /**
    084         * StackedBarRenderer の drawItem メソッドのオーバーライドしています。
    085         *
    086         * Draws a stacked bar for a specific item.
    087         *
    088         * @param g2  the graphics device.
    089         * @param state  the renderer state.
    090         * @param dataArea      the plot area.
    091         * @param plot  the plot.
    092         * @param domainAxis  the domain (category) axis.
    093         * @param rangeAxis  the range (value) axis.
    094         * @param dataset  the data.
    095         * @param row  the row index (zero-based).
    096         * @param column  the column index (zero-based).
    097         * @param pass  the pass index.
    098         */
    099        @Override
    100        public void drawItem( final Graphics2D g2,
    101                                                  final CategoryItemRendererState state,
    102                                                  final Rectangle2D dataArea,
    103                                                  final CategoryPlot plot,
    104                                                  final CategoryAxis domainAxis,
    105                                                  final ValueAxis rangeAxis,
    106                                                  final CategoryDataset dataset,
    107                                                  final int row,
    108                                                  final int column,
    109                                                  final int pass) {
    110
    111                // nothing is drawn for null values...
    112                final Number dataValue = dataset.getValue(row, column);
    113                if( dataValue == null ) {
    114                        return;
    115                }
    116
    117                double value = dataValue.doubleValue();
    118                double total = 0.0;  // only needed if calculating percentages
    119                if( getRenderAsPercentages() ) {
    120                        total = DataUtilities.calculateColumnTotal(dataset, column);
    121                        value = value / total;
    122                }
    123
    124                final PlotOrientation orientation = plot.getOrientation();
    125
    126                final double barW0 = domainAxis.getCategoryStart(column, getColumnCount(),
    127                                dataArea, plot.getDomainAxisEdge())
    128                                + domainMargin * state.getBarWidth() / 2.0;
    129
    130                double positiveBase = getBase();
    131                double negativeBase = positiveBase;
    132
    133                // 4.3.1.1 (2008/08/23) 変数名が短いので変更(v ⇒ nm , d ⇒ vd )
    134                for( int i=0; i<row; i++ ) {
    135                        final Number nm = dataset.getValue(i, column);
    136                        if( nm != null ) {
    137                                double vd = nm.doubleValue();
    138                                if( getRenderAsPercentages() ) {
    139                                        vd = vd / total;
    140                                }
    141                                if( vd > 0 ) {
    142                                        positiveBase = positiveBase + vd;
    143                                }
    144                                else {
    145                                        negativeBase = negativeBase + vd;
    146                                }
    147                        }
    148                }
    149
    150                double translatedBase;
    151                double translatedValue;
    152                final RectangleEdge location = plot.getRangeAxisEdge();
    153                if( value >= 0.0 ) {
    154                        translatedBase = rangeAxis.valueToJava2D(positiveBase, dataArea,
    155                                        location);
    156                        translatedValue = rangeAxis.valueToJava2D(positiveBase + value,
    157                                        dataArea, location);
    158                }
    159                else {
    160                        translatedBase = rangeAxis.valueToJava2D(negativeBase, dataArea,
    161                                        location);
    162                        translatedValue = rangeAxis.valueToJava2D(negativeBase + value,
    163                                        dataArea, location);
    164                }
    165                final double barL0 = Math.min(translatedBase, translatedValue);
    166                final double barLength = Math.max(Math.abs(translatedValue - translatedBase),
    167                                getMinimumBarLength());
    168
    169                Rectangle2D bar = null;
    170                if( orientation == PlotOrientation.HORIZONTAL ) {
    171                        bar = new Rectangle2D.Double(barL0, barW0, barLength,
    172                                        state.getBarWidth());
    173                }
    174                else {
    175                        bar = new Rectangle2D.Double(barW0, barL0, state.getBarWidth(),
    176                                        barLength);
    177                }
    178                if( pass == 0 ) {
    179                        Paint itemPaint = getItemPaint(row, column);
    180                        // 4.3.1.1 (2008/08/23) 変数名を t ⇒ gpt に変更
    181                        final GradientPaintTransformer gpt = getGradientPaintTransformer();
    182                        if( gpt != null && itemPaint instanceof GradientPaint ) {
    183                                itemPaint = gpt.transform((GradientPaint) itemPaint, bar);
    184                        }
    185                        g2.setPaint(itemPaint);
    186                        g2.fill(bar);
    187                        if( isDrawBarOutline()
    188                                        && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
    189                                g2.setStroke(getItemOutlineStroke(row, column));
    190                                g2.setPaint(getItemOutlinePaint(row, column));
    191                                g2.draw(bar);
    192                        }
    193
    194                        // add an item entity, if this information is being collected
    195                        final EntityCollection entities = state.getEntityCollection();
    196                        if( entities != null) {
    197                                addItemEntity(entities, dataset, row, column, bar);
    198                        }
    199                }
    200                else if( pass == 1 ) {
    201                        final CategoryItemLabelGenerator generator = getItemLabelGenerator(row,column);
    202                        if( generator != null && isItemLabelVisible(row, column) ) {
    203                                drawItemLabel( g2, dataset, row, column, plot, generator, bar,value<0.0 );      // 6.9.7.0 (2018/05/14) PMD Useless parentheses.
    204                        }
    205                }
    206        }
    207
    208        /**
    209         * この文字列と指定されたオブジェクトを比較します。
    210         *
    211         * 親クラスで、equals メソッドが実装されているため、警告がでます。
    212         *
    213         * @og.rev 5.1.8.0 (2010/07/01) findbug対応
    214         * @og.rev 5.1.9.0 (2010/08/01) findbug対応
    215         *
    216         * @param       object  比較するオブジェクト
    217         *
    218         * @return      Objectが等しい場合は true、そうでない場合は false
    219         */
    220        @Override
    221        public boolean equals( final Object object ) {
    222                // 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
    223                return super.equals( object ) && hsCode == ((HybsStackedBarRenderer)object).hsCode;
    224        }
    225
    226        /**
    227         * このオブジェクトのハッシュコードを取得します。
    228         *
    229         * @og.rev 5.1.8.0 (2010/07/01) findbug対応
    230         * @og.rev 5.1.9.0 (2010/08/01) findbug対応
    231         *
    232         * @return      ハッシュコード
    233         */
    234        @Override
    235        public int hashCode() { return hsCode ; }
    236}