Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Copyright (C) 2009 - 2013 SC 4ViewSoft SRL
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.codename1.charts.views;
import com.codename1.io.Log;
import java.util.List;
import com.codename1.charts.compat.Canvas;
import com.codename1.charts.util.NumberFormat;
import com.codename1.charts.compat.Paint;
import com.codename1.charts.compat.Paint.Style;
import com.codename1.charts.models.Point;
import com.codename1.charts.models.SeriesSelection;
import com.codename1.charts.renderers.DefaultRenderer;
import com.codename1.charts.renderers.SimpleSeriesRenderer;
import com.codename1.charts.renderers.XYMultipleSeriesRenderer;
import com.codename1.charts.renderers.XYMultipleSeriesRenderer.Orientation;
import com.codename1.ui.Component;
import com.codename1.ui.geom.GeneralPath;
import com.codename1.ui.geom.Rectangle2D;
import com.codename1.charts.util.ColorUtil;
import com.codename1.charts.util.MathHelper;
import com.codename1.ui.plaf.UIManager;
/**
* An abstract class to be implemented by the chart rendering classes.
*/
public abstract class AbstractChart {
/**
* The graphical representation of the chart.
*
* @param canvas the canvas to paint to
* @param x the top left x value of the view to draw to
* @param y the top left y value of the view to draw to
* @param width the width of the view to draw to
* @param height the height of the view to draw to
* @param paint the paint
*/
public abstract void draw(Canvas canvas, int x, int y, int width, int height, Paint paint);
/**
* Draws the chart background.
*
* @param renderer the chart renderer
* @param canvas the canvas to paint to
* @param x the top left x value of the view to draw to
* @param y the top left y value of the view to draw to
* @param width the width of the view to draw to
* @param height the height of the view to draw to
* @param paint the paint used for drawing
* @param newColor if a new color is to be used
* @param color the color to be used
*/
protected void drawBackground(DefaultRenderer renderer, Canvas canvas, int x, int y, int width,
int height, Paint paint, boolean newColor, int color) {
if (renderer.isApplyBackgroundColor() || newColor) {
if (newColor) {
paint.setColor(color);
} else {
paint.setColor(renderer.getBackgroundColor());
}
paint.setStyle(Style.FILL);
canvas.drawRect(x, y, x + width, y + height, paint);
}
}
/**
* Draws the chart legend.
*
* @param canvas the canvas to paint to
* @param renderer the series renderer
* @param titles the titles to go to the legend
* @param left the left X value of the area to draw to
* @param right the right X value of the area to draw to
* @param y the y value of the area to draw to
* @param width the width of the area to draw to
* @param height the height of the area to draw to
* @param legendSize the legend size
* @param paint the paint to be used for drawing
* @param calculate if only calculating the legend size
*
* @return the legend height
*/
protected int drawLegend(Canvas canvas, DefaultRenderer renderer, String[] titles, int left,
int right, int y, int width, int height, int legendSize, Paint paint, boolean calculate) {
float size = 32;
if (renderer.isShowLegend()) {
float currentX = left;
float currentY = y + height - legendSize + size;
paint.setTextAlign(Component.LEFT);
paint.setTextSize(renderer.getLegendTextSize());
int sLength = Math.min(titles.length, renderer.getSeriesRendererCount());
for (int i = 0; i < sLength; i++) {
SimpleSeriesRenderer r = renderer.getSeriesRendererAt(i);
final float lineSize = getLegendShapeWidth(i);
if (r.isShowLegendItem()) {
String text = titles[i];
if (titles.length == renderer.getSeriesRendererCount()) {
paint.setColor(r.getColor());
} else {
paint.setColor(ColorUtil.LTGRAY);
}
float[] widths = new float[text.length()];
paint.getTextWidths(text, widths);
float sum = 0;
for (float value : widths) {
sum += value;
}
float extraSize = lineSize + 10 + sum;
float currentWidth = currentX + extraSize;
if (i > 0 && getExceed(currentWidth, renderer, right, width)) {
currentX = left;
currentY += renderer.getLegendTextSize();
size += renderer.getLegendTextSize();
currentWidth = currentX + extraSize;
}
if (getExceed(currentWidth, renderer, right, width)) {
float maxWidth = right - currentX - lineSize - 10;
if (isVertical(renderer)) {
maxWidth = width - currentX - lineSize - 10;
}
int nr = paint.breakText(text, true, maxWidth, widths);
text = text.substring(0, nr) + "...";
}
if (!calculate) {
drawLegendShape(canvas, r, currentX, currentY, i, paint);
drawString(canvas, text, currentX + lineSize + 5, currentY + 5, paint);
}
currentX += extraSize;
}
}
}
return Math.round(size + renderer.getLegendTextSize());
}
/**
* Draw a multiple lines string.
*
* @param canvas the canvas to paint to
* @param text the text to be painted
* @param x the x value of the area to draw to
* @param y the y value of the area to draw to
* @param paint the paint to be used for drawing
*/
protected void drawString(Canvas canvas, String text, float x, float y, Paint paint) {
if (text != null) {
String[] lines = split(text,"\n");
Rectangle2D rect = new Rectangle2D();
int yOff = 0;
int llen = lines.length;
for (int i = 0; i < llen; ++i) {
canvas.drawText(lines[i], x, y + yOff, paint);
paint.getTextBounds(lines[i], 0, lines[i].length(), rect);
yOff = yOff + (int)rect.getHeight() + 5; // space between lines is 5
}
}
}
/**
* Calculates if the current width exceeds the total width.
*
* @param currentWidth the current width
* @param renderer the renderer
* @param right the right side pixel value
* @param width the total width
* @return if the current width exceeds the total width
*/
protected boolean getExceed(float currentWidth, DefaultRenderer renderer, int right, int width) {
boolean exceed = currentWidth > right;
if (isVertical(renderer)) {
exceed = currentWidth > width;
}
return exceed;
}
/**
* Checks if the current chart is rendered as vertical.
*
* @param renderer the renderer
* @return if the chart is rendered as a vertical one
*/
public boolean isVertical(DefaultRenderer renderer) {
return renderer instanceof XYMultipleSeriesRenderer
&& ((XYMultipleSeriesRenderer) renderer).getOrientation() == Orientation.VERTICAL;
}
/**
* Makes sure the fraction digit is not displayed, if not needed.
*
*
* @param format the number format for the label
* @param label the input label value
* @return the label without the useless fraction digit
*/
protected String getLabel(NumberFormat format, double label) {
String text = "";
if (format != null) {
text = format.format(label);
} else if (label == Math.round(label)) {
text = Math.round(label) + "";
} else {
text = label + "";
}
return text;
}
private static float[] calculateDrawPoints(float p1x, float p1y, float p2x, float p2y,
int screenHeight, int screenWidth) {
float drawP1x;
float drawP1y;
float drawP2x;
float drawP2y;
if (p1y > screenHeight) {
// Intersection with the top of the screen
float m = (p2y - p1y) / (p2x - p1x);
drawP1x = (screenHeight - p1y + m * p1x) / m;
drawP1y = screenHeight;
if (drawP1x < 0) {
// If Intersection is left of the screen we calculate the intersection
// with the left border
drawP1x = 0;
drawP1y = p1y - m * p1x;
} else if (drawP1x > screenWidth) {
// If Intersection is right of the screen we calculate the intersection
// with the right border
drawP1x = screenWidth;
drawP1y = m * screenWidth + p1y - m * p1x;
}
} else if (p1y < 0) {
float m = (p2y - p1y) / (p2x - p1x);
drawP1x = (-p1y + m * p1x) / m;
drawP1y = 0;
if (drawP1x < 0) {
drawP1x = 0;
drawP1y = p1y - m * p1x;
} else if (drawP1x > screenWidth) {
drawP1x = screenWidth;
drawP1y = m * screenWidth + p1y - m * p1x;
}
} else {
// If the point is in the screen use it
drawP1x = p1x;
drawP1y = p1y;
}
if (p2y > screenHeight) {
float m = (p2y - p1y) / (p2x - p1x);
drawP2x = (screenHeight - p1y + m * p1x) / m;
drawP2y = screenHeight;
if (drawP2x < 0) {
drawP2x = 0;
drawP2y = p1y - m * p1x;
} else if (drawP2x > screenWidth) {
drawP2x = screenWidth;
drawP2y = m * screenWidth + p1y - m * p1x;
}
} else if (p2y < 0) {
float m = (p2y - p1y) / (p2x - p1x);
drawP2x = (-p1y + m * p1x) / m;
drawP2y = 0;
if (drawP2x < 0) {
drawP2x = 0;
drawP2y = p1y - m * p1x;
} else if (drawP2x > screenWidth) {
drawP2x = screenWidth;
drawP2y = m * screenWidth + p1y - m * p1x;
}
} else {
// If the point is in the screen use it
drawP2x = p2x;
drawP2y = p2y;
}
return new float[] { drawP1x, drawP1y, drawP2x, drawP2y };
}
/**
* The graphical representation of a path.
*
* @param canvas the canvas to paint to
* @param points the points that are contained in the path to paint
* @param paint the paint to be used for painting
* @param circular if the path ends with the start point
*/
protected void drawPath(Canvas canvas, List points, Paint paint, boolean circular) {
GeneralPath path = new GeneralPath();
int height = canvas.getHeight();
int width = canvas.getWidth();
float[] tempDrawPoints;
if (points.size() < 4) {
return;
}
tempDrawPoints = calculateDrawPoints(points.get(0), points.get(1), points.get(2),
points.get(3), height, width);
path.moveTo(tempDrawPoints[0], tempDrawPoints[1]);
path.lineTo(tempDrawPoints[2], tempDrawPoints[3]);
int length = points.size();
for (int i = 4; i < length; i += 2) {
if ((points.get(i - 1) < 0 && points.get(i + 1) < 0)
|| (points.get(i - 1) > height && points.get(i + 1) > height)) {
continue;
}
tempDrawPoints = calculateDrawPoints(points.get(i - 2), points.get(i - 1), points.get(i),
points.get(i + 1), height, width);
if (!circular) {
path.moveTo(tempDrawPoints[0], tempDrawPoints[1]);
}
path.lineTo(tempDrawPoints[2], tempDrawPoints[3]);
}
if (circular) {
path.lineTo(points.get(0), points.get(1));
}
canvas.drawPath(path, paint);
}
/**
* The graphical representation of a path.
*
* @param canvas the canvas to paint to
* @param points the points that are contained in the path to paint
* @param paint the paint to be used for painting
* @param circular if the path ends with the start point
*/
protected void drawPath(Canvas canvas, float[] points, Paint paint, boolean circular) {
GeneralPath path = new GeneralPath();
int height = canvas.getHeight();
int width = canvas.getWidth();
float[] tempDrawPoints;
if (points.length < 4) {
return;
}
tempDrawPoints = calculateDrawPoints(points[0], points[1], points[2], points[3], height, width);
path.moveTo(tempDrawPoints[0], tempDrawPoints[1]);
path.lineTo(tempDrawPoints[2], tempDrawPoints[3]);
int length = points.length;
for (int i = 4; i < length; i += 2) {
if ((points[i - 1] < 0 && points[i + 1] < 0)
|| (points[i - 1] > height && points[i + 1] > height)) {
continue;
}
tempDrawPoints = calculateDrawPoints(points[i - 2], points[i - 1], points[i], points[i + 1],
height, width);
if (!circular) {
path.moveTo(tempDrawPoints[0], tempDrawPoints[1]);
}
path.lineTo(tempDrawPoints[2], tempDrawPoints[3]);
}
if (circular) {
path.lineTo(points[0], points[1]);
}
canvas.drawPath(path, paint);
}
/**
* Returns the legend shape width.
*
* @param seriesIndex the series index
* @return the legend shape width
*/
public abstract int getLegendShapeWidth(int seriesIndex);
/**
* The graphical representation of the legend shape.
*
* @param canvas the canvas to paint to
* @param renderer the series renderer
* @param x the x value of the point the shape should be drawn at
* @param y the y value of the point the shape should be drawn at
* @param seriesIndex the series index
* @param paint the paint to be used for drawing
*/
public abstract void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x,
float y, int seriesIndex, Paint paint);
/**
* Calculates the best text to fit into the available space.
*
* @param text the entire text
* @param width the width to fit the text into
* @param paint the paint
* @return the text to fit into the space
*/
private String getFitText(String text, float width, Paint paint) {
if(UIManager.getInstance().getLookAndFeel().isDefaultEndsWith3Points()) {
String newText = text;
int length = text.length();
int diff = 0;
while (paint.measureText(newText) > width && diff < length) {
diff++;
newText = text.substring(0, length - diff) + "...";
}
if (diff == length) {
newText = "...";
}
return newText;
}
return text;
}
/**
* Calculates the current legend size.
*
* @param renderer the renderer
* @param defaultHeight the default height
* @param extraHeight the added extra height
* @return the legend size
*/
protected int getLegendSize(DefaultRenderer renderer, int defaultHeight, float extraHeight) {
int legendSize = renderer.getLegendHeight();
if (renderer.isShowLegend() && legendSize == 0) {
legendSize = defaultHeight;
}
if (!renderer.isShowLegend() && renderer.isShowLabels()) {
legendSize = (int) (renderer.getLabelsTextSize() * 4 / 3 + extraHeight );
}
return legendSize;
}
/**
* Draws a text label.
*
* @param canvas the canvas
* @param labelText the label text
* @param renderer the renderer
* @param prevLabelsBounds the previous rendered label bounds
* @param centerX the round chart center on X axis
* @param centerY the round chart center on Y axis
* @param shortRadius the short radius for the round chart
* @param longRadius the long radius for the round chart
* @param currentAngle the current angle
* @param angle the label extra angle
* @param left the left side
* @param right the right side
* @param color the label color
* @param paint the paint
* @param line if a line to the label should be drawn
* @param display display the label anyway
*/
protected void drawLabel(Canvas canvas, String labelText, DefaultRenderer renderer,
List prevLabelsBounds, int centerX, int centerY, float shortRadius, float longRadius,
float currentAngle, float angle, int left, int right, int color, Paint paint, boolean line,
boolean display) {
if (renderer.isShowLabels() || display) {
paint.setColor(color);
double rAngle = Math.toRadians(90 - (currentAngle + angle / 2));
double sinValue = Math.sin(rAngle);
double cosValue = Math.cos(rAngle);
int x1 = Math.round(centerX + (float) (shortRadius * sinValue));
int y1 = Math.round(centerY + (float) (shortRadius * cosValue));
int x2 = Math.round(centerX + (float) (longRadius * sinValue));
int y2 = Math.round(centerY + (float) (longRadius * cosValue));
float size = renderer.getLabelsTextSize();
float extra = Math.max(size / 2, 10);
paint.setTextAlign(Component.LEFT);
if (x1 > x2) {
extra = -extra;
paint.setTextAlign(Component.RIGHT);
}
float xLabel = x2 + extra;
float yLabel = y2;
float width = right - xLabel;
if (x1 > x2) {
width = xLabel - left;
}
labelText = getFitText(labelText, width, paint);
float widthLabel = paint.measureText(labelText);
boolean okBounds = false;
while (!okBounds && line) {
boolean intersects = false;
int length = prevLabelsBounds.size();
for (int j = 0; j < length && !intersects; j++) {
Rectangle2D prevLabelBounds = prevLabelsBounds.get(j);
if (prevLabelBounds.intersects(xLabel, yLabel, widthLabel, size)) {
intersects = true;
yLabel = (float)Math.max(yLabel, prevLabelBounds.getY()+prevLabelBounds.getHeight());
}
}
okBounds = !intersects;
}
if (line) {
y2 = (int) (yLabel - size / 2);
canvas.drawLine(x1, y1, x2, y2, paint);
canvas.drawLine(x2, y2, x2 + extra, y2, paint);
} else {
paint.setTextAlign(Component.CENTER);
}
canvas.drawText(labelText, xLabel, yLabel, paint);
if (line) {
prevLabelsBounds.add(PkgUtils.makeRect(xLabel, yLabel, xLabel + widthLabel, yLabel + size));
}
}
}
public boolean isNullValue(double value) {
return Double.isNaN(value) || Double.isInfinite(value) || value == MathHelper.NULL_VALUE;
}
/**
* Given screen coordinates, returns the series and point indexes of a chart
* element. If there is no chart element (line, point, bar, etc) at those
* coordinates, null is returned.
*
* @param screenPoint
* @return the series and point indexes
*/
public SeriesSelection getSeriesAndPointForScreenCoordinate(Point screenPoint) {
return null;
}
private static char[] stopCharCandidates = "!@#$%^&*()?><,./+-qwertyuiop[zxcvbnm,./\\|}{".toCharArray();
private static String[] split(String input, String sep){
if ( sep.length() > 1 ){
int clen = stopCharCandidates.length;
for ( int i=0; i 1 ){
throw new RuntimeException("Failed to find appropriate stop character");
}
List parts = com.codename1.util.StringUtil.tokenize(input, sep);
String[] out = new String[parts.size()];
return parts.toArray(out);
}
}