สร้างกราฟ Line Chart บน Android ด้วย AChartEngine

บทความสอนเขียนแอพ Android วันนี้ขอนำเสนอเรื่อง การเขียนกราฟ การ plot กราฟ บนแอพพลิเคชัน Android สำหรับบทความนี้จะใช้ Library ที่ชื่อว่า AChartEngine ตัวอย่าง AChartEngine ทำอะไรได้บ้าง ก็ดูได้จากลิงค์นี้ครับ ตัวอย่าง AChartEngine
มาเข้าเรื่องเลยดีกว่า บทความนี้จะเป็นการแสดง Line Chart (กราฟเส้น) แบบง่ายๆให้ดูนะครับ เริ่มต้น ก็สร้างโปรเจ็คแบบปกติ ไฟล์ที่ต้องใช้มีแค่ 2 ไฟล์ครับ คือ ไฟล์ Activity กับ ไฟล์เลเอาท์ xml
บทความนี้ใช้ Eclipse รันบน Ubuntu 14.04 นะครับ
Add Library
ทำการโหลด Library ของ AChartEngine ที่นี่ เลือกดาวน์โหลด achartengine-1.1.0.jar จากนั้นก็ import ไปที่โปรเจ็คของเรา
สำหรับ Eclipse ก็อปปี้ไฟล์ achartengine-1.1.0.jar ไปไว้ที๋โฟลเดอร์ libs
ของโปรเจ็ค จากนั้นคลิกขวาที่ไฟล์ เลือก Build Path -> Add to Build Path
สำหรับ Android Studio มีสองทางเลือกครับ คือ ก็อปไปไว้ที่โฟลเดอร์ libs
เช่นเดียวกัน จากนั้นแก้ไขไฟล์ build.gradle
โดยเพิ่ม dependencies ดังนี้
dependencies { compile fileTree(dir: 'libs', include: ['*.jar'])}
หากใครมีแล้ว ก็ไม่ต้องแก้อะไร (คำสั่งด้านบนเป็นการสั่ง compile ไฟล์ .jar ทั้งหมดที่อยู่ในโฟลเดอร์ libs)
อีกวิธีหนึ่ง สำหรับคนใช้ maven ครับ เปิด build.gradle
ที่ root โปรเจ็คนะครับ แล้วเพิ่ม นี้ลงไป
maven { url "https://repository-achartengine.forge.cloudbees.com/snapshot/"}
จะได้เป็นแบบนี้
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.11.+'
// NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files }}
allprojects { repositories { mavenCentral() maven { url "https://repository-achartengine.forge.cloudbees.com/snapshot/" } }}
ส่วนไฟล์ build.gradle
ที่อยู่ใน module ก็เพิ่ม dependencies เข้าไปเป็นแบบนี้
dependencies { compile 'com.android.support:appcompat-v7:19.+' compile 'org.achartengine:achartengine:1.2.0'}
Getting Started with AChartEngine
ก่อนที่จะไปสร้าง Line Chart (กราฟเส้น) ด้วย AChartEngine เรามาดูภาพรวม แล้วก็แต่ละคลาสที่ใช้กันก่อนครับ
XYSeries
: ตัวนี้จะเปรียบเสมือนข้อมูลของกราฟเรา เช่น รายได้ จำนวนประชากร เป็นต้นXYSeriesRenderer
: ตัวนี้จะเอาไว้ render กราฟเราครับ เช่น รูปทรงกราฟ สี รูปแบบต่างๆ ปรับแต่งได้XYMultipleSeriesDataset
: ตัวนี้คือ Dataset มันคือข้อมูลทั้งหมดของกราฟ โดยดึงมาจากXYSeries
XYMultipleSeriesRenderer
: ตัวนี้คือตัว render ทั้งกราฟครับGraphicalView
: ตัวนี้คือ View ชนิดหนึ่ง ที่เอาไว้แสดง graph ครับ
รายละเอียดคร่าวๆ ก็เป็นดังนี้ หากใครงง (แน่นอนว่าต้องงง ถ้าเพิ่งเคยทำ ต้องลองดูตัวอย่าง แล้วจะเข้าใจมากขึ้นครับ)
เริ่มสร้างกราฟ
เป้าหมายคือ ต้องการสร้างกราฟข้อมูลยอดขาย ของ 3 บริษัท ในปีๆหนึ่ง ฉะนั้นกราฟก็จะมี 3 เส้น แบบนี้
ให้เปิดคลาส MainActivity.java
ขึ้นมา โค๊ดเริ่มต้นผมเป็นแบบนี้
package com.devahoy.sample.achartengine;
import android.support.v7.app.ActionBarActivity;import android.support.v7.app.ActionBar;import android.support.v4.app.Fragment;import android.os.Bundle;import android.view.LayoutInflater;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.ViewGroup;import android.os.Build;
public class MainActivity extends ActionBarActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() .add(R.id.container, new PlaceholderFragment()) .commit(); } }
/** * A placeholder fragment containing a simple view. */ public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {}
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container, false); return rootView; } }
}
ใครใช้ fragment ไม่เป็น แนะนำให้อ่าน Android Fragment คือ? จริงๆควรจะใช้ fragment ในทุกๆโปรเจ็คนะครับ
ก่อนสร้างกราฟ เราต้องมีข้อมูลก่อน ฉะนั้น สร้างข้อมูลจำลองขึ้นมา โดยสร้างเมธอดใหม่ ชื่อ initData()
แบบนี้
private void initData() { String[] months = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
int[] index = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[] incomeA = {4000, 5500, 2300, 2100, 2500, 2900, 3200, 2400, 1800, 2100, 3500, 5900}; int[] incomeB = {3600, 4500, 3200, 3600, 2800, 1800, 2100, 2900, 2200, 2500, 4000, 3500}; int[] incomeC = {4300, 4000, 3000, 3200, 2400, 2500, 2600, 3400, 3900, 4500, 5000, 4500};}
โค๊ดด้านบน months
หมายถึง ข้อมูลที่่จะแสดงบนแกน x ระบุว่าแต่ละเดือนยอดขายเป็นยังไง ส่วน index
คือตำแหน่งของข้อมูล โดยใช้ข้อมูล 3 บริษัท ได้แก่ incomeA
, incomeB
และ incomeC
เมื่อมีข้อมูลดิบแล้ว ขั้นตอนต่อมาทำอย่างไร?
ใช้ XYSeries
เพื่อเก็บข้อมูลที่ของเราแบบนี้ (ยังอยู่ในเมธอด initData()
นะ)
XYSeries seriesA = new XYSeries("Googla");XYSeries seriesB = new XYSeries("Microsa");XYSeries seriesC = new XYSeries("Appla");
int length = index.length;for (int i = 0; i < length; i++) { seriesA.add(index[i], incomeA[i]); seriesB.add(index[i], incomeB[i]); seriesC.add(index[i], incomeC[i]);}
ต่อมาใช้ XYSeriesRenderer
เพื่อจะกำหนดให้กราฟออกมาลักษณะไหน
XYSeriesRenderer rendererA = new XYSeriesRenderer();rendererA.setPointStyle(PointStyle.CIRCLE);rendererA.setColor(Color.RED);rendererA.setLineWidth(2);
ด้านบนเป็นการกำหนด ให้แสดง กราฟเป็นจุดและเป็นสีแดง
ต่อมาสร้าง dataset ขึ้นมาโดยใช้ XYMultipleSeriesDataset
แล้วทำการเพิ่ม XYSeries
ทั้ง 3 ที่สร้างไว้ก่อนหน้านี้ ดังนี้
XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();dataset.addSeries(seriesA);dataset.addSeries(seriesB);dataset.addSeries(seriesC);
ต่อมาใช้ XYMultipleSeriesRenderer
เพื่อที่จะแสดงกราฟทั้งหมด ขึ้นตอนนี้คือการปรับแต่ง และตั้งค่ากราฟก่อนครับ
XYMultipleSeriesRenderer multipleSeriesRenderer = new XYMultipleSeriesRenderer();
for (int i = 0; i < length; i++) { multipleSeriesRenderer.addXTextLabel(i + 1, months[i]);}multipleSeriesRenderer.setChartTitle("ตัวอย่างกราฟเส้น (Line Chart)");multipleSeriesRenderer.setYTitle("ยอดขายรวม(สตางค์)");multipleSeriesRenderer.setXTitle("ปี พ.ศ. 2600");multipleSeriesRenderer.setZoomButtonsVisible(true);
จะเห็นว่าด้านบน เป็นการกำหนด ข้อความที่จะแสดงในแกน x คือแสดงเดือน ที่เก็บไว้ใน months
ส่วนอันอื่นก็ดูตามชื่อเมธอดเลยครับ มัน make sense อยู่แล้ว สุดท้าย ก็ต้องเพิ่ม XYSeriesRenderer
ไปที่ XYMultipleSeriesRenderer
ด้วย
multipleSeriesRenderer.addSeriesRenderer(rendererA);multipleSeriesRenderer.addSeriesRenderer(rendererA);multipleSeriesRenderer.addSeriesRenderer(rendererA);
ข้อควรระวัง
dataset
และXYSeriesRenderer
ต้องมีจำนวนเท่ากันนะครับdataset
เราเพิ่ม Series ไปเท่าไหร่XYMultipleSeriesRenderer
ก็ต้องเพิ่มXYSeriesRenderer
จำนวนเดียวกันด้วยครับ
ต่อมาเพิ่มอีกหนึ่งบรรทัด เป็นอันจบเมธอด initData()
drawChart(dataset, multipleSeriesRenderer);
ปล่อยให้ error ไว้ก่อนครับ เนื่องจากเรายังไม่ได้ทำการสร้าง เมธอด drawChart()
ให้ไปสร้างเลเอาท์ xml ก่อน
สร้างไฟล์ XML
การสร้างเลเอาท์ xml ไม่มีอะไรมากครับ แค่สร้าง ViewGroup
ให้มันซักตัว จะเป็น RelativeLayout
หรือ LinearLayout
ก็ได้ อย่างในบทความ ใช้ RelativeLayout
โดยใช้ไฟล์ res/layout/fragment_main.xml
จะได้ดังนี้
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/graph_container" tools:context="com.devahoy.sample.achartengine.MainActivity$PlaceholderFragment" >
</RelativeLayout>
ต่อมาที่คลาส PlachHolderFragment
ภายในคลาส MainActivity
ก็เพ่ิมนี้ลงไป
private View mView;
@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container, false); mView = rootView; initData(); return rootView;}
เพื่อจะเอา View ที่สร้างจาก onCreateView()
ไปใช้ในการสร้าง graph ครับ เลยต้องประกาศเป็นตัวแปร global ไว้
ต่อมาได้เวลาเพิ่มเมธอด drawChart()
ซักที ภายในเมธอดก็มีโค๊ดแบบนี้
private void drawChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) { GraphicalView graphView = ChartFactory.getLineChartView(getActivity(), dataset, renderer);
RelativeLayout container = (RelativeLayout) mView.findViewById(R.id.graph_container);
container.addView(graphView);}
เราใช้ GraphicalView
ซึ่งมันก็คือ View
นั่นแหละ เหมือนๆกับ TextView, EditText, Button ทั่วๆไป จากนั้น ก็ใช้ RelativeLayout
ที่เราได้สร้างไว้ใน fragment_main.xml
ที่ชื่อว่า graph_container
ทำการ addView()
ซะ เป็นอันจบ
เมื่อเปิดโปรแกรมขึ้นมา จะได้ดังภาพ
!!! แต่เดี๋ยวก่อน ในเมื่อมีกราฟ ถึง 3 อัน ซึ่งสีเหมือนกัน มันดุยาก เราอยากจะปรับเปลี่ยนสีทำยังไงละ ? แน่นอนครับ ก็ใช้ XYSeriesRenderer
เข้ามาช่วย ฉะนั้นผมสร้าง XYSeriesRenderer
เพิ่ม 2 ตัว ในเมธอด initData()
ดังนี้
XYSeriesRenderer rendererB = new XYSeriesRenderer();rendererB.setPointStyle(PointStyle.X);rendererB.setColor(Color.BLUE);rendererB.setLineWidth(2);
XYSeriesRenderer rendererC = new XYSeriesRenderer();rendererC.setPointStyle(PointStyle.DIAMOND);rendererC.setColor(Color.GREEN);rendererC.setLineWidth(2);
แล้ว XYMultipleSeriesRenderer
ก็เพิ่ม XYSeries
ให้มันซะ จาก
multipleSeriesRenderer.addSeriesRenderer(rendererA);multipleSeriesRenderer.addSeriesRenderer(rendererA);multipleSeriesRenderer.addSeriesRenderer(rendererA);
ก็จะได้เป็น
multipleSeriesRenderer.addSeriesRenderer(rendererA);multipleSeriesRenderer.addSeriesRenderer(rendererB);multipleSeriesRenderer.addSeriesRenderer(rendererC);
ลองรันโปรแกรมใหม่ ผลลัพธ์เป็นแบบนี้
ยังไม่จบ เรายังสามารถปรับแต่งกราฟได้อีก โดยผมปรับแต่ง XYMultipleSeriesRenderer
อีกเป็นแบบนี้
multipleSeriesRenderer.setXLabels(0);multipleSeriesRenderer.setBackgroundColor(Color.WHITE);multipleSeriesRenderer.setApplyBackgroundColor(true);multipleSeriesRenderer.setMarginsColor(Color.WHITE);multipleSeriesRenderer.setLabelsColor(Color.BLACK);multipleSeriesRenderer.setAxesColor(Color.GRAY);multipleSeriesRenderer.setYLabelsColor(0, Color.BLACK);multipleSeriesRenderer.setXLabelsColor(Color.BLACK);
ข้างบนคือปรับสี background ปรับสี แกน x, y ปรับตัวหนังสือ และที่สำคัญ ปรับค่า x ให้เป็น 0 เนื่องจากมันจะไปทับกับค่า เดือน ที่เรากำหนดไว้นั่นเอง
สุดท้าย ก็ได้กราฟออกมาเป็นแบบลักษณะดังรูป
สรุป
ตัวอย่างนี้ก็เป็นตัวอย่างการใช้ AChartEngine โดยการวาด Line Chart (กราฟแท่ง) แบบง่ายๆนั้นเอง หวังว่าผู้อ่านทุกท่าน สามารถนำไปประยุกต์ ปรับแต่ง ใช้งานให้เข้ากับแอพของท่านได้นะครับ
สุดท้าย โค๊ดตัวอย่าง อัพลง Github เรียบร้อยแล้ว ไปดูได้ที่นี่ครับ
- Authors
-
Chai Phonbopit
เป็น Web Dev ในบริษัทแห่งหนึ่ง ทำงานมา 10 ปีกว่าๆ ด้วยภาษาและเทคโนโลยี เช่น JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจในเรื่องของ Blockchain และ Crypto กำลังหัดเรียนภาษา Rust