成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

開發(fā)適用于微信小程序的跨平臺圖表庫:part1

mingde / 1749人閱讀

摘要:寫在前面微信小程序出來已經(jīng)有一段時間了,上也有很多人開源了很多項目。但是由于微信平臺的限制底層能力調(diào)用為一系列封裝,圖表的制作一直是個比較頭疼的問題。這個圖形庫已經(jīng)完成基本的圖形建設(shè),已經(jīng)支持瀏覽器,,以及微信小程序等環(huán)境。

寫在前面

微信小程序出來已經(jīng)有一段時間了,github上也有很多人開源了很多項目。但是由于微信平臺的限制(底層Canvas能力調(diào)用為一系列JSBridge封裝),圖表的制作一直是個比較頭疼的問題。當(dāng)前的成熟圖表庫無法正常運行,即使經(jīng)過改造,性能也有很大問題。

當(dāng)前已經(jīng)有做的比較好的圖表庫,如xiaolin3303的 wx-charts,但是只是為小程序量身定做的,在普通的H5頁面就無法執(zhí)行。因此,在開發(fā)中萌生了寫一個多環(huán)境下兼容的圖形庫的念頭。

這個圖形庫已經(jīng)完成基本的圖形建設(shè),已經(jīng)支持PC瀏覽器,WAP,React以及微信小程序等環(huán)境。并上傳至github,大家可以自由使用:wx-chart,并歡迎在Issues中提出BUG以及修改建議。

效果圖

無圖無真相,首先上個效果圖吧

工程結(jié)構(gòu)

wx-chart 圖形庫參考了眾多圖形庫的構(gòu)建,分為三層,如下圖所示:

最下方一層為兼容層,其中最主要的是 WxCanvas 和 WxCanvasRenderingContext2D
用于兼容瀏覽器以及微信小程序的環(huán)境。在本章節(jié)中,一會兒會展開講解實現(xiàn)原理。
中間層為基礎(chǔ)組件以及動畫庫,最上層為實現(xiàn)的各種圖形。這兩部分會在后續(xù)的章節(jié)中再另行闡述。

WxCanvas & WxCanvasRenderingContext2D

首先,我們實現(xiàn)這個中間層的目的很明確,就是完成一套與W3C Canvas一致的接口層,忽略小程序的底層接口,并使得上層調(diào)用時與普通Canvas使用方式一致。

小程序的架構(gòu)是類似于React Native的JSBridge混合開發(fā)模式,因此其Canvas繪圖實現(xiàn)也很有局限性,與普通的瀏覽器對比,主要有四個不同點:

節(jié)點和Canvas對象創(chuàng)建:小程序的Canvas節(jié)點(嚴格意義上小程序沒有節(jié)點的概念)id的標識屬性為canvas-id,其創(chuàng)建JS對象使用wx.createCanvasContext方法

屬性賦值不同:在W3C的規(guī)范中,繪制的屬性都是賦值形式的,例如:

ctx.fillStyle = "#ffffff";
ctx.font = "40px Arial";

而小程序全部是調(diào)用形式的:

ctx.setFillStyle("#ffffff");
ctx.setFontSize(20);

每次繪圖后需要調(diào)用 draw 方法完成渲染

有些Canvas的能力與原生的參數(shù)有區(qū)別,如shadowBlur,shadowOffsetX均要調(diào)用wx.setShadow;有些能力并沒有實現(xiàn),例如lineDash屬性,clip剪切能力等。

其中,以上這些基本也都是由于其JSBridge的實現(xiàn)機理導(dǎo)致的,有興趣的同學(xué)可以Google一下具體了解。

那么,問題來了,我們的中間層能夠解決上面那些問題?實現(xiàn)思路是什么?
第一個問題很簡單,我們聲明節(jié)點同時書寫idcanvas-id,而其他三個問題我的解決思路是:

能夠檢測小程序環(huán)境

與W3C標準一樣,實現(xiàn)Canvas & CanvasRenderingContext2D 兩個類:我們稱其為WxCanvas & WxCanvasRenderingContext2D

使用Object.defineProperty將調(diào)用轉(zhuǎn)換為賦值

當(dāng)調(diào)用有區(qū)別和沒有實現(xiàn)的函數(shù)時,自動處理。

