Discuss / JavaScript / 我来解释一下!!!!

我来解释一下!!!!

Topic source

已知函数传进来的data是一个数组,数组的每个元素是一个对象,格式如下 {"date":"20150602","open":4844.7,"close":4910.53,"high":4911.57,"low":4797.55,"vol":62374809900,"change":1.69} 其中我们能用到的是 open , close, high, low 解释一下四个参数的含义,我们知道K线图的形状 类似于汉字 其中 high表示的是中字中间一竖的最上边一点的Y坐标, low 是中字中间一竖的最下边一点的Y坐标, 如果open大于close,则表示股票交易结束的时候比开始的时候低了,则要用绿色表示 open是中字中间的口的上边一横的Y坐标, close是下边一横的Y坐标 如果open小于close,则表示股票交易结束的时候比开始的时候高了,则要用红色表示 open是中字中间的口的下边一横的Y坐标 close是上边一横的Y坐标 这样就可以清楚的表示出 在时间上(横坐标,单位:天)股票点数(Y坐标)的变化

下面来看我写的代码

    ctx.fillStyle = "#000000";  //背景设为黑色
    ctx.fillRect(0, 0, width, height);
    //开始取所有数据中的最小值
    low = data[0].low;  //给low赋初始值
    high = data[0].high;    //给high赋初始值
    for (var i = 1; i < data.length; i++) {     //遍历数组
        low = data[i].low < low ? data[i].low : low;    //保证low是最小的
        high = data[i].high > high ? data[i].high : high; //保证high是最大的
    }

    //Y坐标的起始值,取0.05的系数保留空白
    height_start = height * 0.05;

    //股票点数变化值(Y坐标最大和最小之间的差值)和盒子像素(0.9的系数,上下各留0.05)的比值
    scale = (high - low) / (height * 0.9);

    //汉字中  竖线左边半个口的宽度,  这里width乘了系数0.3
    //因为我是这样分配的:整个canvas的盒子宽度为1, 左边预留0.05, 中字中间的一竖是1个像素, 
    // 整个口字的宽度占0.6(半个口字就是0.3), 口字与口字之间的宽度占0.2
    //所以我计算宽度的分配是这样的  半个口+1像素+半个口+空白+半个口+1像素+半个口+空白.....
    width_half_k = Math.round((width * 0.30) / data.length);
    //空白的像素,空白比元素个数少一个
    k_blank = Math.round((width * 0.2) / (data.length - 1));
    //左边保留的像素的宽度
    width_start = Math.round(width * 0.05);

    //开始画图
    for (var i = 0; i < data.length; i++) {
        //先来画中间的竖线

        //中字中间竖线的x坐标,开始是左边保留的像素个数,加上半个口的宽度即第一条线的x坐标
        //以后的每条线,就每次往后加上 (1像素线宽,半个口,空白,半个口)
        line_x = width_start + width_half_k + i * (1 + width_half_k * 2 + k_blank);
        //中字 最下边一点的Y坐标,因为height_start对应着high,所以就是height_start+两个值之差的绝对值再除以系数
        //这里有点逻辑会有点乱,因为对于Y坐标来说,是从坐上往下递增的,而对于股票点数来说是从下往上递增
        y_low = Math.round(height_start + Math.abs(data[i].low - high) / scale);
        //同样的方法计算高点对应的Y坐标
        y_high = Math.round(height_start + Math.abs(data[i].high - high) / scale);

        //取画线的起始Y坐标,因为股票点数高的肯定在上边,所以去y_high坐标
        line_y = y_high;
        //要画的线的高度
        line_high = Math.abs(y_low - y_high);
        //线的宽度
        line_width = 1;

        //画线中间的口字,可以将其视为一个盒子

        //计算盒子的左上角的X坐标,第一个是保留的width_start,之后的每次往后加两个半口字,加1像素,加留白
        box_x = width_start + (i * (width_half_k * 2 + 1 + k_blank));
        //计算open值对应的Y坐标
        y_open = Math.round(height_start + Math.abs(data[i].open - high) / scale);
        //计算close值对应的Y坐标
        y_close = Math.round(height_start + Math.abs(data[i].close - high) / scale);
        //最小的Y坐标才是左上角盒子的Y坐标
        box_y = y_open < y_close ? y_open : y_close;
        //盒子的高度
        box_high = Math.abs(y_open - y_close);
        //盒子的宽度,两个半口字,加1像素
        box_width = width_half_k * 2 + line_width;

        //判断颜色
        if (data[i].open >= data[i].close) {
            ctx.fillStyle = "#dc0000";
        }
        else {
            ctx.fillStyle = "#1caa3d";
        }
        //画线
        ctx.fillRect(line_x, line_y, line_width, line_high);
        //画盒子
        ctx.fillRect(box_x, box_y, box_width, box_high);

    }

