基于Highcharts箱线图实现k线图

如何制作一个k线图?

似乎可利用的插件或库有很多,比如echarts、highcharts、d3.js等。使用echarts是最简单的,有现成的demo可供参考,而d3可定制性是最高的,这些定制需要你一点点去写,也不好写,highcharts官网上没有demo,网上也没有相关的案例,但是通过阅读他的说明文档,发现了箱线图这一图表类型,这不正是highcharts实现k线图最好的方法吗?

认识箱线图

箱线图中一个箱体包含五个值:上边缘(最大观测值或样品最大值)、上四分位数(Q3)、中位数(Q2)、下四分位数(Q1)和下边缘(最小观测值或样品最小值)。另外在箱体外还可以用圆形点表示异常值,下面是箱线图组成部分示意图:
基于Highcharts箱线图实现k线图_第1张图片
在 Highcharts 中,箱线图的箱体由主箱体(Box)、中位线(median)、颈部(Stem)和须线(Whishker)组成,异常值是用散点的形式展现,下面是示意图:
基于Highcharts箱线图实现k线图_第2张图片

数据结构

正如上面说的,箱线图中每个箱体包含五个值,Highcharts 可以识别的箱线数据点的定义方式包括:

1、对象数组的形式,其中 x 值是可选的
    { x: Date.UTC(2013, 1, 7), low: 0, q1: 1, median: 2, q3: 3, high: 4 }
2、包含五个元素的数组,x 值自动计算
    [0, 1, 2, 3, 4]
3、包含六个元素的数组,其中第一个值是 x 值
    [Date.UTC(2013, 1, 7), 0, 1, 2, 3, 4]

我们可以用上须线(high)表示k线图数据的最大值,下须线(low)表示k线图的最小值,箱体(q1,q3)表示k线图的开盘/收盘价,我的数据格式:

效果预览

基于Highcharts箱线图实现k线图_第3张图片

难点及解决:

0、数据的生成,只是简单模拟日数据(毕竟对股票数据这块不太熟,线上项目肯定是从后台取的数据吧?)
1、箱体颜色填充,看遍说明文档也没发现怎么填充不同的颜色
    发现series 配置 data 中可以配置className,但是怎么也出不来,放弃
    阅读源码,发现填充色默认为#ffffff,但如果设置为null,undefined或"",则根据设置的color来填充。苦笑...
2、x轴标签问题,数据过多,会自动旋转,取消旋转,会出现溢出隐藏(默认是溢出显示省略号)
    设置 autoRotation 为 [-10],之前试了[0]不行,为什么[-10]是平的,而[0]不可以???坑!!!
3、像x轴的网格线,y轴的轴线,默认宽度为0,需要自己设置下
4、提示框悬停在箱线图上才会出现,需要设置shared为true,全屏扑捉提示框

代码


<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>基于Highcharts箱线图实现k线图title>
        <style>
            .myTooltip p{
                margin: 0;
                padding: 0;
                height: 25px;
                line-height: 25px;
                width: 120px;
            }
            .myTooltip p.blockSpan{
                text-align: center;
                font-weight: bold;
            }
            .myTooltip p.myRed{
                color:#E30000;
            }
            .myTooltip p.myGreen{
                color:#007130;
            }
            .myTooltip p span:first-child{
                display: inline-block;
                width: 50px;
                text-align: right;
                padding-right: 10px;
            }
        style>
    head>
    <body>
        <div id="container" style="height: 400px; margin: auto; width: 600px">div>

<script src="http://cdn.hcharts.cn/highcharts/highcharts.js">script>
<script src="http://cdn.hcharts.cn/highcharts/highcharts-more.src.js">script> 



