angular5+angular图表chart

angular + material实现栅格条纹式chart表

2018-08-13  本文已影响346人  小宝薯

图下示:


Grid Chart 啊啊啊啊

设计稿到手一脸懵逼,
但是!
甲方爸爸的需求怎么能轻易放弃呢~哼哼哈嘿

Chart.js- --想了3秒钟,还是默默放弃🤦‍♀️🤦‍♀️🤦‍♀️
D3 ----搜啊搜啊搜,就是木有咱们这样滴表格系统😭😭😭
给跪了~~~~~~


向大佬低头

用到的技术

Angular5+
Angular- Material
SCSS
父子信息传递 @Input()
mock数据
ngClass三元判断
*ngFor + index索引的运用
*ngStyle
ngOnInit运用
如何遍历数字次数

一、配置(angular + material)

ng  new app-chart  --style=scss//创建angular项目
ng g c chart //创建chart组件
npm install --save @angular/material @angular/cdk //安装angular-material
npm install --save @angular/animations //安装material对应的animations

二、思路


三、项目html + scss + ts代码

// app.component.html 
<app-chart [mockData]="mockData"></app-chart>
// app.component.ts 
 mockData = {
    propertion: [
      {
        name: 'Review required',  // 每个bar的文本信息
        color: '#F1A636',  //各自对应的color和background-color
        bars: [], // 计算,用来存放判断后最终分得的格子数
        num: 30,  // 各自的数量
        total: 120,  //总数量
      },
      {
        name: 'Issue confirmed',
        color: '#398F90',
        bars: [],
        num: 25,
        total: 120,
      },
      {
        name: 'No issue',
        color: '#8DA656',
        bars: [],
        num: 65,
        total: 120,
      },
    ]
  };
// chart.component.ts
import { Component, OnInit, Input } from '@angular/core';
@Input() mockData;
<div class="chart clearfix">
  <!-- 当数据不为空 -->
  <div class="not-empty" *ngIf="!isEmpty">
      <!-- 奇数时添加class="odd" stick在下面 -->
    <div class="item" [ngClass]="{'odd': index %2 !==0}" *ngFor="let item of newMockData; index as index">
      <div class="stick" [ngStyle]="{'background-color':item.color}">
        <div class="item-text" [ngStyle]="{'color':item.color}">{{item.name}} </div>
        <div class="item-cent" [ngStyle]="{'color':item.color}">{{item.cent }}%
          <span class="item-showCent">({{item.num }}/{{item.total}})</span>
        </div>
      </div>
      <div class="bars clearfix">
<!-- 根据各自分得的小格子数,遍历显示在页面 -->
        <div class="bar" *ngFor="let i of item.bars" [ngStyle]="{'background-color':item.color}"></div>
      </div>
    </div>
  </div>
  <div class="empty" *ngIf="isEmpty">
    <div class="empty-bars bar" *ngFor="let i of emptyArray" [class.empty-bg]="isEmpty">
    </div>
  </div>
</div>
.chart {
  display: inline-block;
  height: 40px;
  position: relative;
  right: -40px;
  top: 70px;
  font-family: 'Roboto', Helvetica, Arial, sans-serif;
  .clearfix:after {
    content: '';
    display: block;
    visibility: hidden;
    line-height: 0;
    font-size: 0;
    height: 0;
    clear: none;
  }
  .bar {
    width: 5px;
    height: 40px;
    float: left;
    margin-right: 5px;
  }
  .item {
    display: inline-block;
  }
  .item-text {
    position: absolute;
    top: 2px;
    left: 10px;
    white-space: nowrap; // 禁止字体换行
    font-size: 18px;
  }
  .item-cent {
    position: absolute;
    top: 25px;
    left: 10px;
    white-space: nowrap;
    font-size: 18px;
    font-weight: 700;
  }
  .item-showCent {
    font-weight: 300;
  }
  .stick {
    width: 5px;
    height: 60px;
    position: absolute;
    top: -59px;
  }
  .odd .stick {
    top: 40px;
  }
}
// 数据全空时的小格子颜色
.empty-bg {
  background-color: rgba(40, 14, 0, 0.1);
}
export class ChartComponent implements OnInit {
  @Input() mockData;
  constructor() { }
  totalBars = 50; // 一共50个小格子
  newMockData: any;
  realData = [];
  isEmpty = false;
  emptyArray = [];
  ngOnInit() {
    // this.mockData.propertion[0].num = 100;
    this.cloneMockData();
    this.setCent();
    this.setBar();
  }
  cloneMockData() {
    // 如果传来的参数为0就直接filter掉不进入后续数据操作
    this.newMockData = JSON.parse(
      JSON.stringify(this.mockData),
    ).propertion.filter(el => {
      return el.num !== 0;
    });
    console.log('newmock data: ', this.newMockData);
  }
  // 获取每个值的百分比
  setCent() {
    this.newMockData.propertion.forEach(ele => {
      ele.cent = ((ele.num / ele.total) * 100).toFixed(0);
    });
  }
  setBar() {
    // 如果数据是空的,就显示灰色条条
    if (this.newMockData.length === 0) {
      this.isEmpty = true;
      for (let i = 0; i < this.totalBars; i++) {
        this.emptyArray.push(1);
      }
      return;
    } else {
      // [10.5, 20.3, 19.2]
      const barsAssign = this.newMockData.map(ele => {
        return (ele.num / ele.total) * this.totalBars;
      });
      let bars = []; // [10, 20, 19];
      const points = []; // [0.5, 0.3, 0.2];
      let sum = 0;

      barsAssign.forEach(ele => {
        let integer = Math.floor(ele);
        points.push(ele - integer);
        if (integer === 0) {
          integer = 1;
        }
        bars.push(integer);
        sum += integer;
      });
      while (sum < this.totalBars) {
        // 获取最大的小数位在points的索引值;进1位,
        const maxPoint = Math.max(...points);
        const index = points.indexOf(maxPoint);
        bars[index] = bars[index] + 1; // [11, 20, 19];
        points[index] = 0; // 最大points对应的bars的加1之后,就置为0,下次就不会再加。
        sum++;
      }

      // angular想遍历数字 ===》要通过转成数组方式
      bars = bars.map(ele => {
        const temp = [];
        for (let i = 0; i < ele; i++) {
          temp.push(1);
        }
        return temp;
      });
      // 填充newMockData数据里的bar作为格子数
      bars.forEach((bar, i) => {
        this.newMockData[i].bars = bar;
      });
      console.log(this.newMockData);
    }
  }
最终效果

四、复用性

github帐号:slwzero
github项目链接戳此处鸭

star我鸭~
上一篇下一篇

猜你喜欢

热点阅读