如何使用highcharts自定义按钮导出图片

文章目录

接触highcharts这个图表插件已经有好几年了,摸打滚爬到现在可以说对highchart已经有一定的了解了

首先 Highcharts 本身就提供了导出图片的功能,只需要在配置中增加相应的参数即可

1
2
3
4
5
navigation : {
buttonOptions : {
enabled : true
}
}

设置完毕即可导出图片了,但是这种方式有个缺点,就是导出图片时会请求highchart官方的服务器生成图片,最后返回客户端给用户下载,我们可以在官方源码中看到这样一段代码:

1
2
3
4
5
6
defaultOptions.exporting = {
//enabled: true,
//filename: 'chart',
type: 'image/png',
url: 'http://export.highcharts.com/'
}

那如何请求自己的服务器生成对应的图片呢?官方API已经为我们留出了对应的接口供我们调用
点击这里可以查看exportChart相关属性

###如何配置自己服务器的URL,有2种方式:

####全局配置文件中配置

  • 建立一个自己常用的 highchart配置文件 在配置属性中配置 exporting 的相关属性
    大家可以新建一个通用js文件叫ChartOptions.js,将下面的代码拷入即可,代码中exporting 设置自己的服务器URL,contextButton 数组里可以扩展自己其他的按钮。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    function GetChartOptions() {
    var options = {
    chart : {
    renderTo : '',
    // 是否开启水平缩放
    zoomType:null
    },
    loading : {
    hideDuration : 1000,
    showDuration : 1000
    },
    yAxis : {
    title : {
    text : ""
    },
    allowDecimals : false,
    min : 0,
    tickPixelInterval : 72
    },
    legend:{
    enabled:true
    },
    xAxis : {
    type : 'linear',
    categories:null,
    minRange:null,
    tickInterval:null,
    labels : {
    rotation : 0
    },
    },
    navigation : {
    buttonOptions : {
    enabled : true
    }
    },
    credits : {
    // 是否启用右下角水印
    enabled : false
    },
    plotOptions : {
    bar : {
    dataLabels : {
    enabled : true
    }
    },
    column : {
    cursor : 'pointer',
    depth : 25
    },
    pie : {
    allowPointSelect : true,
    cursor : 'pointer',
    dataLabels : {
    enabled : true,
    color : '#000000',
    connectorColor : '#000000',
    format : '<b>{point.name}</b>: {point.percentage:.1f} %'
    },
    showInLegend : true,
    events: {
    click:null
    }
    },
    line : {
    dataLabels : {
    enabled : false
    },
    cursor : 'pointer'
    },
    series:{
    pointStart : 0,
    pointInterval : 1,// 24 * 3600 * 1000
    point: {
    events: {
    click: null
    }
    }
    }
    },
    tooltip : {
    xDateFormat : '%Y-%m-%d'
    },
    subtitle : {
    text : ""
    },
    title : {
    text : ""
    },
    exporting: {
    buttons: {
    contextButton: {
    menuItems: [{
    text: '导出JPEG',
    onclick: function () {
    this.exportChart({
    type: 'image/jpeg'
    });
    }
    },
    {
    text: '导出PNG',
    onclick: function () {
    this.exportChart();
    }
    },
    {
    text: '导出PDF',
    onclick: function () {
    this.exportChart({
    type: 'application/pdf'
    });
    }
    }]
    }
    },
    width: '800',
    formAttributes: {"accept-charset":"utf-8"},
    url: "/exportSvg/convertSvg.html" //将此URL改成自己服务器请求URL即可
    },
    series : []
    };
    return options;
    }
  • 接下来是调用初始化图表,highchart初始化也有2种方式,第一种是 jquery方式,第二种是原生的highchart方式,这里我介绍的是第二种方式,在前端放入一个DIV,ajax请求后在success中调用下面这段代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    var chart = null;
    var option = GetChartOptions();
    // 这里为renderTo 赋值,要渲染的div ID名称
    option.chart.renderTo = "divForwardPersonRanking";
    option.chart.height = 350;
    option.chart.width=$("#divForwardPersonRanking").width();
    option.xAxis.labels.rotation = -45;
    option.title.text = "转发排行前十";
    var category = [];
    var obj = {
    name : "转发数",
    data : []
    }
    //这里的data 是ajax返回回来的数据
    if (!jQuery.isEmptyObject(data) && data.length > 0) {
    $.each(data, function(i, n) {
    category.push(n.userName);
    obj.data.push( [ n.userName, n.times ]);
    });
    option.xAxis.categories = category;
    }
    //这里是为series动态填充数据
    option.series.push(obj);
    //这里为图表指定类型
    option.chart.type = "column";
    //最后开始渲染
    chart = new Highcharts.Chart(option);

####外部自定义DownLoad方法,用chart对象调用

