天天看點

在vue項目中使用Antv-f2的小案例

目錄

一.兩種引入方式

1.浏覽器引入

2.通過 npm 安裝

二. 兩種使用方式

1. 在配置了webpack或使用vue-cli建構的vue項目使用

2. 另一種使用方式是在html中直接使用

三. vue循環渲染圖表,動态綁定Id

最近在研究資料可視化,了解到會有移動端的資料可視化需求,是以看到了阿裡出的Antv F2.

官網有如下簡介: F2,一個專注于移動,開箱即用的可視化解決方案,完美支援 H5 環境同時相容多種環境(node, 小程式,weex)。完備的圖形文法理論,滿足你的各種可視化需求。專業的移動設計指引為你帶來最佳的移動端圖表體驗。 那我們在vue項目中應當如何使用呢?

一.兩種引入方式

1.浏覽器引入

既可以通過将腳本下載下傳到本地也可以直接引入線上資源。

引入線上資源

<script src="https://gw.alipayobjects.com/os/antv/assets/f2/3.4.2/f2.min.js"></script>
           

友情提醒:請按需更新版本号。

引入本地腳本

<script src="./f2.js"></script>
           

你也可以直接通過 unpkg 下載下傳。

2.通過 npm 安裝

npm install @antv/f2 --save
           

安裝完之後,在入口檔案main.js裡引入

import F2 from '@antv/f2'
Vue.prototype.$F2= F2;
           

二. 兩種使用方式

1. 在配置了webpack或使用vue-cli建構的vue項目使用

在chart.vue元件中使用F2建構圖表:

<template >
 <div class="about">
   <canvas id="myChart" width="400" height="260"></canvas>
 </div>
</template>
           
export default {
  name:'about',
  data(){
    return {
      data:[
         { genre: 'Sports', sold: 275 },
         { genre: 'Strategy', sold: 115 },
         { genre: 'Action', sold: 120 },
         { genre: 'Shooter', sold: 350 },
         { genre: 'Other', sold: 150 }
      ]
    }
  },
  methods:{
    drawChart(){
      // Step 1: 建立 Chart 對象
      const chart = new this.$F2.Chart({
        id: 'myChart',
        pixelRatio: window.devicePixelRatio // 指定分辨率
      });

      // Step 2: 載入資料源
      console.log(this.data);
      chart.source(this.data);

      // Step 3:建立圖形文法,繪制柱狀圖,由 genre 和 sold 兩個屬性決定圖形位置,genre 映射至 x 軸,sold 映射至 y 軸
      chart.interval().position('genre*sold').color('genre');

      // Step 4: 渲染圖表
      chart.render();
    }
  },
  mounted(){
    var v = this;
    this.$nextTick(()=>{
      v.drawChart();
    });
  },
  created(){

  }
}
           

為什麼我們要将調用畫圖的函數放置到vue.$nextTick函數裡面呢? 因為我們要保證dom渲染完成之後去擷取dom元素,再進行畫圖。如果這裡我們不放置到這個函數裡面,會報找不到ID的錯誤。

生成的圖表如圖:

在vue項目中使用Antv-f2的小案例

2. 另一種使用方式是在html中直接使用

html引入部分的代碼

在vue項目中使用Antv-f2的小案例
<link rel="stylesheet" href="https://gw.alipayobjects.com/os/rmsportal/YmDAMEQVbLJpVbKiRQVX.css" target="_blank" rel="external nofollow"  />
 <script src="https://gw.alipayobjects.com/os/antv/assets/f2/3.4.2/f2.min.js"></script>
 <script src="https://gw.alipayobjects.com/os/antv/assets/lib/jquery-3.2.1.min.js"></script>
 <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
 <script src="https://gw.alipayobjects.com/os/rmsportal/NjNldKHIVQRozfbAOJUW.js"></script>
           

script代碼

window.onload = function(){
        var vm = new Vue({
            el: '#app',
            data(){
                return {
                    data:[],
                }
            },
            methods:{
                getData(){
                    let list = [{"tem":"10","time":"2016-08-08 00:00:00"},{"tem":"22","time":"2016-08-08 00:10:00"},{"tem":"20","time":"2016-08-08 00:30:00"},{"tem":"26","time":"2016-08-09 00:35:00"},{"tem":"20","time":"2016-08-09 01:00:00"},{"tem":"26","time":"2016-08-09 01:20:00"},{"tem":"28","time":"2016-08-10 01:40:00"},{"tem":"20","time":"2016-08-10 02:00:00"}];
                    var chart = new F2.Chart({
                        id: 'mountNode',
                        pixelRatio: window.devicePixelRatio,
                        padding: [ 30, 24, 30, 40],
                    });
                    var defs = {
                        time: {
                            type: 'timeCat',
                            mask: 'MM-DD',
                            tickCount: 3,
                            range: [0, 1]
                        },
                        tem: {
                            tickCount: 5,
                            min: 0,
                            alias: '算力'
                        }
                    };
                    if(list.length>0){
                        chart.source(list, defs);
                        chart.axis('time', {
                            label: function label(text, index, total) {
                            var textCfg = {};
                            if (index === 0) {
                                textCfg.textAlign = 'left';
                            } else if (index === total - 1) {
                                textCfg.textAlign = 'right';
                            }
                            return textCfg;
                            }
                        });
                        chart.axis('time',{
                            label: {
                                fill: '#52FFFF'
                            }
                        });
                        chart.axis('tem',{
                            label: {
                                fill: '#52FFFF'
                            }
                        });
                        chart.tooltip({
                            showCrosshairs: true,
                        });
                        chart.guide().text({
                            position: [ 'min', 'max' ], // x 軸最小值, y 軸最大值
                            content: '算力',
                            style: {
                                textAlign: 'start',
                                textBaseline: 'top',
                                fill:'#52FFFF'
                            },
                            offsetY: -10,
                            offsetX: -10, // 可以通過 padding 值配合來保證顯示位置
                        });
                        chart.line().position('time*tem').shape('smooth');
                        chart.point().position('time*tem').shape('smooth').style({
                            stroke: '#fff',
                            lineWidth: 1
                        });
                        chart.render();
                        // document.getElementById("secondid").value = list;
                    }
                },
            },
            mounted(){
                this.getData();
            }
        })
  }
           

