2017年12月3日 星期日

Angular5 + ng-Chart 簡易示範

圖表的工具有很多,如果朋友們還不知道從何下手,我們就簡單超基本圖表的ng-chart來,因為最簡單~ 超級簡單因為太簡單了所以第一次玩angular的朋友也會玩出動感的圖表喔!!!

1.    下戴ng-chart.js

2.    注入到angular model
  import { ChartsModule } from 'ng2-charts/ng2-charts';

加入 imports
imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp),
    AngularFireModule.initializeApp(firebaseConfig),
    AngularFirestoreModule,
    ChartsModule
  ],

Chart.htmlè 目前先示範bar 的圖表
  <div >
    <div style="display: block">
        <canvas baseChart width="400" height="200"
        [datasets]="barChart3Data"
        [labels]="barChart3Labels"
        [options]="barChart3Options"
        [colors]="barChart3Colors"
        [legend]="barChart3Legend"
        [chartType]="barChart3Type"
        (chartHover)="chartHovered($event)"
        (chartClick)="chartClicked($event)"></canvas>
    </div>
        <ion-list>
            <ion-item >
              <ion-label><font color=black>年份</font></ion-label>
              <ion-select [(ngModel)]="choiseYear"
               (ionChange)="onChange()">
                <ion-option  *ngFor="let y of years" >{{y}}</ion-option>
              </ion-select>
            </ion-item>
          </ion-list>
  </div>

Chart.ts
客製化圖表的內容,有些參數用來顯示圖表的外觀,搭配html的參數設定
public barChart3Options: any = {
    scaleShowVerticalLines: false,
    responsive: true
  };
 
  //用來顯示橫軸的名稱
  public barChart3Labels: string[] = ['一月', '二月', '三月', '四月',
    '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];
  public barChart3Type: string = 'bar'; //圖示的類型
  public barChart3Legend: boolean = true; //顯示圖例
//這是顯示圖表的陣列格式
  public barChart3Data: any[] = [
    { data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], label: '2017' }
  ]; //用來顯示圖表的數據
 
//用來顯示圖片的背景色和前景色,依照barChart3Data的陣列值顯示不同顏包
  public barChart3Colors: Array<any> = [
    { // green
      backgroundColor: 'lightgreen',
      borderColor: 'green'
    },
    { // red
      backgroundColor: 'pink',
      borderColor: 'red'
    }
  ];

建立圖表的函式
doBarchartData(items) {
    var groupData = [];
    var data = [];
    var sumByMonth = 0;
    // 以下程式用來整理出,可以匯出到chart圖表的的陣列集合
    var example = this.myService.getGroupByMonth(items).subscribe(d => {
        this.barChart3Labels.forEach((day, key) => {
if (d.length == 0) {
          return [];
        } else if (d[this.choiseYear] == undefined) {
          return [];
        }

        if (d[this.choiseYear][key + 1] == undefined) {
data.push(0);
        } else {
          sumByMonth = 0;
          d[this.choiseYear][key + 1].forEach((data, key) => {
            sumByMonth = sumByMonth + Number(data.cost);
          })
          data.push(sumByMonth);
        }
      })

      //將結果匯出到圖表中
      this.barChart3Data = [
        { data: data, label: this.choiseYear },
      ];
    });
  }




2017年11月26日 星期日

Ionic3+ firebase

FireBase推出最新的雲端資料庫的版本(cloud Firestore), 有別之前的RealTime的資料庫,更引進rxjsoberserablesubscription的模式,讓程式更具有高彈性,我們就簡單的實作範例。

一、建立Colud Firestore
選擇下拉式選單è Cloud Firestore



二、引用firestore

安裝angularfire2  
npm install angularfire2 –save 

import { AngularFireModule } from 'angularfire2';
import {AngularFirestoreModule} from 'angularfire2/firestore';

新版的colud firestore的設定檔需要加上projectId
// AF2 Settings
export const firebaseConfig = {
  apiKey: "xxxxxxxxxxx",
  authDomain: "fiyy4.firebaseapp.com",
  databaseURL: "https://firstapp-xxxx.firebaseio.com",
  projectId: "fyyyy4",
  storageBucket: "firstyy.appspot.com",
  messagingSenderId: "1233456789"
};

注入AngularFireModuleAngularFirestoreModule
imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp),
    AngularFireModule.initializeApp(firebaseConfig),
    AngularFirestoreModule
  ],

三、ProvideràMoney_service.ts建立CRUD的函式

AngularFirestoreCollection 用來取得資料列表(查詢)
AngularFirestoreDocument 用來允許編輯/刪除資料
Observable 用來取得資料陣列有更新的值
import { Observable } from 'rxjs/Observable';
import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from 'angularfire2/firestore';

