16224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala/* 26224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * Copyright 2012 AndroidPlot.com 36224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * 46224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * Licensed under the Apache License, Version 2.0 (the "License"); 56224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * you may not use this file except in compliance with the License. 66224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * You may obtain a copy of the License at 76224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * 86224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * http://www.apache.org/licenses/LICENSE-2.0 96224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * 106224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * Unless required by applicable law or agreed to in writing, software 116224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * distributed under the License is distributed on an "AS IS" BASIS, 126224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * See the License for the specific language governing permissions and 146224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * limitations under the License. 156224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala */ 166224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 176224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalapackage com.androidplot.xy; 186224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 196224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalaimport android.graphics.*; 206224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalaimport android.util.Pair; 216224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalaimport com.androidplot.exception.PlotRenderException; 226224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalaimport com.androidplot.util.ValPixConverter; 236224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 246224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalaimport java.util.ArrayList; 256224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalaimport java.util.List; 266224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 276224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala/** 286224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * Renders a point as a line with the vertices marked. Requires 2 or more points to 296224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * be rendered. 306224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala */ 316224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalapublic class LineAndPointRenderer<FormatterType extends LineAndPointFormatter> extends XYSeriesRenderer<FormatterType> { 326224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 336224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala public LineAndPointRenderer(XYPlot plot) { 346224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala super(plot); 356224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 366224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 376224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala @Override 386224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala public void onRender(Canvas canvas, RectF plotArea) throws PlotRenderException { 396224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 406224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 416224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala List<XYSeries> seriesList = getPlot().getSeriesListForRenderer(this.getClass()); 426224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if (seriesList != null) { 436224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala for (XYSeries series : seriesList) { 446224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala //synchronized(series) { 456224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala drawSeries(canvas, plotArea, series, getFormatter(series)); 466224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala //} 476224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 486224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 496224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 506224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 516224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala @Override 526224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala public void doDrawLegendIcon(Canvas canvas, RectF rect, LineAndPointFormatter formatter) { 536224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala // horizontal icon: 546224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala float centerY = rect.centerY(); 556224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala float centerX = rect.centerX(); 566224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 576224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if(formatter.getFillPaint() != null) { 586224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala canvas.drawRect(rect, formatter.getFillPaint()); 596224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 606224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if(formatter.getLinePaint() != null) { 616224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala canvas.drawLine(rect.left, rect.bottom, rect.right, rect.top, formatter.getLinePaint()); 626224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 636224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 646224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if(formatter.getVertexPaint() != null) { 656224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala canvas.drawPoint(centerX, centerY, formatter.getVertexPaint()); 666224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 676224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 686224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 696224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala /** 706224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * This method exists for StepRenderer to override without having to duplicate any 716224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala * additional code. 726224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala */ 736224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala protected void appendToPath(Path path, PointF thisPoint, PointF lastPoint) { 746224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 756224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala path.lineTo(thisPoint.x, thisPoint.y); 766224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 776224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 786224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 796224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala protected void drawSeries(Canvas canvas, RectF plotArea, XYSeries series, LineAndPointFormatter formatter) { 806224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala PointF thisPoint; 816224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala PointF lastPoint = null; 826224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala PointF firstPoint = null; 836224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala Paint linePaint = formatter.getLinePaint(); 846224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 856224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala //PointF lastDrawn = null; 866224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala Path path = null; 876224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala ArrayList<Pair<PointF, Integer>> points = new ArrayList<Pair<PointF, Integer>>(series.size()); 886224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala for (int i = 0; i < series.size(); i++) { 896224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala Number y = series.getY(i); 906224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala Number x = series.getX(i); 916224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 926224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if (y != null && x != null) { 936224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala thisPoint = ValPixConverter.valToPix( 946224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala x, 956224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala y, 966224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala plotArea, 976224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala getPlot().getCalculatedMinX(), 986224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala getPlot().getCalculatedMaxX(), 996224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala getPlot().getCalculatedMinY(), 1006224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala getPlot().getCalculatedMaxY()); 1016224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala points.add(new Pair<PointF, Integer>(thisPoint, i)); 1026224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala //appendToPath(path, thisPoint, lastPoint); 1036224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } else { 1046224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala thisPoint = null; 1056224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 1066224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 1076224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if(linePaint != null && thisPoint != null) { 1086224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 1096224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala // record the first point of the new Path 1106224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if(firstPoint == null) { 1116224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala path = new Path(); 1126224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala firstPoint = thisPoint; 1136224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala // create our first point at the bottom/x position so filling 1146224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala // will look good 1156224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala path.moveTo(firstPoint.x, firstPoint.y); 1166224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 1176224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 1186224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if(lastPoint != null) { 1196224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala appendToPath(path, thisPoint, lastPoint); 1206224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 1216224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 1226224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala lastPoint = thisPoint; 1236224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } else { 1246224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if(lastPoint != null) { 1256224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala renderPath(canvas, plotArea, path, firstPoint, lastPoint, formatter); 1266224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 1276224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala firstPoint = null; 1286224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala lastPoint = null; 1296224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 1306224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 1316224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if(linePaint != null && firstPoint != null) { 1326224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala renderPath(canvas, plotArea, path, firstPoint, lastPoint, formatter); 1336224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 1346224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 1356224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala // TODO: benchmark this against drawPoints(float[]); 1366224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala Paint vertexPaint = formatter.getVertexPaint(); 1376224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala PointLabelFormatter plf = formatter.getPointLabelFormatter(); 1386224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if (vertexPaint != null || plf != null) { 1396224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala for (Pair<PointF, Integer> p : points) { 1406224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala PointLabeler pointLabeler = formatter.getPointLabeler(); 1416224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 1426224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala // if vertexPaint is available, draw vertex: 1436224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if(vertexPaint != null) { 1446224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala canvas.drawPoint(p.first.x, p.first.y, formatter.getVertexPaint()); 1456224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 1466224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 1476224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala // if textPaint and pointLabeler are available, draw point's text label: 1486224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if(plf != null && pointLabeler != null) { 1496224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala canvas.drawText(pointLabeler.getLabel(series, p.second), p.first.x + plf.hOffset, p.first.y + plf.vOffset, plf.getTextPaint()); 1506224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 1516224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 1526224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 1536224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 1546224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 1556224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala protected void renderPath(Canvas canvas, RectF plotArea, Path path, PointF firstPoint, PointF lastPoint, LineAndPointFormatter formatter) { 1566224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala Path outlinePath = new Path(path); 1576224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 1586224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala // determine how to close the path for filling purposes: 1596224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala // We always need to calculate this path because it is also used for 1606224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala // masking off for region highlighting. 1616224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala switch (formatter.getFillDirection()) { 1626224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala case BOTTOM: 1636224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala path.lineTo(lastPoint.x, plotArea.bottom); 1646224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala path.lineTo(firstPoint.x, plotArea.bottom); 1656224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala path.close(); 1666224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala break; 1676224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala case TOP: 1686224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala path.lineTo(lastPoint.x, plotArea.top); 1696224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala path.lineTo(firstPoint.x, plotArea.top); 1706224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala path.close(); 1716224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala break; 1726224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala case RANGE_ORIGIN: 1736224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala float originPix = ValPixConverter.valToPix( 1746224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala getPlot().getRangeOrigin().doubleValue(), 1756224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala getPlot().getCalculatedMinY().doubleValue(), 1766224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala getPlot().getCalculatedMaxY().doubleValue(), 1776224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala plotArea.height(), 1786224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala true); 1796224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala originPix += plotArea.top; 1806224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 1816224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala path.lineTo(lastPoint.x, originPix); 1826224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala path.lineTo(firstPoint.x, originPix); 1836224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala path.close(); 1846224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala break; 1856224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala default: 1866224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala throw new UnsupportedOperationException("Fill direction not yet implemented: " + formatter.getFillDirection()); 1876224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 1886224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 1896224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if (formatter.getFillPaint() != null) { 1906224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala canvas.drawPath(path, formatter.getFillPaint()); 1916224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 1926224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 1936224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 1946224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala //} 1956224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 1966224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala // draw any visible regions on top of the base region: 1976224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala double minX = getPlot().getCalculatedMinX().doubleValue(); 1986224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala double maxX = getPlot().getCalculatedMaxX().doubleValue(); 1996224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala double minY = getPlot().getCalculatedMinY().doubleValue(); 2006224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala double maxY = getPlot().getCalculatedMaxY().doubleValue(); 2016224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 2026224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala // draw each region: 2036224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala for (RectRegion r : RectRegion.regionsWithin(formatter.getRegions().elements(), minX, maxX, minY, maxY)) { 2046224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala XYRegionFormatter f = formatter.getRegionFormatter(r); 2056224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala RectF regionRect = r.getRectF(plotArea, minX, maxX, minY, maxY); 2066224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if (regionRect != null) { 2076224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala try { 2086224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala canvas.save(Canvas.ALL_SAVE_FLAG); 2096224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala canvas.clipPath(path); 2106224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala canvas.drawRect(regionRect, f.getPaint()); 2116224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } finally { 2126224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala canvas.restore(); 2136224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 2146224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 2156224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 2166224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 2176224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala // finally we draw the outline path on top of everything else: 2186224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala if(formatter.getLinePaint() != null) { 2196224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala canvas.drawPath(outlinePath, formatter.getLinePaint()); 2206224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 2216224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala 2226224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala path.rewind(); 2236224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala } 2246224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala} 225