注意 :这种方法和上面那种方法稍微有点区别,即我们可以把按钮放在图表外自己喜欢的任意位置,而第一种方式,只能通过highchart封装的按钮去导出图片,使用第二种方法前,先将上面highchart配置文件中的 exporting 节点去掉,因为我们会在外部通过chart对象调用export方法

  • 前端HTML,这里我用span充当了一个按钮用来导出图片

    1
    2
    <div id="div_img"></div>
    <span class="section-buttons normal-button button-list" onclick="DownLoad()">导出数据</span>
  • 前端js代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    var chart;
    function InitChart()
    {
    $.ajax({
    type: "GET",
    url: location.href + "?action=getChart",
    dataType: 'json',
    data: "AnalysisType=" + condition.TypeAnalysisA,
    beforeSend: function () {
    },
    success:function(result){
    if (!jQuery.isEmptyObject(result) && result.length > 0) {
    //chart参数设置
    var options = GetChartOptions();
    //接着对options的参数进行赋值
    option.chart.height = "300";
    option.chart.renderTo = "div_img";
    option.chart.width = "400";
    option.title.text="主标题";
    option.title.text="副标题";
    option.chart.type = "pie";//指定需要渲染的图表类型
    var obj = { name: "类型分布", data: [] };
    $.each(result, function (i, n) {
    var c = "";
    //根据不同的类型指定不同的颜色,当然也可以在后台json中拼好后前台直接使用
    switch (n.Name.toString()) {
    case "news": c = "#FFDBC4"; break;
    case "blogs": c = "#F2FAD7"; break;
    case "weibo": c = "#D3DCD0"; break;
    }
    var temp = { name: n.Name, y: parseInt(n.Values), color: c };
    obj.data.push(temp);
    });
    option.series.push(obj);
    chart = new Highcharts.Chart(option);
    }
    }
    });
    }
    function DownLoad()
    {
    if(chart!=null)
    {
    var currentDate = new Date();
    chart.exportChart({
    type: "image/jpeg",//指定导出的类型
    width: '800',
    url: location.href + "?action=export"
    filename: currentDate.getTime() //图片的名称,当然也可以在后台定义
    });
    }
    }
    InitChart();

说明:第二种方法,先初始化chart对象,然后在外部定义了一个DownLoad方法,用过span按钮去调用该方法,最后通过chart对象动态调用了exportChart方法


  • 前端的代码的阐述到此结束,接下来为大家介绍下后端对应的代码(这里我只介绍asp.net的,其他语言可以在官网下载相关的代码)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    private void ExportData()
    {
    string tType = Request.Form["type"].ToString();
    string tSvg = Request.Form["svg"].ToString();
    string tFileName = Request.Form["filename"].ToString();
    if (tFileName == "")
    {
    tFileName = "chart";
    }
    MemoryStream tData = new MemoryStream(Encoding.UTF8.GetBytes(tSvg));
    MemoryStream tStream = new MemoryStream();
    string tTmp = new Random().Next().ToString();
    string tExt = string.Empty;
    string tTypeString = string.Empty;
    switch (tType)
    {
    case "image/png":
    tTypeString = "-m image/png";
    tExt = "png";
    break;
    case "image/jpeg":
    tTypeString = "-m image/jpeg";
    tExt = "jpg";
    break;
    case "application/pdf":
    tTypeString = "-m application/pdf";
    tExt = "pdf";
    break;
    case "image/svg+xml":
    tTypeString = "-m image/svg+xml";
    tExt = "svg";
    break;
    }

    if (!string.IsNullOrEmpty(tTypeString))
    {
    string tWidth = Request.Form["width"].ToString();
    Svg.SvgDocument tSvgObj = SvgDocument.Open(tData);
    switch (tExt)
    {
    case "jpg":
    tSvgObj.Draw().Save(tStream, ImageFormat.Jpeg);
    break;
    case "png":
    tSvgObj.Draw().Save(tStream, ImageFormat.Png);
    break;
    case "pdf":
    PdfWriter tWriter = null;
    Document tDocumentPdf = null;
    try
    {
    tSvgObj.Draw().Save(tStream, ImageFormat.Png);
    tDocumentPdf = new Document(new Rectangle((float)tSvgObj.Width, (float)tSvgObj.Height));
    tDocumentPdf.SetMargins(0.0f, 0.0f, 0.0f, 0.0f);
    iTextSharp.text.Image tGraph = iTextSharp.text.Image.GetInstance(tStream.ToArray());
    tGraph.ScaleToFit((float)tSvgObj.Width, (float)tSvgObj.Height);

    tStream = new MemoryStream();
    tWriter = PdfWriter.GetInstance(tDocumentPdf, tStream);
    tDocumentPdf.Open();
    tDocumentPdf.NewPage();
    tDocumentPdf.Add(tGraph);
    tDocumentPdf.CloseDocument();
    }
    catch (Exception ex)
    {
    throw ex;
    }
    finally
    {
    tDocumentPdf.Close();
    tDocumentPdf.Dispose();
    tWriter.Close();
    tWriter.Dispose();
    tData.Dispose();
    tData.Close();

    }
    break;

    case "svg":
    tStream = tData;
    break;
    }

    Response.ClearContent();
    Response.ClearHeaders();
    Response.ContentType = tType;
    Response.AppendHeader("Content-Disposition", "attachment; filename=" + tFileName + "." + tExt + "");
    Response.BinaryWrite(tStream.ToArray());
    Response.End();
    }
    }

总结:原理大概就是这样子的:
1、初始化图表
2、调用export方法请求服务器,export会获取到图表的svg信息,然后以post的方式将form提交给URL
3、后台接受到请求,获取相关的参数,调用图片处理程序绘制图片