Android Open Source - SpunkyCharts Traditional 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.traditionalchart;
/*  ww w. java 2 s .c  om*/
/* 
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.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.ConditionVariable;
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.GlobalChartPreferences;
import com.jogden.spunkycharts.R;
import com.jogden.spunkycharts.misc.OHLC;
import com.jogden.spunkycharts.traditionalchart.draw.DrawSemanticsA;
import com.jogden.spunkycharts.traditionalchart.draw.DrawSemantics_LINE;


public class TraditionalChartPanel extends RelativeLayout
    implements ChartPanelSurfaceView.DrawingThreads{
    
    public interface CallBackOnRemove {
        public void call(Number number, Number number2);
    }
    public interface DrawSemantics{
        public void drawSegment(Canvas canvas, int xPos, OHLC ohlc);           
        public boolean hasDisplayValues();
    }
    
    private CallBackOnRemove _callbackOnRemove;
    
    private float _displayHigh = 0;
    private float _displayLow = Float.MAX_VALUE;
    private float _actualHigh = 0;
    private float _actualLow = Float.MAX_VALUE;
    
    private OHLC _activeSeg = new OHLC(0);
    
    private int _height = 0;
    private int _width = 0;
    
    private int _topBuffer = 
        ApplicationPreferences.getSegmentVerticalPadding();
    private int _bottomBuffer = 
        ApplicationPreferences.getSegmentVerticalPadding();
    private int _segWidth = 
         ApplicationPreferences.getSegmentWidth();
    private float _segThickness = 
         TraditionalChartPreferences.getDefaultSegThickness();
    private GlobalChartPreferences.LineThickness _lineThickness = 
        GlobalChartPreferences.getDefaultLineThickness();
    private int _lineColor = 
        TraditionalChartPreferences.getDefaultLineColor();
    
    private Deque<OHLC> _data = new ArrayDeque<OHLC>();    
    private Class<? extends DrawSemanticsA> _drawSemanticsTy;    
    
    private ChartPanelSurfaceView _activeSurface = null;
    private ChartPanelSurfaceView _nonActiveSurface = null;

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

    public <T extends Number> void update(T value)
    {
        float val = value.floatValue();
        
        if( val > _activeSeg.high ){
            _activeSeg.high = val;        
            if( val > _actualHigh ) 
                _actualHigh = val;               
        }
        if( val < _activeSeg.low ){
            _activeSeg.low = val;       
            if( val < _actualLow )
                _actualLow = val;                   
        }
       
        _activeSeg.close = val;
        _activeSurface.postUpdate();
    }
        
    public float last()
    {
        return _activeSeg.close;
    }

    public boolean isFull()
    {
        return _data.size() > 
             (_nonActiveSurface.getMeasuredWidth() / _segWidth);
    }
    
    public void clear()
    {
        synchronized(_data){
            _data.clear();
            _activeSeg = new OHLC(0);
        }
    }
  
    public synchronized void addSubSegment(
        OHLC ohlc, boolean drawNow
    ){ 
        synchronized(_data){
            _activeSeg = new OHLC(ohlc); /* copy */
            _data.addFirst(_activeSeg); 
        }
        final int max = _width / _segWidth;      
        /* issue here if width is very small and max  < 1 */
        if (_data.size() > max && max != 0) {
            OHLC pped = _dropSubSegment();            
            if ( pped != null && 
                (pped.high >= _actualHigh || pped.low <= _actualLow)
                ){
                    _resetHighLow();
                    _callbackOnRemove.call(
                        this._actualHigh, this._actualLow
                        );               
                }  
        } 
        if(drawNow)
            _nonActiveSurface.postDraw();
    }
    private synchronized OHLC _dropSubSegment()
    {        
        OHLC tmp;
        synchronized(_data){
           tmp= _data.pollLast();
        }         
        return tmp;
    }
    
    public void setDrawSemantics(
        Class<? extends DrawSemanticsA> type
    ){
        this._drawSemanticsTy = type;
    }
        
    public TraditionalChartPanel(Context context, int segWidth) 
        {
            super(context);
            _segWidth = segWidth;   
        }
    public TraditionalChartPanel(Context context, AttributeSet attrs) 
        {
            super(context, attrs);
            TypedArray ta = context.obtainStyledAttributes(
                attrs, R.styleable.CustomSpunky
                );
            _segWidth = (int) ta.getDimension(
                R.styleable.CustomSpunky_seg_width,
                ApplicationPreferences.getSegmentWidth()
                );
            ta.recycle();          
        }
    public TraditionalChartPanel(Context context, AttributeSet attrs, int steez) 
        {
            super(context, attrs, steez);
            TypedArray ta = context.obtainStyledAttributes(
                attrs, R.styleable.CustomSpunky, steez, 0
                );
            _segWidth = (int) ta.getDimension(
                R.styleable.CustomSpunky_seg_width,
                ApplicationPreferences.getSegmentWidth()
                );
            ta.recycle();          
        }
    public void init()
    {    
        _activeSurface = 
            (ChartPanelSurfaceView)this.findViewWithTag(
                "active_surface"
                );
        _nonActiveSurface = 
            (ChartPanelSurfaceView)this.findViewWithTag(
                "non_active_surface"
                );         
        _activeSurface.setParent(this);
        _nonActiveSurface.setParent(this);
    }

    public void forceDraw() {
        _activeSurface.postDraw();
        _nonActiveSurface.postDraw();
   }
    public void forceStop(){
        _activeSurface.postStop();
        _nonActiveSurface.postStop();
    }
    public void forceStart(){
        _activeSurface.postStart();
        _nonActiveSurface.postStart();
    }
    public  int getSegmentWidth() {
        return _segWidth;
    }

    public float getSegmentThickness() {
        return _segThickness;
    }

    public GlobalChartPreferences.LineThickness 
    getLineThickness() {
        return _lineThickness;
    }

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

    public void setLineColor(int colorId) {
        _lineColor = colorId;    
    }

    public void setSegmentWidth(int w) {
        if (w > 0) {
            _segWidth = w;    
        }
        LayoutParams lParams =       
            new LayoutParams(
                w, LayoutParams.MATCH_PARENT
                );
        lParams.addRule(ALIGN_PARENT_RIGHT);
        _activeSurface.setLayoutParams(lParams);
       _nonActiveSurface.postInvalidate();      
    }

    public synchronized void setYRange(
        float _displayHigh, float _displayLow,
        float _actualHigh, float _actualLow
    ){
       this._displayHigh = _displayHigh;
       this._displayLow = _displayLow;
       this._actualHigh = _actualHigh;
       this._actualLow = _actualLow;      
    }

    public void setVerticalBuffers(
        int topBuf, int bottomBuf
    ){
        this._topBuffer = topBuf;
        this._bottomBuffer = bottomBuf;     
    }

    public void setSegmentThickness(
        float thickness
    ){   
        if(thickness < 0 || thickness > 1)
            throw new IllegalArgumentException(
                "thickness arg must be between 0 and 1"
                );
        _segThickness = thickness;
    }

    public void setLineThickness(
        GlobalChartPreferences.LineThickness thickness
    ){        
        _lineThickness = thickness;        
    }

    public void setOnRemoveCallBack(
        CallBackOnRemove callback
     ){
        _callbackOnRemove = callback;      
    }
   
    private void _resetHighLow() {
        float high = 0;
        float low = Float.MAX_VALUE;       
        synchronized(_data){
            for(OHLC ohlc : _data ){
                if( ohlc.high > high )
                    high = ohlc.high;
                if( ohlc.low < low )
                    low = ohlc.low;
            }
        }
        this.setYRange(_displayHigh, _displayLow, high, low);
    }
    
    class NonActiveDrawingThread extends Thread { 
        private int xAdj; 
        private Canvas canvas = null;  
        private DrawSemantics drawSemantics;      
        private boolean isLine = false;
        private SurfaceHolder holder;
        public NonActiveDrawingThread(SurfaceHolder holder)
            {
                super();
                this.holder = holder;
            }
        private OHLC adjLineSeg(OHLC ohlc, OHLC prev)
        { /* use the prev elements close as our open */
            /* prob should just cache the val so we dont need to call this */
            OHLC tmp = new OHLC(ohlc);
            if( prev != null)
                tmp.close = prev.open;
            return tmp;
        }
        @Override
        public void run() {                     
            try{
                if( (drawSemantics = _getDrawSemantics()) == null)
                    return;
                if (drawSemantics.getClass() == DrawSemantics_LINE.class)
                    isLine = true;      
                else
                    isLine = false;
                xAdj = _segWidth / 2;                    
                synchronized(holder){            
                     canvas = holder.lockCanvas();
                     if(canvas == null)
                         return;
                     final int wdth = canvas.getWidth();
                     int xPos = wdth - xAdj;
                     if( xPos <= 0)
                         return;                        
                     if(drawSemantics.hasDisplayValues()){
                        canvas.drawColor(
                            Color.TRANSPARENT,
                            android.graphics.PorterDuff.Mode.CLEAR
                            );       
                         synchronized(_data){
                             Iterator<OHLC> iter = _data.iterator();
                             OHLC curr, prev = null;
                             if (iter.hasNext())
                                 prev = iter.next(); /* skip the first(active) */                                                  
                             for( ;                                        
                                     iter.hasNext() && xPos >= xAdj 
                                         && !Thread.interrupted();
                                     xPos-=_segWidth
                                     ){         
                                            curr = iter.next();
                                            drawSemantics.drawSegment(
                                                canvas, xPos, isLine ? adjLineSeg(curr,prev) : curr
                                                );     
                                            prev = curr;    
                                     }     
                             }
                     }                       
                }
            }finally{
                if(canvas != null)
                    holder.unlockCanvasAndPost(canvas);            
            }
        }                         
    };    
    public Thread newDrawingThreadInstance(
        SurfaceHolder holder, ChartPanelSurfaceView parent, 
        boolean active
    ){ /* disregard parent param */
        return active ? new ActiveDrawingThread(holder)
            : new NonActiveDrawingThread(holder);        
    }

    
    class ActiveDrawingThread extends Thread 
        implements ChartPanelSurfaceView.Flags{         
        private  int xAdj ;
        private DrawSemantics drawSemantics;
    //    private boolean isLine = false;
        private Canvas canvas;   
        private boolean running = false;
        private SurfaceHolder holder;
        public ActiveDrawingThread(SurfaceHolder holder)
            {
                super();
                this.holder = holder;
            }
        public void setRunningFlag(boolean status)
        {
            running = status;
        }
        private void draw()
        {
            synchronized(holder){
                canvas = holder.lockCanvas();  
                if(canvas == null)
                    return;
                canvas.drawColor(
                    Color.TRANSPARENT,
                    android.graphics.PorterDuff.Mode.CLEAR
                    );      
                drawSemantics.drawSegment(
                    canvas, xAdj, _activeSeg );
                holder.unlockCanvasAndPost(canvas);     
            }
        }     
        @Override
        public void run() {                   
            try{                          
                xAdj = _segWidth / 2;
                if( (drawSemantics = _getDrawSemantics()) == null)                 
                    return; /*
                if (drawSemantics.getClass() == DrawSemantics_LINE.class)
                    isLine = true;      
                else
                    isLine = false; */
                while(running){                           
                   synchronized(this){
                       this.wait(2500);    // DEBUG                  
                       if(drawSemantics.hasDisplayValues())
                           draw();
                   }                           
               }                  
            } catch (InterruptedException e) {         
            } 
        }
    };
    
    private DrawSemantics _getDrawSemantics()
    {
        DrawSemantics drawSemantics = null;
        try {                
            drawSemantics = _drawSemanticsTy.getConstructor(
                Context.class, int.class, int.class, int.class, 
                int.class, float.class, float.class, int.class,
                int.class, float.class
                ).newInstance(
                    this.getContext(),_segWidth,_height,
                    _topBuffer, _bottomBuffer,
                    _displayHigh,_displayLow,
                    _lineColor,_lineThickness.value,_segThickness
                    );               
        } catch (Exception e) {         
        }
        return drawSemantics;
    }
}




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