小程序 - K線圖畫法

K線圖在股票走勢圖那裏用的很多,現在我們就一起學起K線圖的畫法吧。

效果圖
XML
<!-- 折線圖 -->
<view class="canvas-view">
    <canvas class="canvas" canvas-id="canvasId"></canvas>
</view>

CSS
/* 折線圖 */
.canvas-view {
    height: 100%;
    background: #fff;
    display: flex;
    align-items: center;
    margin-top: 48rpx;
}

.canvas {
    width: 100%;
    height: 640rpx;
}

js完整代碼

const app = getApp()

Page({
    data: {
        //開盤價, 收盤價, 最高價, 最低價
        list: [[50, 100, 130, 40], [160, 200, 220, 140], [210, 170, 220, 160], [150, 90, 160, 60], [150, 180, 190, 130], [210, 170, 240, 160], [50, 100, 140, 30], [100, 130, 140, 80], [210, 170, 240, 130], [240, 200, 260, 160]],
        h32: 32,
        h64: 64,
        h360: 360,
        h420: 420,
        s28: 28,
        s18: 18,
        //Y軸分成的大分段
        heightLineNum: 7,
        //X軸分成的大分段
        widthLineNum: 10,
        //Y軸一個分段的值
        yOneDuan: 50
    },
    onLoad: function (options) {
        //畫圖
        this.initChart()
    },

    // 初始化條形圖
    initChart: function () {
        const ctx = wx.createCanvasContext('canvasId')

        ctx.beginPath()
        ctx.setStrokeStyle('#999999')
        ctx.setFillStyle('#AAAAAA')
        ctx.setLineWidth(1)

        //座標原點,Y軸座標值從上往下是增加
        const leftBottomX = this.getEleWidth(this.data.h64)
        const leftBottomY = this.getEleWidth(this.data.h360)
        //Y座標
        const leftTopX = this.getEleWidth(this.data.h64)
        const leftTopY = this.getEleWidth(this.data.h32)
        //X座標
        const rightBottomX = this.getEleWidth(this.data.h420)
        const rightBottomY = this.getEleWidth(this.data.h360)

        const yHeight = this.getEleWidth(this.data.h360 - this.data.h32)
        const xWidth = this.getEleWidth(this.data.h420 - this.data.h64)

        //從Y軸座標開始畫座標系
        //Y軸座標到原點座標畫出Y軸線
        //畫完Y軸線,再從原點座標到X軸座標畫出X軸線
        ctx.moveTo(leftTopX, leftTopY)
        ctx.lineTo(leftBottomX, leftBottomY)
        ctx.lineTo(rightBottomX, rightBottomY)
        //設置字體大小
        ctx.setFontSize(this.getEleWidth(this.data.s28))
        //設置字的位置
        ctx.fillText("K線圖", this.getEleWidth(340), this.getEleWidth(32))

        //劃分Y軸
        this.drawYScale(ctx);
        //劃分X軸
        this.drawXScale(ctx);
        //畫條形圖
        this.drawRectScale(ctx);

        ctx.stroke()
        ctx.draw(true)
    },

    //劃分Y軸
    drawYScale: function (ctx) {
        var that = this;

        //Y軸座標刻度橫座標起點
        var scaleStartX = this.getEleWidth(this.data.h64)
        //長的刻度
        var scaleEndX = this.getEleWidth(this.data.h64 + 18)
        //短的刻度
        var littleScaleEndX = this.getEleWidth(this.data.h64 + 9)

        //Y軸刻度總高度
        const yHeight = this.getEleWidth(this.data.h360)
        //一個大分段的長度,一共分爲6段
        var oneScaleX = yHeight / this.data.heightLineNum
        //大分段數字字體大小
        ctx.setFontSize(this.getEleWidth(this.data.s18))
        //大分段數字位置橫座標
        var textX = this.getEleWidth(this.data.h64 - 42)
        //大分段,長刻度:50-300
        for (var i = 1; i < this.data.heightLineNum; i++) {
            var scaleEndY = yHeight - oneScaleX * i
            //畫長刻度線條
            ctx.moveTo(scaleStartX, scaleEndY)
            ctx.lineTo(scaleEndX, scaleEndY)
            ctx.fillText(this.data.yOneDuan * i, textX, scaleEndY + this.getEleWidth(10))
            var littleScaleStartY = yHeight - oneScaleX * (i - 1)
            //小分段,短刻度
            for (var j = 1; j < 5; j++) {
                var littleScaleEndY = littleScaleStartY - (oneScaleX / 5) * j
                //畫短刻度線條
                ctx.moveTo(scaleStartX, littleScaleEndY)
                ctx.lineTo(littleScaleEndX, littleScaleEndY)
                ctx.stroke();
            }
        }
    },

    //劃分X軸
    drawXScale: function (ctx) {
        var that = this;
        //X軸刻度值Y座標
        var scaleStartY = this.getEleWidth(that.data.h360)
        //X軸總長度=X軸橫座標-向右偏移長度
        const xWidth = this.getEleWidth(that.data.h420 - that.data.h64)
        //X軸起始點
        const xMaginLeft = this.getEleWidth(that.data.h64)
        //一個分段的寬度
        const oneScaleX = xWidth / (that.data.widthLineNum + 1)
        for (var i = 0; i < that.data.widthLineNum + 1; i++) {
            var toEndX = xMaginLeft + oneScaleX * i;
            ctx.fillText(i, toEndX - this.getEleWidth(5), scaleStartY + this.getEleWidth(24))
        }
    },

    //畫矩形方框, 畫最高最低線條
    drawRectScale: function (ctx) {
        var that = this;
        //X軸總長度=X軸橫座標-向右偏移長度
        const xWidth = this.getEleWidth(that.data.h420 - that.data.h64)
        const yHeight = this.getEleWidth(that.data.h360)

        //X軸起始點
        const xMaginLeft = this.getEleWidth(that.data.h64)
        //X座標,一個空格的值
        const oneScaleX = xWidth / (that.data.widthLineNum + 1)
        //Y座標,一個空格的值
        var oneScaleY = yHeight / this.data.heightLineNum
        for (var i = 0; i < that.data.list.length; i++) {
            const currentRect = that.data.list[i];
            //條矩形的寬度
            const rectWidth = oneScaleX / 3 * 2;
            //條矩形的高度
            const rectHeight = Math.abs(currentRect[1] - currentRect[0]) / this.data.yOneDuan * oneScaleY;
            //矩形左上角的x座標和y座標
            const x = xMaginLeft - (oneScaleX - rectWidth) / 2 + oneScaleX * (i + 1);
            var height = currentRect[0] > currentRect[1] ? currentRect[0] : currentRect[1];
            const y = yHeight - oneScaleY / this.data.yOneDuan * height;
            if (currentRect[1] > currentRect[0]) {
                //收盤大於開盤,綠色
                ctx.setFillStyle('#66FF00')
            } else {
                //開盤大於收盤,紅色
                ctx.setFillStyle('#990000')
            }
            //畫框
            ctx.fillRect(x, y, rectWidth, rectHeight);

            //最高最低線條,X軸
            const xh = x + rectWidth / 2;
            //最高價線條
            ctx.moveTo(xh, y)
            ctx.lineTo(xh, yHeight - oneScaleY / this.data.yOneDuan * currentRect[2])
            ctx.stroke();
            //最低價線條
            ctx.moveTo(xh, y + rectHeight)
            ctx.lineTo(xh, yHeight - oneScaleY / this.data.yOneDuan * currentRect[3])
            ctx.stroke();
        }
    },

    //獲取屏幕自適應寬度
    getEleWidth: function (w) {
        var real = 0;
        try {
            var res = wx.getSystemInfoSync().windowWidth;
            //以寬度480px設計做寬度的自適應
            var scale = (480 / 2) / (w / 2);
            real = Math.floor(res / scale);
            return real;
        } catch (e) {
            return false;
        }
    }
})


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章