何小狗____

#2 Created at ... [Delete] [Delete and Lock User]

详细解读了仁兄的思路,自己实现了一遍。仁兄的是最符合K线图的。我在仁兄的基础上封装了划线和画盒子的函数。增加了文字信息,背景我是使用第二个图层实现的。

function drawline(data,width_start,width_half_k,k_blank,height_start,scale,high) { for(var i=0;i<data.length;i++) { var line_X=width_start+width_half_k+i*(1+2*width_half_k+k_blank); var line_y=Math.round(height_start+Math.abs(data[i].high-high)*scale); var line_width=1; var line_high=(data[i].high-data[i].low)*scale; if (data[i].open >= data[i].close) { ctx.fillStyle = "#dc0000"; } else { ctx.fillStyle = "#1caa3d"; } ctx.fillRect(line_X,line_y,line_width,line_high); } } function drawbox(data,width_start,width_half_k,k_blank,height_start,scale,high) { for(var i=0;i<data.length;i++) { var box_x=width_start+i*(2*width_half_k+1+k_blank); var y_open=Math.round(height_start+Math.abs(data[i].open-high)*scale); var y_close=Math.round(height_start+Math.abs(data[i].close-high)*scale); var box_y=y_open<y_close ? y_open:y_close; var box_width=2*width_half_k+1; var box_high=Math.abs(data[i].open-data[i].close)*scale; if (data[i].open >= data[i].close) { ctx.fillStyle = "#dc0000"; } else { ctx.fillStyle = "#1caa3d"; } ctx.fillRect(box_x,box_y,box_width,box_high); } } function drawStock(data) { var canvas=document.getElementById('stock-canvas'); var width=canvas.width; var height=canvas.height;

    //创建背景图层2,创建图层2的原因是为了避免文字,背景用一种fillStyle
    var layer2=document.createElement('canvas');
    layer2.style.position='absolute';
    layer2.style.left='0';
    layer2.style.opacity='0.2';
    var ctx2=layer2.getContext('2d');
    ctx2.fillStyle='#00000';
    ctx2.fillRect(0,0,width,height);
    document.getElementsByTagName('body')[0].appendChild(layer2);

    ctx=canvas.getContext('2d');
    ctx.clearRect(0,0,width,height);

    ctx.font='20px Verdana';
    // 创建渐变,产生文字
    var gradient=ctx.createLinearGradient(0,0,width,height);
    gradient.addColorStop("0","magenta");
    gradient.addColorStop("0.5","blue");
    gradient.addColorStop("1.0","red");
    ctx.fillStyle=gradient;
    ctx.fillText('Test canvas',75,20);

    var low=data[0].low;
    var high=data[0].high;
    for(var i=0;i<data.length;i++)
    {
        low=data[i].low<low ? data[i].low:low;
        high=data[i].high>high ? data[i].high:high;
    }

    var height_start=height*0.05;
    var scale=height*0.9/(high-low);

    var width_half_k=Math.round((width*0.3)/data.length);
    var k_blank=Math.round((width*0.2)/(data.length-1));
    var width_start=width*0.05;
    //调用上面封装好的划线和画盒子的函数
    drawline(data,width_start,width_half_k,k_blank,height_start,scale,high);
    drawbox(data,width_start,width_half_k,k_blank,height_start,scale,high);

}
function loadStockData(r) {
    var NUM=30;
    var data=r.data;
    if(data.length>NUM){
        data=data.slice(data.length-NUM);
    }
    data=data.map(function (x) {
        return {
            data: x[0],
            open: x[1],
            close:x[2],
            high: x[3],
            low:  x[4],
            vol:  x[5],
            change:x[6]
        };
    });
    drawStock(data);
}
var js=document.createElement('script');
js.src = 'http://img1.money.126.net/data/hs/kline/day/history/2015/0000001.json?callback=loadStockData&t='+Date.now();
document.getElementsByTagName('head')[0].appendChild(js);

biggerdream

#3 Created at ... [Delete] [Delete and Lock User]

你改的代码有问题,你创建的图层2,没有起到任何作用,文字和划线,盒子,也都还是在原来的一个图层。


  • 1

Reply