檢測小程序環(huán)境
export function checkWX() {
    return __GLOBAL__DEBUG__WX__ === true || (typeof wx != "undefined" && typeof wx === "object");
}

忽略__GLOBAL__DEBUG__WX__,此變量用于調(diào)試。我們簡單檢測 wx 全局是否存在。代碼

實現(xiàn)兼容類

WxCanvas主要邏輯如下:

class WxCanvas {
    constructor(id, config, contextOptions) {
        let me = this;

        // 檢查小程序環(huán)境
        me.isWeiXinAPP = checkWX();
        me._config = extend({}, WX_CANVAS_DEFAULT_PROPERTY, me.initConfig(config));

        // 提前獲取Canvas與context(這里忽略了webgl的情況)
        let {canvas, context} = this.acquireContext(id, config);

        me._canvas = canvas;
        me._ctx = context;
        // 實例化WxCanvasRenderingContext2D
        me.wxCanvasRenderingContext2D = new WxCanvasRenderingContext2D(canvas, context, contextOptions);

        return me;
    }
    /**
     * Create Canvas context
     * @param {String} id
     * @param {Object} config
     * @returns {*}
     */
    acquireContext(id, config) {
        let me = this,
            canvas,
            context;
        // Outer canvas config
        let handlerCanvas = config.canvas;

        if (me.isWeiXinAPP) {
            if (is.String(id)) {
                canvas = context = wx.createCanvasContext(id);
            } else { //... }
        } else {
            if (handlerCanvas) canvas = handlerCanvas;
            else
                canvas = is.String(id) ? document.getElementById(id) :
                    (typeof HTMLCanvasElement != "undefined" && id instanceof HTMLCanvasElement) ?
                        id:
                        null;
            if (typeof canvas != "undefined") {
                context = canvas.getContext && canvas.getContext("2d");
            }
        }

        // ...
        return {canvas, context};
    }
    getContext(str){
    }
    set height() {...}
    get height() {...}
    set width() {...}
    get width() {...}
}

WxCanvas的實現(xiàn)還是比較簡單的,主要注意的就是acquireContext方法,在這里我們判斷了小程序與非小程序環(huán)境,并獲得Canvas上下文。

下面我們看下WxCanvasRenderingContext2D的實現(xiàn)。

class WxCanvasRenderingContext2D {
    constructor(canvas, context, options) {
        let me = this;

        me.canvas = canvas;
        me._ctx = context;
        me.isWeiXinAPP = checkWX();

        // 聲明canvas屬性緩存棧,用于優(yōu)化性能
        me._ctxOptions = options;
        me._propertyCache = [extend({}, WX_CANVAS_CTX_DEFAULT_PROPERTY, options)];
        me.cp = me._propertyCache[0];

        // 屬性賦值轉(zhuǎn)化
        me.createStyleProperty();
        me.createShadowsProperty();
        
        // 后續(xù)省略,我們就拿前兩個舉例足以...
        
        return me;
    }
    createStyleProperty() {
        let me = this;

        let styleProperty = ["fillStyle", "strokeStyle"];
        styleProperty.forEach(p => {
            Object.defineProperty(me, p, {
                get: () => {
                    return me.cp[p];
                },
                set: (value) => {
                    if (value) {
                        return me._wxSetPropertyCallable(value.toLowerCase(), p)
                    }
                }
            })
        });
    }
    
