小程序 - 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: 48 rpx ;
}

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

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


微信小程序,作为腾讯旗下的轻量级应用平台,凭借其独特的优势和特点,已经深入渗透到人们的生活中。以下是微信小程序的一些关键优势和特点,以及我们为您准备的资源介绍: 优势与特点: 即用即走,无需安装:用户只需在微信内搜索或扫码即可使用,无需下载安装,节省手机存储空间,也降低了用户的使用门槛。 跨平台兼容性:微信小程序可在多种操作系统和设备上运行,无需考虑不同平台的适配问题,为开发者提供了统一的开发环境。 丰富的API接口:微信提供了丰富的API接口,使得开发者能够轻松实现各种功能,如微信支付、用户授权、消息推送等。 强大的社交属性:微信小程序与微信生态紧密结合,可以充分利用微信的社交属性,实现用户裂变和增长。 低成本开发:相较于传统App,微信小程序的开发成本更低,周期更短,降低了企业的开发门槛和成本。 资源介绍: “微信小程序-项目源码-原生开发框架-含效果截图示例”这份资源,不仅包含了完整的微信小程序项目源码,而且基于原生开发框架,确保了代码的健壮性和可扩展性。源码中涵盖了微信小程序的基础架构、页面布局、功能实现等各个方面,通过详细的注释和说明,让您能够快速上手并掌握微信小程序的开发技巧。 同时,我们还提供了丰富的效果截图示例,让您能够直观地了解项目的最终效果,更好地评估项目的实用性和商业价值。无论您是前端开发者、小程序爱好者,还是希望拓展业务的企业,这份资源都将为您带来极大的帮助和启示。快来查看吧,开启您的小程序开发之旅!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值