All Downloads are FREE. Search and download functionalities are using the official Maven repository.

eu.webtoolkit.jwt.chart.WPieChart Maven / Gradle / Ivy

There is a newer version: 3.2.0
Show newest version
/*
 * Copyright (C) 2009 Emweb bvba, Leuven, Belgium.
 *
 * See the LICENSE file for terms of use.
 */
package eu.webtoolkit.jwt.chart;

import java.util.*;
import java.util.regex.*;
import java.io.*;
import java.lang.ref.*;
import java.util.concurrent.locks.ReentrantLock;
import javax.servlet.http.*;
import javax.servlet.*;
import eu.webtoolkit.jwt.*;
import eu.webtoolkit.jwt.chart.*;
import eu.webtoolkit.jwt.utils.*;
import eu.webtoolkit.jwt.servlet.*;

/**
 * A pie chart.
 * 

* * A pie chart renders a single data series as segments of a circle, so that the * area of each segment is proportional to the value in the data series. *

* To use a pie chart, you need to set a model using * {@link WAbstractChart#setModel(WAbstractItemModel model) * WAbstractChart#setModel()}, and use * {@link WPieChart#setLabelsColumn(int modelColumn) setLabelsColumn()} and * {@link WPieChart#setDataColumn(int modelColumn) setDataColumn()} to specify * the model column that contains the category labels and data. *

* The pie chart may be customized visually by enabling a 3D effect ( * {@link WPieChart#setPerspectiveEnabled(boolean enabled, double height) * setPerspectiveEnabled()}), or by specifying the angle of the first segment. * One or more segments may be exploded, which seperates the segment from the * rest of the pie chart, using * {@link WPieChart#setExplode(int modelRow, double factor) setExplode()}. *

* The segments may be labeled in various ways using * {@link WPieChart#setDisplayLabels(EnumSet options) setDisplayLabels()}. *

*

CSS

*

* Styling through CSS is not applicable. *

*

Example of a pie chart *

* Example of a pie chart *

*
*

* * @see eu.webtoolkit.jwt.chart.WCartesianChart */ public class WPieChart extends WAbstractChart { /** * Creates a new pie chart. */ public WPieChart(WContainerWidget parent) { super(parent); this.labelsColumn_ = -1; this.dataColumn_ = -1; this.height_ = 0.0; this.startAngle_ = 45; this.labelOptions_ = EnumSet.noneOf(LabelOption.class); this.shadow_ = false; this.pie_ = new ArrayList(); this.setPalette(new WStandardPalette(WStandardPalette.Flavour.Neutral)); this.setPreferredMethod(WPaintedWidget.Method.InlineSvgVml); this.setPlotAreaPadding(5); } /** * Creates a new pie chart. *

* Calls {@link #WPieChart(WContainerWidget parent) * this((WContainerWidget)null)} */ public WPieChart() { this((WContainerWidget) null); } /** * Sets the model column that holds the labels. *

* The labels are used only when * {@link WPieChart#setDisplayLabels(EnumSet options) setDisplayLabels()} is * called with the {@link LabelOption#TextLabel TextLabel} option. *

* The default value is -1 (not defined). *

* * @see WAbstractChart#setModel(WAbstractItemModel model) * @see WPieChart#setDisplayLabels(EnumSet options) * @see WPieChart#setDataColumn(int modelColumn) */ public void setLabelsColumn(int modelColumn) { if (this.labelsColumn_ != modelColumn) { this.labelsColumn_ = modelColumn; this.update(); } } /** * Returns the model column used for the labels. *

* * @see WPieChart#setLabelsColumn(int modelColumn) */ public int getLabelsColumn() { return this.labelsColumn_; } /** * Sets the model column that holds the data. *

* The data column should contain data that can be converted to a number, * but should not necessarily be of a number type, see also * {@link StringUtils#asNumber(Object)}. *

* The default value is -1 (not defined). *

* * @see WAbstractChart#setModel(WAbstractItemModel model) * @see WPieChart#setLabelsColumn(int modelColumn) */ public void setDataColumn(int modelColumn) { if (this.dataColumn_ != modelColumn) { this.dataColumn_ = modelColumn; this.update(); } } /** * Returns the model column used for the data. *

* * @see WPieChart#setDataColumn(int modelColumn) */ public int getDataColumn() { return this.dataColumn_; } /** * Customizes the brush used for a pie segment. *

* By default, the brush is taken from the * {@link WAbstractChart#getPalette() WAbstractChart#getPalette()}. You can * use this method to override the palette's brush for a particular * modelRow. *

* * @see WAbstractChart#setPalette(WChartPalette palette) */ public void setBrush(int modelRow, WBrush brush) { this.pie_.get(modelRow).customBrush = true; this.pie_.get(modelRow).brush = brush; this.update(); } /** * Returns the brush used for a pie segment. *

* * @see WPieChart#setBrush(int modelRow, WBrush brush) */ public WBrush getBrush(int modelRow) { if (this.pie_.get(modelRow).customBrush) { return this.pie_.get(modelRow).brush; } else { return this.getPalette().getBrush(modelRow); } } /** * Sets the explosion factor for a pie segment. *

* Separates the segment corresponding to model row modelRow from the * rest of the pie. The factor is a positive number that represents * the distance from the center as a fraction of the pie radius. Thus, 0 * corresponds to no separation, and 0.1 to a 10% separation, and 1 to a * separation where the segment tip is on the outer perimeter of the pie. *

* The default value is 0. */ public void setExplode(int modelRow, double factor) { this.pie_.get(modelRow).explode = factor; this.update(); } /** * Returns the explosion factor for a segment. *

* * @see WPieChart#setExplode(int modelRow, double factor) */ public double getExplode(int modelRow) { return this.pie_.get(modelRow).explode; } /** * Enables a 3D perspective effect on the pie. *

* A 3D perspective effect is added, which may be customized by specifying * the simulated height of the pie. The height is defined as a * fraction of the pie radius. *

* The default value is false. */ public void setPerspectiveEnabled(boolean enabled, double height) { if (!enabled && this.height_ != 0.0 || this.height_ != height) { this.height_ = height; this.update(); } } /** * Enables a 3D perspective effect on the pie. *

* Calls {@link #setPerspectiveEnabled(boolean enabled, double height) * setPerspectiveEnabled(enabled, 1.0)} */ public final void setPerspectiveEnabled(boolean enabled) { setPerspectiveEnabled(enabled, 1.0); } /** * Returns whether a 3D effect is enabled. *

* * @see WPieChart#setPerspectiveEnabled(boolean enabled, double height) */ public boolean isPerspectiveEnabled() { return this.height_ > 0.0; } /** * Enables a shadow effect. *

* A soft shadow effect is added. *

* The default value is false. */ public void setShadowEnabled(boolean enabled) { if (this.shadow_ != enabled) { this.shadow_ = enabled; this.update(); } } /** * Returns whether a shadow effect is enabled. *

* * @see WPieChart#setShadowEnabled(boolean enabled) */ public boolean isShadowEnabled() { return this.shadow_; } /** * Sets the angle of the first segment. *

* The default value is 45 degrees. */ public void setStartAngle(double startAngle) { if (this.startAngle_ != startAngle) { this.startAngle_ = startAngle; this.update(); } } /** * Returns the angle of the first segment. *

* * @see WPieChart#setStartAngle(double startAngle) */ public double getStartAngle() { return this.startAngle_; } /** * Configures if and how labels should be displayed. *

* The options must be the logical OR of a placement option ( * {@link LabelOption#Inside Inside} or {@link LabelOption#Outside Outside}) * and {@link LabelOption#TextLabel TextLabel} and/or * {@link LabelOption#TextPercentage TextPercentage}. If both TextLabel and * TextPercentage are specified, then these are combined as * "<label>: <percentage>". *

* The default value is {@link LabelOption#NoLabels NoLabels}. */ public void setDisplayLabels(EnumSet options) { this.labelOptions_ = EnumSet.copyOf(options); this.update(); } /** * Configures if and how labels should be displayed. *

* Calls {@link #setDisplayLabels(EnumSet options) * setDisplayLabels(EnumSet.of(option, options))} */ public final void setDisplayLabels(LabelOption option, LabelOption... options) { setDisplayLabels(EnumSet.of(option, options)); } /** * Returns options set for displaying labels. *

* * @see WPieChart#setDisplayLabels(EnumSet options) */ public EnumSet getDisplayLabels() { return this.labelOptions_; } /** * Creates a widget which renders the a legend item. *

* Depending on the passed LabelOption flags, the legend item widget, will * contain a text (with or without the percentage) and/or a span with the * segment's color. */ public WWidget createLegendItemWidget(int index, EnumSet options) { WContainerWidget legendItem = new WContainerWidget(); legendItem.setPadding(new WLength(4)); WText colorText = new WText(); legendItem.addWidget(colorText); colorText .setPadding(new WLength(10), EnumSet.of(Side.Left, Side.Right)); colorText.getDecorationStyle().setBackgroundColor( this.getBrush(index).getColor()); if (WApplication.getInstance().getEnvironment().agentIsIE()) { colorText.setAttributeValue("style", "zoom: 1;"); } double total = 0; if (this.dataColumn_ != -1) { for (int i = 0; i < this.getModel().getRowCount(); ++i) { double v = StringUtils.asNumber(this.getModel().getData(i, this.dataColumn_)); if (!Double.isNaN(v)) { total += v; } } } double value = StringUtils.asNumber(this.getModel().getData(index, this.dataColumn_)); if (!Double.isNaN(value)) { WString label = this.labelText(index, value, total, options); if (!(label.length() == 0)) { WText l = new WText(label); l.setPadding(new WLength(5), EnumSet.of(Side.Left)); legendItem.addWidget(l); } } return legendItem; } /** * Creates a widget which renders the a legend item. *

* Returns {@link #createLegendItemWidget(int index, EnumSet options) * createLegendItemWidget(index, EnumSet.of(option, options))} */ public final WWidget createLegendItemWidget(int index, LabelOption option, LabelOption... options) { return createLegendItemWidget(index, EnumSet.of(option, options)); } /** * Adds a data point area (used for displaying e.g. tooltips). *

* You may want to specialize this is if you wish to modify (or delete) the * area. *

*

* Note: Currently, an area is only created if the ToolTipRole * data at the data point is not empty. *

*/ public void addDataPointArea(WModelIndex index, WAbstractArea area) { (this).addArea(area); } public void paint(WPainter painter, WRectF rectangle) { double total = 0; if (this.dataColumn_ != -1) { for (int i = 0; i < this.getModel().getRowCount(); ++i) { double v = StringUtils.asNumber(this.getModel().getData(i, this.dataColumn_)); if (!Double.isNaN(v)) { total += v; } } } if (!painter.isActive()) { throw new WtException("WPieChart::paint(): painter is not active."); } WRectF rect = rectangle; if (rect.isEmpty()) { rect.assign(painter.getWindow()); } rect.setX(rect.getX() + this.getPlotAreaPadding(Side.Left)); rect.setY(rect.getY() + this.getPlotAreaPadding(Side.Top)); rect.setWidth(rect.getWidth() - this.getPlotAreaPadding(Side.Left) - this.getPlotAreaPadding(Side.Right)); rect.setHeight(rect.getHeight() - this.getPlotAreaPadding(Side.Top) - this.getPlotAreaPadding(Side.Bottom)); double side = Math.min(rect.getWidth(), rect.getHeight()); painter.save(); painter.translate(rect.getLeft() + (rect.getWidth() - side) / 2, rect .getTop() + (rect.getHeight() - side) / 2); if (!(this.getTitle().length() == 0)) { painter.translate(0, 15); } double cx = Math.floor(side / 2) + 0.5; double cy = cx; double r = (int) (side / 2 + 0.5); double h = this.height_ * r; painter.save(); if (h > 0.0) { painter.translate(0, r / 2 - h / 4); painter.scale(1, 0.5); } this.drawPie(painter, cx, cy, r, h, total); painter.restore(); painter.translate(0, -h / 4); if (!this.labelOptions_.isEmpty()) { if (total != 0) { double currentAngle = this.startAngle_; for (int i = 0; i < this.getModel().getRowCount(); ++i) { double v = StringUtils.asNumber(this.getModel().getData(i, this.dataColumn_)); if (Double.isNaN(v)) { continue; } double spanAngle = -v / total * 360; double midAngle = currentAngle + spanAngle / 2.0; double endAngle = currentAngle + spanAngle; if (endAngle < 0) { endAngle += 360; } if (midAngle < 0) { midAngle += 360; } double width = 200; double height = 30; double left; double top; double f; if (!EnumUtils .mask(this.labelOptions_, LabelOption.Outside) .isEmpty()) { f = this.pie_.get(i).explode + 1.1; } else { f = this.pie_.get(i).explode + 0.7; } double px = cx + f * r * Math .cos(-midAngle / 180.0 * 3.14159265358979323846); double py = cy + f * r * Math .sin(-midAngle / 180.0 * 3.14159265358979323846) * (h > 0 ? 0.5 : 1); EnumSet alignment = EnumSet .noneOf(AlignmentFlag.class); WColor c = painter.getPen().getColor(); if (!EnumUtils .mask(this.labelOptions_, LabelOption.Outside) .isEmpty()) { if (midAngle < 90) { left = px; top = py - height; alignment = EnumSet.copyOf(EnumSet.of( AlignmentFlag.AlignLeft, AlignmentFlag.AlignBottom)); } else { if (midAngle < 180) { left = px - width; top = py - height; alignment = EnumSet.copyOf(EnumSet.of( AlignmentFlag.AlignRight, AlignmentFlag.AlignBottom)); } else { if (midAngle < 270) { left = px - width; top = py + h / 2; alignment = EnumSet.copyOf(EnumSet.of( AlignmentFlag.AlignRight, AlignmentFlag.AlignTop)); } else { left = px; top = py + h / 2; alignment = EnumSet.copyOf(EnumSet.of( AlignmentFlag.AlignLeft, AlignmentFlag.AlignTop)); } } } } else { left = px - width / 2; top = py - height / 2; alignment = EnumSet.copyOf(EnumSet.of( AlignmentFlag.AlignCenter, AlignmentFlag.AlignMiddle)); c = this.getPalette().getFontColor(i); } painter.setPen(new WPen(c)); painter.drawText(new WRectF(left, top, width, height), alignment, this.labelText(i, v, total, this.labelOptions_)); currentAngle = endAngle; } } } if (!(this.getTitle().length() == 0)) { WFont oldFont = painter.getFont(); painter.setFont(this.getTitleFont()); painter.drawText(cx - 50, cy - r, 100, 50, EnumSet.of( AlignmentFlag.AlignCenter, AlignmentFlag.AlignTop), this .getTitle()); painter.setFont(oldFont); } painter.restore(); } protected void paintEvent(WPaintDevice paintDevice) { while (!this.getAreas().isEmpty()) { ; } WPainter painter = new WPainter(paintDevice); painter.setRenderHint(WPainter.RenderHint.Antialiasing, true); this.paint(painter); } private int labelsColumn_; private int dataColumn_; private double height_; private double startAngle_; private EnumSet labelOptions_; private boolean shadow_; static class PieData { public boolean customBrush; public WBrush brush; public double explode; public PieData() { this.customBrush = false; this.brush = new WBrush(); this.explode = 0; } } private List pie_; protected void modelChanged() { this.pie_.clear(); { int insertPos = 0; for (int ii = 0; ii < this.getModel().getRowCount(); ++ii) this.pie_.add(insertPos + ii, new WPieChart.PieData()); } ; this.update(); } protected void modelReset() { if (this.getModel().getRowCount() != (int) this.pie_.size()) { this.modelChanged(); } else { this.update(); } } protected void modelColumnsInserted(WModelIndex parent, int start, int end) { if (this.labelsColumn_ >= start) { this.labelsColumn_ += end - start + 1; } if (this.dataColumn_ >= start) { this.dataColumn_ += end - start + 1; } } protected void modelColumnsRemoved(WModelIndex parent, int start, int end) { boolean needUpdate = false; if (this.labelsColumn_ >= start) { if (this.labelsColumn_ <= end) { this.labelsColumn_ = -1; needUpdate = true; } else { this.labelsColumn_ -= end - start + 1; } } if (this.dataColumn_ >= start) { if (this.dataColumn_ <= end) { this.dataColumn_ = -1; needUpdate = true; } else { this.dataColumn_ -= end - start + 1; } } if (needUpdate) { this.update(); } } protected void modelRowsInserted(WModelIndex parent, int start, int end) { for (int i = start; i <= end; ++i) { this.pie_.add(0 + i, new WPieChart.PieData()); } this.update(); } protected void modelRowsRemoved(WModelIndex parent, int start, int end) { for (int i = end; i >= start; --i) { this.pie_.remove(0 + i); } this.update(); } protected void modelDataChanged(WModelIndex topLeft, WModelIndex bottomRight) { if (this.labelsColumn_ >= topLeft.getColumn() && this.labelsColumn_ <= bottomRight.getColumn() || this.dataColumn_ >= topLeft.getColumn() && this.dataColumn_ <= bottomRight.getColumn()) { this.update(); } } private void drawPie(WPainter painter, double cx, double cy, double r, double h, double total) { if (h > 0) { if (total == 0) { if (this.shadow_) { this.setShadow(painter); } this.drawOuter(painter, cx, cy, r, 0, -180, h); if (this.shadow_) { painter.setShadow(new WShadow()); } } else { if (this.shadow_) { this.setShadow(painter); painter.setBrush(new WBrush(WColor.black)); this.drawSlices(painter, cx, cy + h, r, total, true); painter.setShadow(new WShadow()); } List startAngles = new ArrayList(); List midAngles = new ArrayList(); { int insertPos = startAngles.size(); for (int ii = 0; ii < this.getModel().getRowCount(); ++ii) startAngles.add(insertPos + ii, 0.0); } ; { int insertPos = midAngles.size(); for (int ii = 0; ii < this.getModel().getRowCount(); ++ii) midAngles.add(insertPos + ii, 0.0); } ; int index90 = 0; double currentAngle = this.startAngle_; for (int i = 0; i < this.getModel().getRowCount(); ++i) { startAngles.set(i, currentAngle); double v = StringUtils.asNumber(this.getModel().getData(i, this.dataColumn_)); if (Double.isNaN(v)) { continue; } double spanAngle = -v / total * 360; midAngles.set(i, currentAngle + spanAngle / 2.0); double endAngle = currentAngle + spanAngle; double to90 = currentAngle - 90; if (to90 < 0) { to90 += 360; } if (spanAngle <= -to90) { index90 = i; } if (endAngle < 0) { endAngle += 360; } currentAngle = endAngle; } for (int j = 0; j < this.getModel().getRowCount(); ++j) { int i = (index90 + j) % this.getModel().getRowCount(); double v = StringUtils.asNumber(this.getModel().getData(i, this.dataColumn_)); if (Double.isNaN(v)) { continue; } double midAngle = midAngles.get(i); double endAngle = startAngles.get((i + 1) % this.getModel().getRowCount()); int n = this.nextIndex(i); boolean visible = endAngle <= 90 || endAngle >= 270; boolean drawS2 = visible && (this.pie_.get(i).explode > 0.0 || this.pie_ .get(n).explode > 0.0); if (drawS2) { double pcx = cx + r * this.pie_.get(i).explode * Math .cos(-midAngle / 180.0 * 3.14159265358979323846); double pcy = cy + r * this.pie_.get(i).explode * Math .sin(-midAngle / 180.0 * 3.14159265358979323846); painter.setBrush(darken(this.getBrush(i))); this.drawSide(painter, pcx, pcy, r, endAngle, h); } if (!visible) { break; } } for (int j = this.getModel().getRowCount(); j > 0; --j) { int i = (index90 + j) % this.getModel().getRowCount(); double v = StringUtils.asNumber(this.getModel().getData(i, this.dataColumn_)); if (Double.isNaN(v)) { continue; } double startAngle = startAngles.get(i); double midAngle = midAngles.get(i); int p = this.prevIndex(i); boolean visible = startAngle >= 90 && startAngle <= 270; boolean drawS1 = visible && (this.pie_.get(i).explode > 0.0 || this.pie_ .get(p).explode > 0.0); if (drawS1) { double pcx = cx + r * this.pie_.get(i).explode * Math .cos(-midAngle / 180.0 * 3.14159265358979323846); double pcy = cy + r * this.pie_.get(i).explode * Math .sin(-midAngle / 180.0 * 3.14159265358979323846); painter.setBrush(darken(this.getBrush(i))); this.drawSide(painter, pcx, pcy, r, startAngle, h); } if (!visible) { break; } } for (int j = 0; j < this.getModel().getRowCount(); ++j) { int i = (index90 + j) % this.getModel().getRowCount(); double v = StringUtils.asNumber(this.getModel().getData(i, this.dataColumn_)); if (Double.isNaN(v)) { continue; } double startAngle = startAngles.get(i); double midAngle = midAngles.get(i); double endAngle = startAngles.get((i + 1) % this.getModel().getRowCount()); double spanAngle = endAngle - startAngle; if (spanAngle > 0) { spanAngle -= 360; } boolean drawBorder = startAngle > 180 || endAngle > 180 || spanAngle < -180 || this.getModel().getRowCount() == 1; if (drawBorder) { painter.setBrush(darken(this.getBrush(i))); double pcx = cx + r * this.pie_.get(i).explode * Math .cos(-midAngle / 180.0 * 3.14159265358979323846); double pcy = cy + r * this.pie_.get(i).explode * Math .sin(-midAngle / 180.0 * 3.14159265358979323846); double a1 = startAngle < 180 ? 360 : startAngle; double a2 = endAngle < 180 ? 180 : endAngle; this.drawOuter(painter, pcx, pcy, r, a1, a2, h); } } } } if (total == 0) { painter.drawArc(cx - r, cy - r, r * 2, r * 2, 0, 16 * 360); } else { this.drawSlices(painter, cx, cy, r, total, false); } } private void drawSlices(WPainter painter, double cx, double cy, double r, double total, boolean shadow) { double currentAngle = this.startAngle_; for (int i = 0; i < this.getModel().getRowCount(); ++i) { double v = StringUtils.asNumber(this.getModel().getData(i, this.dataColumn_)); if (Double.isNaN(v)) { continue; } double spanAngle = -v / total * 360; double midAngle = currentAngle + spanAngle / 2.0; double pcx = cx + r * this.pie_.get(i).explode * Math.cos(-midAngle / 180.0 * 3.14159265358979323846); double pcy = cy + r * this.pie_.get(i).explode * Math.sin(-midAngle / 180.0 * 3.14159265358979323846); if (!shadow) { painter.setBrush(this.getBrush(i)); } if (v / total != 1.0) { painter.drawPie(pcx - r, pcy - r, r * 2, r * 2, (int) (currentAngle * 16), (int) (spanAngle * 16)); } else { painter.drawEllipse(pcx - r, pcy - r, r * 2, r * 2); } if (!shadow) { WModelIndex index = this.getModel().getIndex(i, this.dataColumn_); Object toolTip = index.getData(ItemDataRole.ToolTipRole); if (!(toolTip == null)) { final int SEGMENT_ANGLE = 20; WPolygonArea area = new WPolygonArea(); WTransform t = painter.getWorldTransform(); area.addPoint(t.map(new WPointF(pcx, pcy))); double sa = Math.abs(spanAngle); for (double d = 0; d < sa; d += SEGMENT_ANGLE) { double a; if (spanAngle < 0) { a = currentAngle - d; } else { a = currentAngle + d; } area .addPoint(t .map(new WPointF( pcx + r * Math .cos(-a / 180.0 * 3.14159265358979323846), pcy + r * Math .sin(-a / 180.0 * 3.14159265358979323846)))); } double a = currentAngle + spanAngle; area .addPoint(t .map(new WPointF( pcx + r * Math .cos(-a / 180.0 * 3.14159265358979323846), pcy + r * Math .sin(-a / 180.0 * 3.14159265358979323846)))); area.setToolTip(StringUtils.asString(toolTip)); this.addDataPointArea(index, area); } } double endAngle = currentAngle + spanAngle; if (endAngle < 0) { endAngle += 360; } currentAngle = endAngle; } } private void drawSide(WPainter painter, double pcx, double pcy, double r, double angle, double h) { WPainterPath path = new WPainterPath(); path.arcMoveTo(pcx - r, pcy - r, 2 * r, 2 * r, angle); path.lineTo(path.getCurrentPosition().getX(), path.getCurrentPosition() .getY() + h); path.lineTo(pcx, pcy + h); path.lineTo(pcx, pcy); path.closeSubPath(); painter.drawPath(path); } private void drawOuter(WPainter painter, double pcx, double pcy, double r, double a1, double a2, double h) { WPainterPath path = new WPainterPath(); path.arcMoveTo(pcx - r, pcy - r, 2 * r, 2 * r, a1); path.lineTo(path.getCurrentPosition().getX(), path.getCurrentPosition() .getY() + h); path.arcTo(pcx, pcy + h, r, a1, a2 - a1); path.arcTo(pcx, pcy, r, a2, a1 - a2); path.closeSubPath(); painter.drawPath(path); } private void setShadow(WPainter painter) { painter.setShadow(new WShadow(5, 15, new WColor(0, 0, 0, 20), 40)); } private int prevIndex(int i) { int r = this.getModel().getRowCount(); for (int p = i - 1; p != i; --p) { if (p < 0) { p += r; } double v = StringUtils.asNumber(this.getModel().getData(p, this.dataColumn_)); if (!Double.isNaN(v)) { return p; } } return i; } private int nextIndex(int i) { int r = this.getModel().getRowCount(); for (int n = (i + 1) % r; n != i; ++n) { double v = StringUtils.asNumber(this.getModel().getData(n, this.dataColumn_)); if (!Double.isNaN(v)) { return n; } } return i; } private static WBrush darken(WBrush brush) { WBrush result = brush; WColor c = result.getColor(); c.setRgb(c.getRed() * 3 / 4, c.getGreen() * 3 / 4, c.getBlue() * 3 / 4, c.getAlpha()); result.setColor(c); return result; } private WString labelText(int index, double v, double total, EnumSet options) { WString text = new WString(); if (!EnumUtils.mask(options, LabelOption.TextLabel).isEmpty()) { if (this.labelsColumn_ != -1) { text = StringUtils.asString(this.getModel().getData(index, this.labelsColumn_)); } } if (!EnumUtils.mask(options, LabelOption.TextPercentage).isEmpty()) { String buf = null; buf = String.format("%.3g%%", v / total * 100); if (!(text.length() == 0)) { text.append(": "); } text.append(buf); } return text; } private final WString labelText(int index, double v, double total, LabelOption option, LabelOption... options) { return labelText(index, v, total, EnumSet.of(option, options)); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy