Pre loader

Android Custom Series Rounded Column

Android Chart - Examples

SciChart Android ships with ~90 Android Chart Examples which you can browse, play with, view the source-code and even export each SciChart Android Chart Example to a stand-alone Android Studio project. All of this is possible with the new and improved SciChart Android Examples Suite, which ships as part of our Android Charts SDK.

Download Scichart Android

The Rounded Column Chart example demonstrates how to create a custom chart series type with SciChart Android. The RoundedColumnRenderableSeries class created in the example overrides CustomRenderableSeries internalUpdateRenderPassData and internalDraw methods to provide interpolated values.

Learn more about how to create custom series including this sample in the CustomRenderableSeries documentation.

The full source code for the Android Custom Series Rounded Column Example example is included below (Scroll down!).

Did you know you can also view the source code from one of the following sources as well?

  1. Clone the SciChart.Android.Examples from Github.
  2. Or, view source and export each example to an Android Studio project from the Java version of the SciChart Android Examples app.
  3. Also the SciChart Android Trial contains the full source for the examples (link below).

DOWNLOAD THE ANDROID CHART EXAMPLES

Kotlin: RoundedColumnsExampleFragment.kt
View source code
//******************************************************************************
// SCICHART® Copyright SciChart Ltd. 2011-2021. All rights reserved.
//
// Web: http://www.scichart.com
// Support: support@scichart.com
// Sales:   sales@scichart.com
//
// RoundedColumnsExampleFragment.kt is part of SCICHART®, High Performance Scientific Charts
// For full terms and conditions of the license, see http://www.scichart.com/scichart-eula/
//
// This source code is protected by international copyright law. Unauthorized
// reproduction, reverse-engineering, or distribution of all or any portion of
// this source code is strictly prohibited.
//
// This source code contains confidential and proprietary trade secrets of
// SciChart Ltd., and should at no time be copied, transferred, sold,
// distributed or made available without express written permission.
//******************************************************************************

package com.scichart.examples.fragments.examples2d.createCustomCharts.kt

import android.view.animation.AccelerateDecelerateInterpolator
import android.view.animation.OvershootInterpolator
import com.scichart.charting.model.RenderableSeriesCollection
import com.scichart.charting.visuals.SciChartSurface
import com.scichart.charting.visuals.renderableSeries.FastColumnRenderableSeries
import com.scichart.charting.visuals.renderableSeries.data.ColumnRenderPassData
import com.scichart.charting.visuals.renderableSeries.data.ISeriesRenderPassData
import com.scichart.charting.visuals.renderableSeries.hitTest.ColumnHitProvider
import com.scichart.charting.visuals.renderableSeries.hitTest.NearestColumnPointProvider
import com.scichart.core.model.FloatValues
import com.scichart.data.model.DoubleRange
import com.scichart.drawing.common.IAssetManager2D
import com.scichart.drawing.common.IRenderContext2D
import com.scichart.examples.fragments.base.ExampleSingleChartBaseFragment
import com.scichart.examples.utils.Constant
import com.scichart.examples.utils.interpolator.DefaultInterpolator
import com.scichart.examples.utils.scichartExtensions.*

class RoundedColumnsExampleFragment : ExampleSingleChartBaseFragment() {
    override fun initExample(surface: SciChartSurface) {
        surface.suspendUpdates {
            xAxes { numericAxis { growBy = DoubleRange(0.1, 0.1)} }
            yAxes { numericAxis { growBy = DoubleRange(0.2, 0.2)} }

            renderableSeries {
                roundedColumnsRenderableSeries {
                    xyDataSeries<Int, Int> {
                        val yValues = intArrayOf(50, 35, 61, 58, 50, 50, 40, 53, 55, 23, 45, 12, 59, 60)
                        for (i in yValues.indices) {
                            append(i, yValues[i])
                        }
                    }
                    fillBrushStyle = SolidBrushStyle(0xFF634e96)

                    scaleAnimation {
                        interpolator = DefaultInterpolator.getInterpolator()
                        duration = Constant.ANIMATION_DURATION
                        startDelay = Constant.ANIMATION_START_DELAY
                    }
                }
            }

            chartModifiers { defaultModifiers() }
        }
    }

    /**
     * A CustomRenderableSeries example which draws Rounded Columns
     */
    class RoundedColumnsRenderableSeries : FastColumnRenderableSeries(ColumnRenderPassData(), ColumnHitProvider(), NearestColumnPointProvider()) {
        private val topEllipseBuffer = FloatValues()
        private val rectsBuffer = FloatValues()
        private val bottomEllipseBuffer = FloatValues()

        override fun disposeCachedData() {
            super.disposeCachedData()

            topEllipseBuffer.disposeItems()
            rectsBuffer.disposeItems()
            bottomEllipseBuffer.disposeItems()
        }

        override fun internalDraw(renderContext: IRenderContext2D, assetManager: IAssetManager2D, renderPassData: ISeriesRenderPassData) {
            // Don't draw transparent series
            if (opacity == 0f) return

            val fillBrush = fillBrushStyle
            if (fillBrush == null || !fillBrush.isVisible) return

            val rpd = renderPassData as ColumnRenderPassData
            val diameter = rpd.columnPixelWidth
            updateDrawingBuffers(rpd, diameter, rpd.zeroLineCoord)

            val brush = assetManager.createBrush(fillBrush)
            renderContext.fillRects(rectsBuffer.itemsArray, 0, rectsBuffer.size(), brush)
            renderContext.drawEllipses(topEllipseBuffer.itemsArray, 0, topEllipseBuffer.size(), diameter, diameter, brush)
            renderContext.drawEllipses(bottomEllipseBuffer.itemsArray, 0, bottomEllipseBuffer.size(), diameter, diameter, brush)
        }

        private fun updateDrawingBuffers(renderPassData: ColumnRenderPassData, columnPixelWidth: Float, zeroLine: Float) {
            val halfWidth = columnPixelWidth / 2

            topEllipseBuffer.setSize(renderPassData.pointsCount() * 2)
            rectsBuffer.setSize(renderPassData.pointsCount() * 4)
            bottomEllipseBuffer.setSize(renderPassData.pointsCount() * 2)

            val topArray = topEllipseBuffer.itemsArray
            val rectsArray = rectsBuffer.itemsArray
            val bottomArray = bottomEllipseBuffer.itemsArray

            val xCoordsArray = renderPassData.xCoords.itemsArray
            val yCoordsArray = renderPassData.yCoords.itemsArray
            for (i in 0 until renderPassData.pointsCount()) {
                val x = xCoordsArray[i]
                val y = yCoordsArray[i]

                topArray[i * 2] = x
                topArray[i * 2 + 1] = y - halfWidth

                rectsArray[i * 4] = x - halfWidth
                rectsArray[i * 4 + 1] = y - halfWidth
                rectsArray[i * 4 + 2] = x + halfWidth
                rectsArray[i * 4 + 3] = zeroLine + halfWidth

                bottomArray[i * 2] = x
                bottomArray[i * 2 + 1] = zeroLine + halfWidth
            }
        }
    }

    fun RenderableSeriesCollection.roundedColumnsRenderableSeries(init: RoundedColumnsRenderableSeries.() -> Unit) {
        add(RoundedColumnsRenderableSeries().apply(init))
    }
}
Java: RoundedColumnsExampleFragment.java
View source code
//******************************************************************************
// SCICHART® Copyright SciChart Ltd. 2011-2021. All rights reserved.
//
// Web: http://www.scichart.com
// Support: support@scichart.com
// Sales:   sales@scichart.com
//
// RoundedColumnsExampleFragment.java is part of SCICHART®, High Performance Scientific Charts
// For full terms and conditions of the license, see http://www.scichart.com/scichart-eula/
//
// This source code is protected by international copyright law. Unauthorized
// reproduction, reverse-engineering, or distribution of all or any portion of
// this source code is strictly prohibited.
//
// This source code contains confidential and proprietary trade secrets of
// SciChart Ltd., and should at no time be copied, transferred, sold,
// distributed or made available without express written permission.
//******************************************************************************

package com.scichart.examples.fragments.examples2d.createCustomCharts;

import android.content.Context;
import android.util.DisplayMetrics;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;

import androidx.annotation.NonNull;

import com.scichart.charting.model.dataSeries.IDataSeries;
import com.scichart.charting.model.dataSeries.IXyDataSeries;
import com.scichart.charting.visuals.SciChartSurface;
import com.scichart.charting.visuals.axes.IAxis;
import com.scichart.charting.visuals.renderableSeries.FastColumnRenderableSeries;
import com.scichart.charting.visuals.renderableSeries.FastLineRenderableSeries;
import com.scichart.charting.visuals.renderableSeries.data.ColumnRenderPassData;
import com.scichart.charting.visuals.renderableSeries.data.ISeriesRenderPassData;
import com.scichart.charting.visuals.renderableSeries.hitTest.ColumnHitProvider;
import com.scichart.charting.visuals.renderableSeries.hitTest.NearestColumnPointProvider;
import com.scichart.core.framework.UpdateSuspender;
import com.scichart.core.model.FloatValues;
import com.scichart.drawing.common.BrushStyle;
import com.scichart.drawing.common.IAssetManager2D;
import com.scichart.drawing.common.IBrush2D;
import com.scichart.drawing.common.IRenderContext2D;
import com.scichart.drawing.common.SolidBrushStyle;
import com.scichart.examples.fragments.base.ExampleSingleChartBaseFragment;
import com.scichart.examples.utils.Constant;
import com.scichart.examples.utils.interpolator.DefaultInterpolator;

import java.util.Collections;

public class RoundedColumnsExampleFragment extends ExampleSingleChartBaseFragment {

    @Override
    protected void initExample(@NonNull SciChartSurface surface) {
        final IAxis xAxis = sciChartBuilder.newNumericAxis().withGrowBy(0.1d, 0.1d).build();
        final IAxis yAxis = sciChartBuilder.newNumericAxis().withGrowBy(0.2d, 0.2d).build();

        final IXyDataSeries<Integer, Integer> dataSeries = sciChartBuilder.newXyDataSeries(Integer.class, Integer.class).build();
        final int[] yValues = {50, 35, 61, 58, 50, 50, 40, 53, 55, 23, 45, 12, 59, 60};
        for (int i = 0; i < yValues.length; i++) {
            dataSeries.append(i, yValues[i]);
        }

        final RoundedColumnsRenderableSeries rSeries = new RoundedColumnsRenderableSeries.Builder(requireContext())
                .withDataSeries(dataSeries)
                .withFillColor(0xFF634e96)
                .build();

        UpdateSuspender.using(surface, () -> {
            Collections.addAll(surface.getXAxes(), xAxis);
            Collections.addAll(surface.getYAxes(), yAxis);
            Collections.addAll(surface.getRenderableSeries(), rSeries);
            Collections.addAll(surface.getChartModifiers(), sciChartBuilder.newModifierGroupWithDefaultModifiers().build());

            sciChartBuilder.newAnimator(rSeries).withScaleTransformation().withInterpolator(DefaultInterpolator.getInterpolator()).withDuration(Constant.ANIMATION_DURATION).withStartDelay(Constant.ANIMATION_START_DELAY).start();
        });
    }

    /**
     * A CustomRenderableSeries example which draws Rounded Columns
     */
     static class RoundedColumnsRenderableSeries extends FastColumnRenderableSeries {