<script type="text/javascript">
//格式化时间
function formatDate(date){
    //模拟股市开盘时间: 周一至周五(不考虑假期)
    var date = new Date(date),
        w = date.getDay(),
        Y = date.getFullYear(),
        M = date.getMonth() + 1,
        D = date.getDate();
    if(w>0 && w<6){
        return Y+'-'+(M<10?"0":"")+M+'-'+(D<10?"0":"")+D;
        //return date; //x轴为时间轴时的数据
    }
    return false;
}
function getDate(m){
    var date = new Date().getTime(),
        i = 0,
        dates = [];
    while(dates.lengthvar item = formatDate(date - i*24*60*60*1000);
        item && dates.push(item);
        i++;
    }
    dates.reverse();
    //console.log(dates);
    return dates;
}
//获取x轴数据
var xdata = getDate(40);
//获取涨跌幅随机数
function rand(){
    var sum = 0;
    for(var i=0;i<10;i++){
        i%2==0?(sum += Math.random()):(sum -= Math.random());
    }
    return sum.toFixed(2)/100;//百分数
}
//获取 series 数据
function getData(m){
    var data = [{
        low: 3142,//最小值
        q1: 3186,//最小实际值(开盘/收盘价)
        median: null,//中位数
        q3: 3225,//最大实际值(开盘/收盘价)
        high: 3225,//最大值
        name:xdata[0],
        RiseAndFall:1.22,//涨跌幅  百分数
        //className:'red',//给数据项加一个class,方便设置颜色,无效
        color: "#ff0000"
    }],
    obj,RiseAndFall,kpj,spj,RiseAndFall2,RiseAndFall3;
    for(var j=1;j//kpj 开盘价  开盘价 = 前一个交易日的收盘价
        //前一个交易日是涨 收盘价为q3 否则为q1
        kpj = data[j-1].RiseAndFall>0?data[j-1].q3:data[j-1].q1;
        //spj 收盘价  收盘价 = 开盘价 + 开盘价*涨跌幅
        spj = kpj + kpj * RiseAndFall;
        RiseAndFall2 = rand();
        RiseAndFall3 = rand();
        obj = {
            low:+function(){
                if(RiseAndFall>0){//是涨 最小值<=开盘价
                    return RiseAndFall2>0?kpj:(kpj+kpj*RiseAndFall2)
                }else{//是跌 最小值<=收盘价
                    return RiseAndFall2>0?spj:(spj+spj*RiseAndFall2)
                }
            }(),
            q1:RiseAndFall>0?kpj:spj,
            median: null,//中位数
            q3:RiseAndFall>0?spj:kpj,
            high:+function(){
                if(RiseAndFall>0){//是涨 最大值>=收盘价
                    return RiseAndFall3>0?(spj+spj*RiseAndFall3):spj
                }else{//是跌 最大值>=开盘价
                    return RiseAndFall3>0?(kpj+kpj*RiseAndFall3):kpj
                }
            }(),
            name:xdata[j-1],
            RiseAndFall:RiseAndFall*100,
            color: RiseAndFall>0?"#ff0000":RiseAndFall<0?"#00ff00":"#bbbbbb"
        }
        data.push(obj);
    }
    return data;
}
var data = getData(xdata.length);
Highcharts.chart('container', {
    chart: {
        backgroundColor:'#000',
        zoomType: 'x'//可以用鼠标缩放x轴
    },
    credits:{
        enabled:false//不启用版权信息 否则会显示highcharts的一些信息
    },
    title: {
        text: '上证指数[000001]',
        style:{
            color:'#ffffff'
        }
    },
    legend: {
        enabled: false
    },
    xAxis: {
        //type: 'datetime',
        //type:'category',
        title: {visible:false},
        categories: xdata,
        labels:{
            //autoRotation:false,//默认不旋转 无效 不会自动删减
            autoRotation:[-10],
            //overflow:undefined,
            //tickInterval:null,//间隔多少条数据 无效
            //tickPixelInterval:50,//间隔多少像素 无效
            style:{
                color:'#ffffff'
            }
        },
        gridLineColor:'#666',
        gridLineDashStyle:'LongDash',
        gridLineWidth:1,
        //crosshair: true
        crosshair: {
            width: 1,
            color: '#ffffff',
            dashStyle: 'shortdot'
        }
    },
    yAxis: {
        title: {visible:false},
        lineWidth:1,
        labels:{
            style:{
                color:'#ffffff'
            }
        },
        gridLineColor:'#666',
        gridLineDashStyle:'LongDash',
        //crosshair: true
        crosshair: {
            width: 1,
            color: '#ffffff',
            dashStyle: 'shortdot'
        }
    },
    tooltip:{
        shared:true,//共享提示框,整个绘图区都将捕捉鼠标指针的移动,显示提示框,同时将多个数据列的信息展示在同一个提示框里
        useHTML:true,
        formatter:function(){
            var options = this.points[0].point.options,
                RiseAndFall = options.RiseAndFall,
                high = options.high,
                low = options.low,
                kp = (options.q1*RiseAndFall)>(options.q3*RiseAndFall)?options.q3:options.q1,
                sp = (options.q1*RiseAndFall)>(options.q3*RiseAndFall)?options.q1:options.q3,
                html = '

'+this.x+'

'; //这里顺便添加class,设置提示框不同字体颜色,我是随便设置的 html += "

开盘:"+kp.toFixed(2)+"

"
; html += "

最高:"+high.toFixed(2)+"

"
; html += "

最低:"+low.toFixed(2)+"

"
; html += "

收盘:"+sp.toFixed(2)+"

"
; html += "

涨跌幅:"+RiseAndFall.toFixed(2)+"%

"
; html += "
"
; return html; } }, plotOptions: { boxplot: { //中线 medianWidth: 0, //上下边缘线 //whiskerColor:'#fff', whiskerLength:0, //className:'myBoxplot' } }, series: [{ //name: 'boxplot', type: 'boxplot', fillColor:null,//关键:填充色,不做设置,填充色为白色,设置为null,undefined,''等,填充色为data的color data: data }] }); script> body> html>

你可能感兴趣的:(小案例)