    _wxSetPropertyCallable(value, propertyName, wxSetName = "set" + propertyName.replace(/(w)/, v => v.toUpperCase())) {
        let me = this;

        if (is.Null(value) || is.Undefined(value)) {
            return value;
        }

        // performance
        if (me.cp[propertyName] === value) {
            return value;
        }

        if (me.isWeiXinAPP) {
            me._ctx[wxSetName](value);
            me.cp[propertyName] = value;
        } else {
            me._ctx[propertyName] = value;
            me.cp[propertyName] = me._ctx[propertyName];
        }
        return value;
    }
    ...
    draw(ctu = true) {
        if (this.isWeiXinAPP) {
            this._ctx.draw(ctu);
        }
    }
}

上面的例子,我們只舉例 fillStyle, strokeStyle 兩個賦值屬性的兼容轉(zhuǎn)換??梢钥吹?,我們定義了通用方法_wxSetPropertyCallable,在小程序環(huán)境下,它會調(diào)用set[wxSetName](也就是setFillStyle和setStrokeStyle),而在普通環(huán)境下會正常的屬性賦值。

再來看我們的draw方法,同樣只在微信小程序中有效,但是遺憾的是每次繪制以后還是要調(diào)用draw方法一次,這是唯一的與W3C方法有區(qū)別的事情。不過,這主要是為了性能考慮,因為JSBridge每一次的調(diào)用都是有成本的,如果每次設(shè)置我們都自動的調(diào)用draw會大幅增加這個成本。

以上完成以后,我們就可以做到類似于W3C標準,在小程序中繪圖了:

import WxCanvas, { WxCanvasRenderingContext2D } from "wx-chart/util/wxCanvas"

let wxCanvas = new WxCanvas("myCanvas", {width: "800px", height: "500px"});
let wxCanvasContext = wxCanvas.getContext("2d");
wxCanvasContext.fillStyle="#FF0000";
wxCanvasContext.fillRect(0,0,80,100);
wxCanvasContext.draw();
一些遇到的問題

在實現(xiàn)兼容庫時,有幾個比較棘手的問題。
首先是小程序并沒有實現(xiàn) measureText 方法,因此我們需要模擬一個:

measureText(text, fontSize = this.fontSize) {
        let me = this;
        if (me.isWeiXinAPP) {
            if (!text) { return 0; }
            let textLen = text.length;
            let hanzi = text.match(new RegExp(REG_HANZI, "g"));
            let hanziNum = !!hanzi ? hanzi.length: 0;
            let otherNum = textLen - hanziNum;

            return {"width": fontSize * (otherNum + hanziNum * 2) / 2 + fontSize / 4};
        } else {//...}
    }

我們對漢字和非漢字進行了處理。不過,需要承認的是,即便是這樣,也與實際有一些不準。

另外,textBaseline,textAlign 也需要特殊處理(當(dāng)前1.1版本已經(jīng)支持)

結(jié)束

由于時間和和篇幅有限,第一段文章就先寫到這里。有錯誤或者不完善的情況請多多諒解和支持。也換用大家使用wx-chart 圖形庫并提出意見和建議。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/88916.html

相關(guān)文章

  • 2017-10-10 前端日報

    摘要:前端日報精選第期寫給前端應(yīng)屆生的職業(yè)規(guī)劃建議應(yīng)用編譯優(yōu)化之路進階篇命名空間模式解析源碼解析之任務(wù)管理入門教程快速上手聊聊改變歷史中文正式發(fā)布,帶來種新的圖表類型關(guān)系圖解好好寫代碼吧使用手冊掘金發(fā)布在即將全面支持掘金仿懂球帝 2017-10-10 前端日報 精選 【第1074期】寫給前端應(yīng)屆生的職業(yè)規(guī)劃建議webpack 應(yīng)用編譯優(yōu)化之路JS進階篇--命名空間模式解析gulp源碼解析之任...

    myshell 評論0 收藏0
  • 在微信小程序中繪制圖表part1

    摘要:微信小程序中提供了的支持,利用自行繪制圖表。關(guān)注我的項目查看完整代碼。 微信小程序中圖表現(xiàn)狀 由于微信小程序本身框架的限制,很難集成目前已有的圖表工具,顯示圖表目前有兩種方案:1、服務(wù)器端渲染圖表,輸出圖片,微信小程序中直接顯示渲染好的圖片,比如highcharts提供了服務(wù)端渲染的能力hightcharts server render,這種方式需要后臺有一套渲染服務(wù),并且有一定的網(wǎng)絡(luò)...

    chaosx110 評論0 收藏0
  • 在微信小程序中繪制圖表(part2)

    摘要:本期大綱確定縱坐標的范圍并繪制根據(jù)真實數(shù)據(jù)繪制折線相關(guān)閱讀在微信小程序中繪制圖表在微信小程序中繪制圖表關(guān)注我的項目查看完整代碼。相關(guān)閱讀在微信小程序中繪制圖表在微信小程序中繪制圖表 本期大綱 1、確定縱坐標的范圍并繪制 2、根據(jù)真實數(shù)據(jù)繪制折線 相關(guān)閱讀:在微信小程序中繪制圖表(part1)在微信小程序中繪制圖表(part3) 關(guān)注我的 github 項目 查看完整代碼。 確定縱坐...

    canopus4u 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<