小程序模板網(wǎng)

在微信小程序中繪制圖表:餅圖繪制及如何添加動畫效果

發(fā)布時間:2018-04-08 11:48 所屬欄目:小程序開發(fā)教程
本文作者:musiq1989,制作了一個很不錯的圖表插件,并且寫了幾篇文章來輔助,這是其中的第三篇,本系列已經(jīng)獲得授權,來自授權地址

本期大綱

1、餅圖繪制
2、如何添加動畫效果
3、使用rollup構建項目

關注我的 github 項目 查看完整代碼。

很久沒更新了,最近事情比較多,今天來把坑填上!

餅圖繪制

先看一下API

下面開始(使用ES6語法編寫,后面我們可以是用rollup編譯成ES5的語法)

假設我們有這樣的數(shù)據(jù)


const series = [
    {data: 15, color: '#7cb5ec'},
    {data: 35, color: '#f7a35c'},
    {data: 78, color: '#434348'},
    {data: 63, color: '#90ed7d'}
];

計算出各項所占的比例和開始的弧度

calPieData.js


export function calPieAngle (series) {
    // 計算數(shù)據(jù)總和
    let count = 0;
    series.forEach((item) => {
        count += item.data;
    });

    // 計算出開始的弧度和所占比例
    let startAngle = 0;
    return series.map((item) => {
        item.proportion = item.data / count;
        item.startAngle = startAngle;
        startAngle += 2 * Math.PI * item.proportion;
        return item;
    });
}

數(shù)據(jù)已經(jīng)計算出來了,下面讓我開始繪制吧

drawPieChart.js


import { calPieAngle } from 'calPieData'

export default function drawPieChart (series) {
    ...

    let pieSeries = calPieAngle(series);
    pieSeries.forEach((item) => {
        context.beginPath();
        // 設置填充顏色
        context.setFillStyle(item.color);
        // 移動到原點
        context.moveTo(100, 100);    
        // 繪制弧度
        context.arc(100, 100, 80, item.startAngle, item.startAngle + 2 * Math.PI * item.proportion);
        context.closePath();
        context.fill();
    });

    ...

}

調(diào)用drawPieChart(series)就可以得到下面的結果:

很簡單是不是,下面我們給各區(qū)塊加上一個白色的分割線
因為arc實際上是繪制了一條路徑,所以我們簡單的stroke描邊一下就可以了



...

context.setLineWidth(2);
context.setStrokeStyle('#ffffff');
pieSeries.forEach((item) => {
    context.beginPath();
    context.setFillStyle(item.color);
    context.moveTo(100, 100);    
    context.arc(100, 100, 80, item.startAngle, item.startAngle + 2 * Math.PI * item.proportion);
    context.closePath();
    context.fill();
    context.stroke();
})

...

添加動畫效果

首先讓我們創(chuàng)建一個動畫工具,這個動畫工具能夠傳入一些自定義的參數(shù),比如動畫時間,能夠有動畫每一步的回調(diào)以及動畫結束的回調(diào)

animation.js


export default function Animation (opts) {
    // 處理用戶傳入的動畫時間,默認為1000ms
    // 因為用戶有可能傳入duration為0,所以不能用opts.duration = opts.duration || 1000 來做默認值處理
    // 否則用戶傳入0也會處理成默認值1000
    opts.duration = typeof opts.duration === 'undefined' ? 1000 : opts.duration;
    
    let startTimeStamp = null;

    function step (timestamp) {
        if (startTimeStamp === null) {
            startTimeStamp = timestamp;
        } 
        if (timestamp - startTimeStamp < opts.duration) {
            // 計算出動畫的進度
            let process = (timestamp - startTimeStamp) / opts.duration;
            // 觸發(fā)動畫每一步的回調(diào),傳入進度process
            opts.onProcess && opts.onProcess(process);
            // 動畫進行中,執(zhí)行下一次動畫
            requestAnimationFrame(step);
        } else {
            // 動畫結束
            opts.onProcess && opts.onProcess(1);
            // 觸發(fā)動畫結束回調(diào)
            opts.onAnimationFinish && opts.onAnimationFinish();
        }
    }

    requestAnimationFrame(step);
}

動畫使用了requestAnimationFrame,并且已經(jīng)滿足了我們上面定義的需求
在實戰(zhàn)中,此處的動畫都是線性的,一般我們還會加入緩動選項,比如緩入,緩出,還有一點,在微信小程序真機中IOS設備是不支持requestAnimationFrame的,所以要做降級處理,使用setTimeout,查看完整的代碼

下面我們調(diào)用animation來完成動畫效果

app.js


import Animation from 'animation'
import drawPieChart from 'drawPieChart'

Animation({
    duration: 1000,
    onProcess: (process) => {
        drawPieDataChart(series, process);
    }
});

修改一下drawPieDataChart function,能夠接受process參數(shù)



...

export default function drawPieChart (series, process = 1) {
    ...
    // 將process傳入給calPieAngle,計算出對應進度下的圖表角度數(shù)據(jù)
    let pieSeries = calPieAngle(series, process);

...

同樣,修改一下calPieAngle function,能夠接受process參數(shù)



export function calPieAngle (series, process = 1) {
    ...

    // 計算出開始的弧度和所占比例
    let startAngle = 0;
    return series.map((item) => {
        // 計算出當前動畫進度的比例
        item.proportion = item.data / count * process;
        item.startAngle = startAngle;
        startAngle += 2 * Math.PI * item.proportion;
        return item;
    });
}

好了,現(xiàn)在我們的動畫就可以動起來了,類似這樣

使用rollup構建項目

Rollup is a next-generation JavaScript module bundler. Author your app or library using ES2015 modules, then efficiently bundle them up into a single file for use in browsers and Node.js.

也就是說rollup是一個前端構建工具,能夠將我們的整個項目合并輸出成一個最終的編譯結果,上面我們編寫代碼的時候都是按照不同的功能放到不同的文件中,這樣有利于后期的可持續(xù)性開發(fā)和維護,rollup正好能幫助我們構建出最后的編譯結果

先安裝rollup


npm install -g rollup

添加對ES6的支持


npm install --save-dev rollup-plugin-babel
npm install --save-dev babel-preset-es2015-rollup

創(chuàng)建.babelrc文件在項目根目錄,告訴babel轉義時使用哪個presets


{
  "presets": ["es2015-rollup"],
}

好了剩下最后一步,定義我們的rollup.config.js配置文件


import babel from 'rollup-plugin-babel';

export default {
  // 入口文件
  entry: 'app.js',
  // 輸出格式,這里使用commonJS
  format: 'cjs',
  // 輸出文件
  dest: 'dist/charts.js',
  // 使用babel進行ES6轉ES5
  plugins: [
      babel({
          exclude: 'node_modules/**',
      })
  ]
};

rollup會從入口文件開始,查找我們的依賴(import),逐級往下深入,把依賴的文件全部收集起來并合并到一起,最后輸出到我們定義的dest文件中

執(zhí)行


rollup -c

好了,我們就得到了我們最后的項目編譯文件charts.js

下期預告

下一期中我一起討論下有技術含量的內(nèi)容,關于圖表中文案顯示的檢測碰撞問題,大概效果會是這樣的,紅框部分文案發(fā)生了碰撞,這里完成了避讓,能夠正常顯示



易優(yōu)小程序(企業(yè)版)+靈活api+前后代碼開源 碼云倉庫:starfork
本文地址:http://www.u-renovate.com/wxmini/doc/course/23151.html 復制鏈接 如需定制請聯(lián)系易優(yōu)客服咨詢:800182392 點擊咨詢
QQ在線咨詢