Android Open Source - SpunkyCharts Price By Volume Chart Panel






From Project

Back to project page SpunkyCharts.

License

The source code is released under:

GNU General Public License

If you think the Android project SpunkyCharts listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.jogden.spunkycharts.pricebyvolumechart;
/*from  w w  w.  j a  v a 2 s  . com*/
/* 
Copyright (C) 2014 Jonathon Ogden     < jeog.dev@gmail.com >

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see http://www.gnu.org/licenses.
*/

import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.widget.RelativeLayout;

import com.jogden.spunkycharts.ApplicationPreferences;
import com.jogden.spunkycharts.ChartPanelSurfaceView;
import com.jogden.spunkycharts.R;
import com.jogden.spunkycharts.pricebyvolumechart.draw.DrawSemanticsA;
import com.jogden.spunkycharts.traditionalchart.TraditionalChartPreferences;

public class PriceByVolumeChartPanel extends RelativeLayout
    implements ChartPanelSurfaceView.DrawingThreads{
    
    public interface DrawSemantics{
        public void drawSegment(Canvas canvas, int xPos, int price);           
        public boolean hasDisplayValues();
        //DEBUG
        //public void setColor(int colorId);
    }
    
    public interface OnNewHighVolume{
        public void onNewHighVolume(int v);
    }
    
    private PriceByVolumeChartPanel _this = this;
    
    private OnNewHighVolume _callback = null;
        
    private Integer _actualHigh = 0;    

    private int _segCount = 0;
    private int _activeBucket = -1;
    
    private int _height = 0;
    private int _width = 0;
    
    private int _leftBuffer = 
        ApplicationPreferences.getSegmentVerticalPadding();
    private int _rightBuffer = 
        ApplicationPreferences.getSegmentVerticalPadding();
    private int _topBuffer = 0;
    private int _bottomBuffer = 0;

    private Handler _myHandler = null;
    
    private int _segHeight = 
         ApplicationPreferences.getSegmentWidth();
    // use traditional prefs for now
    private float _segThickness = .95f; //
     //    TraditionalChartPreferences.getDefaultSegThickness();
    private int _lineColor = 
        TraditionalChartPreferences.getDefaultLineColor();
    
    private  ArrayList<Integer> _data = new ArrayList<Integer>(); 
 
    
    private Class<? extends DrawSemanticsA> _drawSemanticsTy;    
    
    private ChartPanelSurfaceView _surface = null;

    @Override
    protected void onMeasure(
        int wMeasureSpec,  int hMeasureSpec
    ){
        super.onMeasure(wMeasureSpec,hMeasureSpec);
        _height = MeasureSpec.getSize(hMeasureSpec);
        _width = MeasureSpec.getSize(wMeasureSpec);       
    }

    /* RACE CONDITION WITH THE ADAPTER WHEN WE HAVE 
     * A NEW HIGH/LOW AND NEED TO RECREATE BUCKETS !?!?
     * 
     * DO WE NEED TO SYNC ON _activeBucket ?? ... (yes)
     */
    public  void update(int bucket, int volume)
    {      
        int v;         
        synchronized(_data){
            try{
                v = _data.get(bucket) + volume;
                _data.set(bucket,  v );             
            }catch(IndexOutOfBoundsException e){
                throw new IndexOutOfBoundsException(
                    "_data ListArray doesn't have that bucket(index)"
                    );
            }
        }
        if( v > _actualHigh){
            _actualHigh = v;
            forceDraw();
            if( _callback != null)
                _callback.onNewHighVolume(v);
        }             
        if(_activeBucket != bucket){
            _activeBucket = bucket;             
        }
        Log.d("PBV-UPDATE", "Active Bucket:" + String.valueOf(_activeBucket));
        Log.d("PBV-UDPATE", "[ " + _data.toString() + " ]");
        
        _surface.postUpdate();
    }       

    public void clear()
    {
        synchronized(_data){
            _data.clear();
            _activeBucket = -1;
        }
    }
  
    public void populate( int[] buckets ) 
    {        
        String logStr = "[ ";
        int v;
        synchronized(_data){
            _data.clear();
            for( int i  = 0; i < buckets.length; ++i) {
                v = buckets[i];
                logStr += (String.valueOf(buckets[i]) + ", ");
                if(v > _actualHigh)
                    _actualHigh = v;            
                _data.add( i, v);
            }
            if(_callback != null)
                _callback.onNewHighVolume(_actualHigh);
            logStr += " ]";
            Log.d("PBV-POPULATE", logStr);                       
            _setSegCount(buckets.length);
            _resetView();
        }
    }
    
    public void setDrawSemantics(
        Class<? extends DrawSemanticsA> type
    ){
        this._drawSemanticsTy = type;
    }
        
    public PriceByVolumeChartPanel(Context context, int segHeight) 
        {
            super(context);
            _segHeight = segHeight;   
        }
    public PriceByVolumeChartPanel(Context context, AttributeSet attrs) 
        {
            super(context, attrs);
            TypedArray ta = context.obtainStyledAttributes(
                attrs, R.styleable.CustomSpunky
                );
            _segHeight = (int) ta.getDimension(
                R.styleable.CustomSpunky_seg_width,
                ApplicationPreferences.getSegmentWidth()
                );
            ta.recycle();          
        }
    public PriceByVolumeChartPanel(
        Context context, AttributeSet attrs, int steez
        ){
            super(context, attrs, steez);
            TypedArray ta = context.obtainStyledAttributes(
                attrs, R.styleable.CustomSpunky, steez, 0
                );
            _segHeight = (int) ta.getDimension(
                R.styleable.CustomSpunky_seg_width,
                ApplicationPreferences.getSegmentWidth()
                );
            ta.recycle();          
        }
    public void init(OnNewHighVolume callback, Handler handler)
    {      
        _myHandler = handler;
        _surface = 
            (ChartPanelSurfaceView)_this.findViewWithTag(
                "primary_surface"
                );   
        _callback = callback;
        _surface.setParent(this);
    }

    public void forceDraw() 
    {
        _surface.postDraw();      
   }
    public void forceStop()
    {
        _surface.postStop();      
    }
    public void forceStart()
    {
        _surface.postStart();  
    }
    public  int getSegmentHeight() {
        return _segHeight;
    }

    public float getSegmentThickness() {
        return _segThickness;
    }

    public int buckets() {
        return _data.size();
    }

    private void _setSegCount(int count) {
        if(count <= 0)
            return;
        else
            _segCount = count;
        int h = _height / count;
        if( h <=  0)
            return;
        else          
            _segHeight = h;    
        _resetView();
    }

    public void setHorizontalBuffers(
        int leftBuffer, int rightBuffer
    ){
        _leftBuffer = leftBuffer;
        _rightBuffer = rightBuffer;     
    }
    
    public void setVerticalBuffers(
        int topBuffer, int bottomBuffer
    ){
        _topBuffer = topBuffer;
        _bottomBuffer = bottomBuffer;
    }
    
    public void setSegmentThickness(
        float thickness
    ){   
        if(thickness < 0 || thickness > 1)
            throw new IllegalArgumentException(
                "thickness arg must be between 0 and 1"
                );
        _segThickness = thickness;
    }
    
    public Thread newDrawingThreadInstance(
        SurfaceHolder holder, ChartPanelSurfaceView parent, 
        boolean active
    ){
        return new DrawingThread(holder,parent);
        //return active ? new ActiveDrawingThread(holder, parent)
            //: new NonActiveDrawingThread(holder, parent);        
    }
    
    private void _resetView()
    {
        final LayoutParams lParams = 
            (LayoutParams)_surface.getLayoutParams();
        lParams.height = _segHeight * _segCount;                  
        lParams.topMargin = _topBuffer;
        
        _myHandler.post(
            new Runnable(){
                public void run(){
                    _surface.setLayoutParams(lParams);                                
                }});          
        
    }
    
    private DrawSemantics _getDrawSemantics()
    {
        DrawSemantics drawSemantics = null;
        try {                
            drawSemantics = 
                (DrawSemantics)_drawSemanticsTy.getConstructor(
                    Context.class, int.class, int.class, int.class, 
                    int.class, float.class,  int.class, float.class
                    ).newInstance(
                        this.getContext(),_width, _segHeight,
                        _leftBuffer, _rightBuffer,
                        _actualHigh,
                        _lineColor, _segThickness
                        );               
        } catch (Exception e) {         
        }
        return drawSemantics;
    }    
    /*
    class NonActiveDrawingThread extends Thread {  
        private Canvas canvas = null;  
        private DrawSemantics drawSemantics;   
        private SurfaceHolder holder;
        private ChartPanelSurfaceView parent;
        public NonActiveDrawingThread(
            SurfaceHolder holder, ChartPanelSurfaceView parent)
            {
                super();
                this.holder = holder;
                this.parent = parent;
            }
        @Override
        public void run() {         
            int beg = 0, end = 0; /* note: we are decrementing and using [,]
            try{ 
                if( (drawSemantics = _getDrawSemantics()) == null)
                    return;                        
                synchronized(holder){            
                     canvas = holder.lockCanvas();
                     if(canvas == null)
                         return;
                     final int height = canvas.getHeight();        
                     int yPos;     
                     if(drawSemantics.hasDisplayValues()){
                        canvas.drawColor(
                            Color.TRANSPARENT,
                            android.graphics.PorterDuff.Mode.CLEAR
                            );                       

                        final int INCR = 
                            ApplicationPreferences.getTimeoutIncrement();
                        final int TOUT = 
                            ApplicationPreferences.getLongTimeout();
                        int timeOutCount = 0;       
                        
                        /* stall for a valid bucket value, leave if none 
                        while( _activeBucket < 0 || _activeBucket >= _data.size() )
                            try {                               
                                if( (timeOutCount+=INCR) > TOUT )
                                    return;
                                Thread.sleep(INCR);
                            } catch (InterruptedException e) {               
                            }  
                        
                        if( parent == _nonActiveSurfaceT){                            
                            end = _segCount;
                            beg =  _activeBucket +1 ;       
                            yPos = height-(_segHeight/2);
                            //DEBUG drawSemantics.setColor(Color.GREEN);
                        }else if(parent == _nonActiveSurfaceB){
                            end = _activeBucket;
                            beg = 0;                   
                            yPos = height-(_segHeight/2);
                           //DEBUG drawSemantics.setColor(Color.BLUE);
                        }else{
                            throw new RuntimeException(
                                "invalid parent in NonActiveDrawingThread"
                                );
                        }                 
                        if( yPos <= 0)
                            return;         
                         synchronized(_data){                            
                             Iterator<Integer> iter = _data.iterator(); 
                             Integer curr = null;                                       
                             /* move iter to beginning 
                             for( int i = 0; i < beg; ++i)
                                curr =  iter.next();
                             for( ; 
                                 beg < end && !Thread.interrupted(); 
                                 ++beg, yPos -= _segHeight 
                                 ){
                                     curr =  iter.next();                               
                                     drawSemantics.drawSegment(
                                         canvas, yPos, curr
                                         );                                                                       
                                 }            
                            }
                     }                       
                }
            }catch(IllegalStateException e){                
                throw e;
            }catch(NoSuchElementException e){               
                e.printStackTrace();
            }finally{
                if(canvas != null)
                    holder.unlockCanvasAndPost(canvas);            
            }
        }                         
    };    */
    
    /* REDRAW THE WHOLE THING; THEN OVER-WRITE
        THE ACTIVE SEG */
    class DrawingThread extends Thread 
        implements ChartPanelSurfaceView.Flags{            
        private DrawSemantics drawSemantics;
        private Canvas canvas;   
        private boolean running = true;
        private SurfaceHolder holder;   
        
        public DrawingThread(
            SurfaceHolder holder, ChartPanelSurfaceView parent
            ){
                super();
                this.holder = holder;            
            }
        public void setRunningFlag(boolean status)
        {
            running = status;
        }        
        private void draw()
        {                    
            int yPos;          
            if(canvas == null)
                return;
            final int height = canvas.getHeight();          
            
            /* check state *//* sync issues ? */
            if( _activeBucket < 0 || _activeBucket >= _data.size() ||
                !drawSemantics.hasDisplayValues() || _data.size() != _segCount)                       
                return;                     
            /* need to reset, double buffering doesn't let us retain non-active */
            canvas.drawColor(
                Color.TRANSPARENT,
                android.graphics.PorterDuff.Mode.CLEAR
                );         
                                    
            yPos = height-(_segHeight/2);                              
            if( yPos <= 0)
                return;         
            
            synchronized(_data){                            
                 Iterator<Integer> iter = _data.iterator();                 
                 for( int beg = 0; 
                     beg < _segCount && !Thread.interrupted() && iter.hasNext(); 
                     ++beg, yPos -= _segHeight 
                     ){                                                       
                         drawSemantics.drawSegment( canvas, yPos, iter.next() );                                                                       
                     }            
                }                   
        }
        @Override
        public void run() 
        {                        
            if( (drawSemantics = _getDrawSemantics()) == null)                 
                return;
            synchronized(holder){   
                try{
                    canvas = holder.lockCanvas();
                    draw(); 
                } catch(RuntimeException e) {                            
                     if( canvas != null) /* if we fail initially, clear the canvas */
                            canvas.drawColor(
                                Color.TRANSPARENT,
                                android.graphics.PorterDuff.Mode.CLEAR
                                );                                     
                } finally {
                    if(canvas != null)
                        holder.unlockCanvasAndPost(canvas);                
                }
            }
            while(running){    
                synchronized(holder){
                    try{                                                         
                        synchronized(this){
                            wait(2500);    // DEBUG
                            }  
                        try{
                            canvas = holder.lockCanvas();
                            draw();
                        } finally {
                            if(canvas != null)
                                holder.unlockCanvasAndPost(canvas);            
                        }
                    } catch (InterruptedException e) {                   
                    } catch(NoSuchElementException e) {               
                        e.printStackTrace();
                    } catch(RuntimeException e) {                
                        throw e;                          
                    }
                }                            
            }
        }
    };

}




