美文网首页angular5+angular图表chart
angular + material实现栅格条纹式chart表

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

作者: 小宝薯 | 来源:发表于2018-08-13 15:56 被阅读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
    

    二、思路

    • 项目中我们从后台获取的数据mockData是readonly模式,我们前台通过JSON.parse+ JSON.stringfy对新变量newMockData进行操作
    • 一共50个小格子,按照百分比划分分对应格子数,百分比都是整数那好说,不是整数就单独拎出来小数判断,小数最大的进一位,其他的舍弃小数,
    • angular如果想遍历数字,那也要通过转换成数组的形式
      • 比如数字是8,表示我们想遍历8次,可以通过for循环push 进去一个空数据8个值,这样就达到效果了(具体见ts文件的setBar方法)
    • 通过ngClass进行三元判断给奇数相添加class,从而实现奇数时stick在下面,偶数在上面
    • 如果占比小于一个格子的话,至少我们也要保证显示一个格子,在setBar里Math.floor如果是获取对应数据占比格子数是0就进1位,
    • 如果传来的数据里有num=0的情况,在一开始获取mockData的时候就进行filter过滤掉(setbar)
    • 如果所有的数据num都是0,就改成了默认全灰


      grey

    三、项目html + scss + ts代码

    • 挂载子组件并传递数据
    // app.component.html 
    <app-chart [mockData]="mockData"></app-chart>
    
    • 父组件mock数据
    // 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,
          },
        ]
      };
    
    • 子组件input获取数据
    // chart.component.ts
    import { Component, OnInit, Input } from '@angular/core';
    @Input() mockData;
    
    • 子组件html
    <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>
    
    • 子组件scss样式
    .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);
    }
    
    • 子组件ts文件
    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);
        }
      }
    
    最终效果

    四、复用性

    • 基本上只要后台给多少数据,都能按照这种模式自动往后添加表格


      reusability

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

    star我鸭~

    相关文章

      网友评论

      • 47d53a021620:第五点,帮你修改了下setBar这个方法
        setBar() {
        // [10.5, 20.3, 19.2]
        const barsAssign = this.newMockData.propertion.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 => {
        const integer = Math.floor(ele);
        points.push(ele - integer);
        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];
        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.propertion[i].bars = bar;
        });
        }
        小宝薯:@哆_2f2f 最佳优秀奖,:bow:‍♀️:bow:‍♀️:bow:‍♀️,改改改,
      • 墙上藤蔓:赞赞,博主的angular分享很好,我也要继续学习,项目上马上就了😂

      本文标题:angular + material实现栅格条纹式chart表

      本文链接:https://www.haomeiwen.com/subject/bwwsbftx.html