宣告
valueChange: 傳回Json的物件,不具有metadata的屬性
export class MoneyServiceProvider {
  itemCollections: AngularFirestoreCollection<any>; //資料庫傳回值型態
  items: Observable<any[]>;
  constructor(public afs: AngularFirestore) {
    this.itemCollections = this.afs.collection('moneyCost', ref => ref.orderBy('costDate')); //取回資料庫moneyCost,並依日期排序
    this.items = this.itemCollections.valueChanges();//取回值
  }

新增
snapshotChanges:可以用來異動資料庫,本身具有metadata的屬性
  public add(item) {
    this.itemCollections.add(item);
    const listObservable = this.itemCollections.snapshotChanges()
  }

刪除
AngularFirestoreDocument:取回Firestore Collection 的物件
public remove(itemID) {
    const itemDoc: AngularFirestoreDocument<any> = this.afs.doc<any>('moneyCost/' + itemID);
    itemDoc.delete();
  }

List:取得id
  public list() {
    return this.itemCollections.snapshotChanges().map(actions => {
      return actions.map(a => {
        const data = a.payload.doc.data() as any;
        data.id = a.payload.doc.id;
        return data;
      });
    });
  }

整理陣列的資料 data[key]=[{},{}]
  public groupList(items:any[]){
    let total=0;
    const groupItem=[];
    items.forEach(eachObj => {
      if(groupItem[eachObj.costDate] == undefined){
        groupItem[eachObj.costDate]=[];
      }
total=+eachObj.cost;
groupItem[eachObj.costDate].push({key:eachObj.costDate,
value:eachObj,sum:total});
    });
    return groupItem;
  }

Reduce:累加器,會自動依序陣陣值取出作運算後,傳回最終結果
public getCostSum(items):Observable<number> {
    // return 1000;
    return items.map((items: any[]) => {
      return items.reduce((prev, curr: any) => {            
              return prev + Number(curr.cost);               
      }, 0);
  })}

四、建立Componentàmoney-list.ts
import { MoneyServiceProvider } from '../../providers/money-service/money-service';
import { AngularFirestore, AngularFirestoreCollection } from 'angularfire2/firestore';

宣告物件
interface money {
  productId: string;
  costDate: string;
  cost: number;
}

export class MoneyListComponent implements OnDestroy {
  private subscription: ISubscription;
  itemCollections: AngularFirestoreCollection<money>;
  items:any[];
  obserItem:Observable<any[]>;
  groupList: any[];
  sumCost: Number;
  constructor(public afs: AngularFirestore, public moneyService: MoneyServiceProvider) {
    this.obserItem= moneyService.list(); //取回資料
    this.obserItem.subscribe(x=>{
//將取回來的值放回到變數中,透過item 在畫面上呈現
      this.items=x;
      this.groupList =moneyService.groupList(this.items);
      this.doSum (this.items); //計算總合
    });
  }
}

//累加器,會自動傳回最後值的運算結果
doSum(items) {
    this.items.reduce((prev, curr: any) =>{
         return this.sumCost = prev + Number(curr.cost);
    } ,0);
  }

  doDelete(itemId: any) {
    this.moneyService.remove(itemId); //刪除document
  }

  ngOnDestroy() {
//解除訂閱
    this.obserItem.subscribe().unsubscribe();
  }
}

Component: money-list.html

建立group pipe 呈現複雜資料結構 data[key]=[{},{}],轉換資料結構 [{key:1,value=data},{key:2,value=data}]
@Pipe({
  name: 'group',
})
export class GroupByPipe implements PipeTransform {
  transform(value: any, args: any[] = null): any {
    let keys = [];
    for (let key in value) {
      keys.push({ key: key, value: value[key] });
    }
    return keys;
  }
}

加上關鍵字group 就會將資料置換{key,value}
<ion-list>
        <ion-item-group *ngFor="let item of groupList|group">
                <ion-item-divider color="light">
                        <h3>
                                <font color=black>{{item.key|date}}</font>
                        </h3>
                </ion-item-divider>
                <ion-item *ngFor="let subItem of item.value">
                        <ion-row>
                                <ion-col col-lg-4>
                                   <font color=blue>{{subItem.value.productId}}</font>
                                </ion-col>
                                <ion-col col-lg-4>
                                <font>{{subItem.value.cost|currency}} </font>
                                </ion-col>
                                <ion-col col-lg-4>
                                        <button ion-button color="danger" small  round (click)="doDelete(subItem.value.id)">刪除</button>
                                </ion-col>
                        </ion-row>
                </ion-item>
        </ion-item-group>
       <h1><font color=red>總額<input type="hidden" [(ngModel)]="sumCost"> {{sumCost}}</font></h1>
     </ion-list>

範例如下
新增

 

列表

以上總結 Colud Firestore 可以讓資料傳回時,可先轉換資料型態/結構/運算值等等,更具有彈性。