Java Source Code List

com.jogden.spunkycharts.ApplicationPreferences.java
com.jogden.spunkycharts.BaseChartFragmentA.java
com.jogden.spunkycharts.ChartPanelSurfaceView.java
com.jogden.spunkycharts.DockingPanelActivity.java
com.jogden.spunkycharts.GlobalChartPreferences.java
com.jogden.spunkycharts.InitActivity.java
com.jogden.spunkycharts.MainApplication.java
com.jogden.spunkycharts.OpeningView.java
com.jogden.spunkycharts.animations.BaseAnimationA.java
com.jogden.spunkycharts.animations.BaseEntExAnimationA.java
com.jogden.spunkycharts.animations.BaseSelectAnimationA.java
com.jogden.spunkycharts.animations.HorizontalBulgeAnimation.java
com.jogden.spunkycharts.animations.HorizontalShakeAnimation.java
com.jogden.spunkycharts.animations.VerticalBulgeAnimation.java
com.jogden.spunkycharts.animations.VerticalShakeAnimation.java
com.jogden.spunkycharts.animations.WiggleAnimation.java
com.jogden.spunkycharts.data.DataClientLocalDebug.java
com.jogden.spunkycharts.data.DataContentService.java
com.jogden.spunkycharts.misc.BorderOverlay.java
com.jogden.spunkycharts.misc.ColorPaletteDialog.java
com.jogden.spunkycharts.misc.HideHorizontalLeftOverflowWrapper.java
com.jogden.spunkycharts.misc.OHLC.java
com.jogden.spunkycharts.misc.Pair.java
com.jogden.spunkycharts.misc.TextInput.java
com.jogden.spunkycharts.misc.Triple.java
com.jogden.spunkycharts.pricebyvolumechart.PriceByVolumeChartFragmentAdapter.java
com.jogden.spunkycharts.pricebyvolumechart.PriceByVolumeChartFragment.java
com.jogden.spunkycharts.pricebyvolumechart.PriceByVolumeChartPanel.java
com.jogden.spunkycharts.pricebyvolumechart.PriceByVolumeChartPreferences.java
com.jogden.spunkycharts.pricebyvolumechart.draw.DrawSemanticsA.java
com.jogden.spunkycharts.pricebyvolumechart.draw.DrawSemantics_SILO.java
com.jogden.spunkycharts.traditionalchart.InnerXAxis.java
com.jogden.spunkycharts.traditionalchart.TraditionalChartFragmentAdapter.java
com.jogden.spunkycharts.traditionalchart.TraditionalChartFragment.java
com.jogden.spunkycharts.traditionalchart.TraditionalChartPanel.java
com.jogden.spunkycharts.traditionalchart.TraditionalChartPreferences.java
com.jogden.spunkycharts.traditionalchart.XAxisTimeLabel.java
com.jogden.spunkycharts.traditionalchart.YAxisPriceLabel.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemanticsA_C.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemanticsA.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemantics_CANDLE.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemantics_LINE.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemantics_OC.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemantics_OHLC.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemantics_POINT.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemantics_SILO.java