• go-chart 发送图文的统计报表邮件


    原文:https://blog.csdn.net/zangdaiyang1991/article/details/105200062

    ----------------------------------------------------------------

    需求
    邮件中实现统计信息的发送。统计信息以折线图、饼图、柱状图的形式展示。因为邮件中无法支持js解析,所以采用go-chart生成PNG图片后base64编码后发送。

    <img src="data:image/png;base64,xxx">
    1
    go-chart实战
    go-chart是个强大的go生成图片的库,但是采用默认配置生成线条较多或者文本过长的图片时,无法完美适应。默认不支持中文。但是里面的属性大多可自己定义,整体来说非常强大。

    代码
    package charter

    import (
    "bytes"
    "encoding/base64"
    "fmt"
    "math/rand"
    "os"
    "time"

    "github.com/wcharczuk/go-chart"
    "github.com/wcharczuk/go-chart/drawing"
    )

    const (
    lineChartXAxisName = "Date"
    lineChartYAxisName = "Count"
    lineChartHeight = 700
    lineChartWidth = 1280
    colorMultiplier = 256
    imgStrPrefix = "data:image/png;base64,"
    pieLabelFormat = "%v %v"
    barChartTryAgainErr = "invalid data range; cannot be zero"
    )

    var (
    lineChartStyle = chart.Style{
    Padding: chart.Box{
    Top: 30,
    Left: 150,
    },
    }

    defaultChartStyle = chart.Style{
    Padding: chart.Box{
    Top: 30,
    },
    }

    timeFormat = chart.TimeDateValueFormatter
    )

    type LineYValue struct {
    Name string
    Values []float64
    }

    type ChartValue struct {
    Name string
    Value float64
    }

    // createLineChart 创建线性图
    func createLineChart(title string, endTime time.Time, values []LineYValue) (img string, err error) {
    if len(values) == 0 {
    return
    }
    // 1、计算X轴
    lenX := len(values[0].Values)
    // X轴内容xValues 及 X轴坐标ticks
    var xValues []time.Time
    var ticks []chart.Tick
    for i := lenX - 1; i >= 0; i-- {
    curTime := endTime.AddDate(0, 0, -i)
    xValues = append(xValues, curTime)
    ticks = append(ticks, chart.Tick{Value: getNsec(curTime), Label: timeFormat(curTime)})
    }

    // 2、生成Series
    var series []chart.Series
    for _, yValue := range values {
    series = append(series, chart.TimeSeries{
    Name: yValue.Name,
    Style: chart.Style{
    // 随机渲染线条颜色
    StrokeColor: drawing.Color{
    R: uint8(rand.Intn(colorMultiplier)),
    G: uint8(rand.Intn(colorMultiplier)),
    B: uint8(rand.Intn(colorMultiplier)),
    A: uint8(colorMultiplier - 1), // 透明度
    },
    },
    XValues: xValues,
    YValues: yValue.Values,
    })
    }

    // 3、新建图形
    graph := chart.Chart{
    Title: title,
    Background: lineChartStyle,
    Width: lineChartWidth,
    Height: lineChartHeight,
    XAxis: chart.XAxis{
    Name: lineChartXAxisName,
    ValueFormatter: timeFormat,
    Ticks: ticks,
    },
    YAxis: chart.YAxis{
    Name: lineChartYAxisName,
    },
    Series: series,
    }
    graph.Elements = []chart.Renderable{
    chart.LegendLeft(&graph),
    }

    // 4、输出目标
    img, err = writeLineChart(&graph)

    return
    }

    // getNsec 获取纳秒数
    func getNsec(cur time.Time) float64 {
    return float64(cur.Unix() * int64(time.Second))
    }

    func writeLineChartToPng(c *chart.Chart) (img string, err error) {
    f, _ := os.Create("graph.png")
    err = c.Render(chart.PNG, f)
    return
    }

    func writeLineChart(c *chart.Chart) (img string, err error) {
    var imgContent bytes.Buffer
    err = c.Render(chart.PNG, &imgContent)
    if err != nil {
    return
    }

    img = imgToStr(imgContent)
    return
    }

    func imgToStr(imgContent bytes.Buffer) string {
    return imgStrPrefix + base64.StdEncoding.EncodeToString(imgContent.Bytes())
    }

    // createPieChart 创建饼图
    func createPieChart(title string, pieValues []ChartValue) (img string, err error) {
    if len(pieValues) == 0 {
    return
    }
    // 1、构建value
    var values []chart.Value
    for _, v := range pieValues {

    values = append(values, chart.Value{
    Value: v.Value,
    Label: fmt.Sprintf(pieLabelFormat, getSimpleSensType(v.Name), formatValue(v.Value)),
    })
    }

    // 2、新建饼图
    pie := chart.PieChart{
    Title: title,
    Background: defaultChartStyle,
    Values: values,
    }

    // 4、输出目标
    img, err = writePieChart(&pie)

    return
    }

    func formatValue(f float64) string {
    return fmt.Sprintf("%.2fW", f/10000)
    }

    func writePieChartToPng(c *chart.PieChart) (img string, err error) {
    f, _ := os.Create("pie.png")
    err = c.Render(chart.PNG, f)
    return
    }

    func writePieChart(c *chart.PieChart) (img string, err error) {
    var imgContent bytes.Buffer
    err = c.Render(chart.PNG, &imgContent)
    if err != nil {
    return
    }

    img = imgToStr(imgContent)
    return
    }

    // createBarChart 创建柱状图
    func createBarChart(title string, barValues []ChartValue) (img string, err error) {
    if len(barValues) == 0 {
    return
    }
    // 1、构建value
    var values []chart.Value
    for _, v := range barValues {
    values = append(values, chart.Value{
    Value: v.Value,
    Label: v.Name,
    })
    }

    // 2、新建饼图
    bar := chart.BarChart{
    XAxis: chart.Style{
    TextWrap: 0, // default 1为可以溢出规定的范围
    },
    Width: 2560,
    BarWidth: 50,
    BarSpacing: 300,
    Title: title,
    Background: defaultChartStyle,
    Bars: values,
    }

    // 4、输出目标
    img, err = writeBarChart(&bar)
    if err != nil && err.Error() == barChartTryAgainErr {
    // 添加一个隐藏条目,设置透明度A为0, 设置任意属性如R不为0即可
    values = append(values, chart.Value{
    Style: chart.Style{
    StrokeColor: drawing.Color{R: 1},
    },
    Value: 0,
    Label: "",
    })
    bar.Bars = values
    img, err = writeBarChart(&bar)
    }

    return
    }

    func writeBarChartToPng(c *chart.BarChart) (img string, err error) {
    f, _ := os.Create("bar.png")
    err = c.Render(chart.PNG, f)
    return
    }

    func writeBarChart(c *chart.BarChart) (img string, err error) {
    var imgContent bytes.Buffer
    err = c.Render(chart.PNG, &imgContent)
    if err != nil {
    return
    }

    img = imgToStr(imgContent)
    return
    }


    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
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    测试代码和生成图片效果
    修改以上writeXxxChart为writeXxxChartToPng后,运行以下测试代码

    package charter

    import (
    "testing"
    "time"

    "github.com/stretchr/testify/assert"
    )

    func TestCreateLineChart(t *testing.T) {
    testAssert := assert.New(t)

    tests := []struct {
    title string
    endTime time.Time
    barValues []LineYValue
    }{
    {"line chart", time.Now(), []LineYValue{
    {"asd", []float64{1, 2, 300, 100, 200, 6, 700}},
    {"hgj", []float64{400, 500000, 200, 50, 5, 800, 7}},
    {"dfg45r", []float64{1, 2, 700, 100, 200, 6, 700}},
    {"2342sr", []float64{400, 500000, 200, 50, 5, 800, 7}},
    {"das21-asd", []float64{300000, 200000, 400000, 100000, 400000, 450000, 400000}},
    {"csc", []float64{400, 500000, 200, 50, 5, 800, 7}},
    {"mhj", []float64{1, 2, 300, 100, 200, 6, 700}},
    {"876ijgh", []float64{400, 500000, 200, 50, 5, 800, 7}},
    {"fbfdv", []float64{1, 2, 300, 100, 200, 6, 700}},
    {"67ds", []float64{400, 10000, 200, 50, 5, 800, 7}},
    {"67bdfv", []float64{1, 2, 300, 100, 200, 6, 700}},
    {"sdf324", []float64{400, 500000, 200, 50, 5, 800, 7}},
    {"vdf67", []float64{1, 2, 300, 100, 200, 6, 700}},
    {"vdfs234", []float64{400, 500000, 200, 50, 5, 800, 7}},
    {"123sdf", []float64{1, 2, 700, 100, 200, 6, 700}},
    {"aasdasd", []float64{400, 500000, 200, 50, 5, 800, 7}},
    {"aasd", []float64{1, 2, 300, 100, 200, 6, 700}},
    {"basd", []float64{400, 500000, 200, 50, 5, 800, 7}},
    {"cczx", []float64{1, 2, 300, 100, 200, 6, 700}},
    {"qweqw", []float64{400, 500000, 200, 50, 5, 800, 7}},
    {"asdadf", []float64{1, 2, 300, 100, 200, 6, 700}},
    {"fghfh", []float64{400, 500000, 200, 50, 5, 800, 7}},
    {"erttyrt", []float64{1, 2, 300, 100, 200, 6, 700}}}},
    }

    for _, test := range tests {
    img, err := createLineChart(test.title, test.endTime, test.barValues)
    testAssert.Equal(img, "")
    testAssert.Equal(err, nil)
    }
    }

    func TestCreatePieChart(t *testing.T) {
    testAssert := assert.New(t)

    tests := []struct {
    title string
    pieValues []ChartValue
    }{
    {"pie chart", []ChartValue{{"asdas", 20000}, {"q12asd", 300000}, {"ascasd", 3000}}},
    }

    for _, test := range tests {
    img, err := createPieChart(test.title, test.pieValues)
    testAssert.Equal(img, "")
    testAssert.Equal(err, nil)
    }
    }

    func TestCreateBarChart(t *testing.T) {
    testAssert := assert.New(t)

    tests := []struct {
    title string
    pieValues []ChartValue
    }{
    {"bar chart", []ChartValue{{"asdascasd asd-asd", 20}, {"asdascascasdasdasd.go asdasd-asdasd", 30}, {"asasdasd.asdasd] asdasd-asda", 100},
    {"asdasdasda.go asdasd-asdasd", 20}, {"asdasd.asdasd geass", 30}, {"asdasdasd asdasd-asdasd", 100},
    {"asdasd_adsdasd_dasdasd-asd", 20}, {"asdascasdcad asdasdasda", 30}, {"asdasdasdasd", 100},
    {"asdasclkhy9p867p9", 20}}},
    }

    for _, test := range tests {
    img, err := createBarChart(test.title, test.pieValues)
    testAssert.Equal(img, "")
    testAssert.Equal(err, nil)
    }
    }

    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


    相关:
    https://github.com/wcharczuk/go-chart/issues/62
    go-chart使用中文
    go-echarts: html格式图表
    ————————————————
    版权声明:本文为CSDN博主「藏呆羊」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/zangdaiyang1991/java/article/details/105200062

  • 相关阅读:
    STM32 --- 什么时候打开复用IO的时钟(比如RCC_APB2Periph_AFIO)
    STM32 一直进入串口接收中断
    printf 中的 %.*s
    形参定义为二级指针,可以修改实参指针本身的值
    结构体和联合体配合使用
    自定义注解的实现思路
    log4j application.properties 配置文件
    外观设计模式
    适配器设计模式
    模版方法设计模式
  • 原文地址:https://www.cnblogs.com/oxspirt/p/13051414.html
Copyright © 2020-2023  润新知