在微信小程序中繪製圖表(part3)

本期大綱

一、餅圖繪製
二、如何添加動畫效果
三、使用rollup構建項目javascript

相關閱讀:
在微信小程序中繪製圖表(part1)
在微信小程序中繪製圖表(part2)前端

關注個人 github 項目 查看完整代碼。 java

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

餅圖繪製

先看一下APIgit

clipboard.png

下面開始(使用ES6語法編寫,後面咱們能夠使用rollup編譯成ES5的語法)github

假設咱們有這樣的數據npm

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

計算出各項所佔的比例和開始的弧度小程序

calPieData.jssegmentfault

export function calPieAngle (series) {
    // 計算數據總和
    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;
    });
}

數據已經計算出來了,下面讓我開始繪製吧微信小程序

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();
    });

    ...

}

調用drawPieChart(series)就能夠獲得下面的結果:

clipboard.png

很簡單是否是,下面咱們給各區塊加上一個白色的分割線
由於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();
})

...

clipboard.png

添加動畫效果

首先讓咱們建立一個動畫工具,這個動畫工具可以傳入一些自定義的參數,好比動畫時間,可以有動畫每一步的回調以及動畫結束的回調

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;
            // 觸發動畫每一步的回調,傳入進度process
            opts.onProcess && opts.onProcess(process);
            // 動畫進行中,執行下一次動畫
            requestAnimationFrame(step);
        } else {
            // 動畫結束
            opts.onProcess && opts.onProcess(1);
            // 觸發動畫結束回調
            opts.onAnimationFinish && opts.onAnimationFinish();
        }
    }

    requestAnimationFrame(step);
}

動畫使用了requestAnimationFrame,而且已經知足了咱們上面定義的需求
在實戰中,此處的動畫都是線性的,通常咱們還會加入緩動選項,好比緩入緩出,還有一點,在微信小程序真機中IOS設備是不支持requestAnimationFrame的,因此要作降級處理,使用setTimeout查看完整的代碼

下面咱們調用animation來完成動畫效果

app.js

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

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

修改一下drawPieDataChart function,可以接受process參數

...

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

...

一樣,修改一下calPieAngle function,可以接受process參數

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;
    });
}

好了,如今咱們的動畫就能夠動起來了,相似這樣

clipboard.png

使用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是一個前端構建工具,可以將咱們的整個項目合併輸出成一個最終的編譯結果,上面咱們編寫代碼的時候都是按照不一樣的功能放到不一樣的文件中,這樣有利於後期的可持續性開發和維護,rollup正好能幫助咱們構建出最後的編譯結果

先安裝rollup

npm install -g rollup

添加對ES6的支持

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

建立.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文件中

執行

rollup -c

好了,咱們就獲得了咱們最後的項目編譯文件charts.js

下期預告

下一期中我一塊兒討論下有技術含量的內容,關於圖表中文案顯示的檢測碰撞問題,大概效果會是這樣的,紅框部分文案發生了碰撞,這裏完成了避讓,可以正常顯示

clipboard.png

相關文章
相關標籤/搜索