hochileo / achartengine

Automatically exported from code.google.com/p/achartengine
0 stars 0 forks source link

One way to improve rendering performance for XYSeries on LineChart #368

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Hello.
I am using achartengine library in my android project and found that rendering 
for XYSeries with big number of points (>7000) is too slow.
It happpens on all my android 4.X devices :((

After checking timings for both
XYChart::draw(Canvas canvas, int x, int y, int width, int height, Paint paint)
and AbstractChart::drawPath(Canvas canvas, List<Float> points, Paint paint, 
boolean circular) (see attached timings.patch for details)
I got these results in logcat output:

D/ChartTag(11463): AbstractChart.drawPath: begin
D/ChartTag(11463): AbstractChart.drawPath:      46 ms, add points to path
D/ChartTag(11463): AbstractChart.drawPath:      492 ms, draw path
D/ChartTag(11463): AbstractChart.drawPath: end, 538 ms
D/ChartTag(11463): XYChart.draw: begin
D/ChartTag(11463): XYChart.draw:      3 ms, prepare
D/ChartTag(11463): XYChart.draw:      111 ms, add 7164 points for scale 0
D/ChartTag(11463): XYChart.draw:      0 ms, draw annotations 0
D/ChartTag(11463): XYChart.draw:      540 ms, drawSeries 0
D/ChartTag(11463): XYChart.draw:      24 ms, clickableAreasForPoints 0
D/ChartTag(11463): XYChart.draw:      12 ms, draw scale 0
D/ChartTag(11463): XYChart.draw:      12 ms, draw done
D/ChartTag(11463): XYChart.draw: end, 702 ms

It's clear that call canvas.drawPath(path, paint) in AbstractChart.drawPath is 
too long.
One possible way to avoid this issue is reduce length of path passed in 
canvas.drawPath(path, paint):

   protected void drawPath(Canvas canvas, List<Float> points, Paint paint, boolean circular) {
+    
     Path path = new Path();
     int height = canvas.getHeight();
     int width = canvas.getWidth();
+    int cnt = 0;

     float[] tempDrawPoints;
     if (points.size() < 4) {
@@ -324,11 +329,21 @@
         path.moveTo(tempDrawPoints[0], tempDrawPoints[1]);
       }
       path.lineTo(tempDrawPoints[2], tempDrawPoints[3]);
+      cnt++;
+      if (cnt > 200) { // another dirty hack
+          canvas.drawPath(path, paint);
+          path.rewind();
+          path.moveTo(tempDrawPoints[2], tempDrawPoints[3]);
+          cnt = 0;
+      }
     }
     if (circular) {
       path.lineTo(points.get(0), points.get(1));
     }

     canvas.drawPath(path, paint);
   }

(full patch in timings_and_limited_path_length.patch attachment)

There is results with limited path length:
D/ChartTag(12201): AbstractChart.drawPath: begin
D/ChartTag(12201): AbstractChart.drawPath:      75 ms, add points to path
D/ChartTag(12201): AbstractChart.drawPath:      2 ms, draw path
D/ChartTag(12201): AbstractChart.drawPath: end, 77 ms
D/ChartTag(12201): XYChart.draw: begin
D/ChartTag(12201): XYChart.draw:      2 ms, prepare
D/ChartTag(12201): XYChart.draw:      115 ms, add 7164 points for scale 0
D/ChartTag(12201): XYChart.draw:      0 ms, draw annotations 0
D/ChartTag(12201): XYChart.draw:      79 ms, drawSeries 0
D/ChartTag(12201): XYChart.draw:      25 ms, clickableAreasForPoints 0
D/ChartTag(12201): XYChart.draw:      11 ms, draw scale 0
D/ChartTag(12201): XYChart.draw:      15 ms, draw done
D/ChartTag(12201): XYChart.draw: end, 247 ms

Fixed version of XYChart.draw is 2.8 times faster

Original issue reported on code.google.com by zaitse...@gmail.com on 9 Nov 2013 at 5:48

Attachments:

GoogleCodeExporter commented 9 years ago
It's reproduced on all my android 4.x devices

Original comment by zaitse...@gmail.com on 9 Nov 2013 at 5:51

GoogleCodeExporter commented 9 years ago
I don't find it to be a good idea hacking a library just because some 
developers using it may add 7000 points and still expect it to be extremely 
responsive.

I don't see reasons why you don't just decimate your data and just push less 
than 1000 points to ACE instead of multiple thousands.

Original comment by dandrome...@gmail.com on 8 Jan 2014 at 3:31

GoogleCodeExporter commented 9 years ago

Original comment by dandrome...@gmail.com on 9 Jan 2014 at 12:41

GoogleCodeExporter commented 9 years ago
I don't want to decimate data on each zoom out and zoom in events

Original comment by zaitse...@gmail.com on 9 Jan 2014 at 3:33

GoogleCodeExporter commented 9 years ago
And I don't see API to decimate data on zooming events

Original comment by zaitse...@gmail.com on 9 Jan 2014 at 3:35