        private final FloatValues topEllipseBuffer = new FloatValues();
        private final FloatValues rectsBuffer = new FloatValues();
        private final FloatValues bottomEllipseBuffer = new FloatValues();

        /**
         * Creates a new instance of {@link FastLineRenderableSeries} class
         */
        public RoundedColumnsRenderableSeries() {
            super(new ColumnRenderPassData(), new ColumnHitProvider(), new NearestColumnPointProvider());
        }

        @Override
        protected void disposeCachedData() {
            super.disposeCachedData();

            topEllipseBuffer.disposeItems();
            rectsBuffer.disposeItems();
            bottomEllipseBuffer.disposeItems();
        }

        @Override
        protected void internalDraw(IRenderContext2D renderContext, IAssetManager2D assetManager, ISeriesRenderPassData renderPassData) {
            // Don't draw transparent series
            final float opacity = getOpacity();
            if (opacity == 0) return;

            final BrushStyle fillBrush = getFillBrushStyle();
            if (fillBrush == null || !fillBrush.isVisible()) return;

            final ColumnRenderPassData rpd = (ColumnRenderPassData) renderPassData;
            final float diameter = rpd.columnPixelWidth;
            updateDrawingBuffers(rpd, diameter, rpd.zeroLineCoord);

            final IBrush2D brush = assetManager.createBrush(fillBrush);
            renderContext.fillRects(rectsBuffer.getItemsArray(), 0, rectsBuffer.size(), brush);
            renderContext.drawEllipses(topEllipseBuffer.getItemsArray(), 0, topEllipseBuffer.size(), diameter, diameter, brush);
            renderContext.drawEllipses(bottomEllipseBuffer.getItemsArray(), 0, bottomEllipseBuffer.size(), diameter, diameter, brush);
        }

        private void updateDrawingBuffers(ColumnRenderPassData renderPassData, float columnPixelWidth, float zeroLine) {
            final float halfWidth = columnPixelWidth / 2;

            topEllipseBuffer.setSize(renderPassData.pointsCount() * 2);
            rectsBuffer.setSize(renderPassData.pointsCount() * 4);
            bottomEllipseBuffer.setSize(renderPassData.pointsCount() * 2);

            final float[] topArray = topEllipseBuffer.getItemsArray();
            final float[] rectsArray = rectsBuffer.getItemsArray();
            final float[] bottomArray = bottomEllipseBuffer.getItemsArray();

            final float[] xCoordsArray = renderPassData.xCoords.getItemsArray();
            final float[] yCoordsArray = renderPassData.yCoords.getItemsArray();
            for (int i = 0, count = renderPassData.pointsCount(); i < count; i++) {
                final float x = xCoordsArray[i];
                final float y = yCoordsArray[i];

                topArray[i * 2] = x;
                topArray[i * 2 + 1] = y - halfWidth;

                rectsArray[i * 4] = x - halfWidth;
                rectsArray[i * 4 + 1] = y - halfWidth;
                rectsArray[i * 4 + 2] = x + halfWidth;
                rectsArray[i * 4 + 3] = zeroLine + halfWidth;

                bottomArray[i * 2] = x;
                bottomArray[i * 2 + 1] = zeroLine + halfWidth;
            }
        }

        public static class Builder {
            private final DisplayMetrics displayMetrics;
            private final RoundedColumnsRenderableSeries renderableSeries;

            public Builder(Context context) {
                this.displayMetrics = context.getResources().getDisplayMetrics();
                this.renderableSeries = new RoundedColumnsRenderableSeries();
            }

            public Builder withDataSeries(IDataSeries<?,?> dataSeries) {
                renderableSeries.setDataSeries(dataSeries);
                return this;
            }

            public Builder withFillColor(int fillColor) {
                renderableSeries.setFillBrushStyle(new SolidBrushStyle(fillColor));
                return this;
            }

            public RoundedColumnsRenderableSeries build() {
                return renderableSeries;
            }
        }
    }
}
Back to Android Chart Examples