效果圖:

在vue項目中使用Antv-f2的小案例

三. vue循環渲染圖表,動态綁定Id

需求是後端傳回一個圖表數組, 前端需要展示這個數組,難點就是每個圖表都需要繪制一個canvas, 并且每個id需要唯一, 是以就可以借助數組下标的索引值為id名稱,具體如下:

html代碼

<template>
  <div class='chart-container'>
    <div class="chart-wraper" v-for='item,index in chartList'>
      <canvas  :id='`mountNode_${index}`' class='chart-inner'></canvas>
    </div>
  </div>
</template>
           

js代碼

import BlockService from '@/services/BlockService'
  export default {
    data(){
      return {
        chartList:[], //圖表資料
      }
    },
    methods:{
      getData(datas){
        let defs = {
            day: {
                type: 'timeCat',
                mask: 'MM-DD',
                tickCount: 3,
                range: [0, 1]
            },
            values: {
                tickCount: 5,
                min: 0,
                alias: name
            }
        };
        let chart = {};
        this.$nextTick(() =>{
          for(let i=0;i<datas.length;i++){
            chart[i] = new this.$F2.Chart({
                id: 'mountNode_'+i,
                pixelRatio: window.devicePixelRatio,
                padding: [ 30, 24, 30, 40],
            });
            if(datas[i].values.length>0){
                chart[i].source(datas[i].values, defs);
                chart[i].axis('day', {
                    label: function label(text, index, total) {
                    var textCfg = {};
                    if (0 === 0) {
                        textCfg.textAlign = 'left';
                    } else if (0 === total - 1) {
                        textCfg.textAlign = 'right';
                    }
                    return textCfg;
                    }
                });
                chart[i].axis('day',{
                    label: {
                        fill: '#52FFFF'
                    }
                });
                chart[i].axis('values',{
                    label: {
                        fill: '#52FFFF'
                    }
                });
                chart[i].tooltip({
                    showCrosshairs: true,
                });
                chart[i].guide().text({
                    position: [ 'min', 'max' ], // x 軸最小值, y 軸最大值
                    content: datas[i].name,
                    style: {
                        textAlign: 'start',
                        textBaseline: 'top',
                        fill:'#52FFFF'
                    },
                    offsetY: -20,
                    offsetX: -20, // 可以通過 padding 值配合來保證顯示位置
                });
                chart[i].line().position('day*values').shape('smooth');
                chart[i].point().position('day*values').shape('smooth').style({
                    stroke: '#fff',
                    lineWidth: 1
                });
                chart[i].render();
            }
          }
        });
        
      },
    },
    created(){
      BlockService.getChartList(this, data=>{
        this.chartList = data;
        this.getData(data);
      })
    }
  }
           

上面代碼中, datas是從接口擷取的圖表數組, 含有多個圖表的資料,後端傳回的資料接口如下:

{
    "code":0,
    "message":"success",
    "data":[
        {
            "values":[
                {
                    "values":0,
                    "day":"2019-10-18"
                }
            ],
            "name":"算力",
            "templateId":"02d9f54bd0154832b5cdddde5c479756"
        },
        {
            "values":[
                {
                    "values":99964647,
                    "day":"2019-10-18"
                }
            ],
            "name":"算率",
            "templateId":"202b9359c43d4096ad94d3eba0388612"
        }
    ]
}
           

效果圖:

在vue項目中使用Antv-f2的小案例

說明: 1. id要保證唯一, 需要使用數組下标作為辨別, 

         2. 使用f2有個不太靈活的地方, 後端傳回的資料字段名稱要跟繪制圖表的橫縱坐标對應, 上面代碼,day對應橫坐标的日期, values對應縱坐标的數值.

         3. 在繪制圖表的函數中,一定要放在vue的$nextTick方法裡, 否則會找不到對應id, 圖表無法渲染, 這點很重要.

更新

需求1: toolTip提示框顯示縱坐标名稱

實作: 

chart[i].tooltip({
     showCrosshairs: true, //是否顯示輔助線
     crosshairsStyle: {
           stroke: 'rgba(255,255,255,.25)',
           lineWidth: 2
     }, // 配置輔助線的樣式
     snap: true,
     showTitle:true,
     offsetY: 20, // y 方向的偏移
     onShow: function onShow(ev) {
          var items = ev.items;
          items[0].name = datas[i].name; //name為需要顯示的縱坐标的名稱
     },
  });
           

需求2:縱坐标需要顯示百分比%

實作:

把上面的onShow函數加上以下代碼

onShow: function onShow(ev) {
     var items = ev.items;
     items[0].name = datas[i].name;
       if(datas[i].name == '算率'){
         items[0].value = (items[0].value*100).toFixed(2) + '%';
       }else{
                        items[0].value = items[0].value
        }
  },