Chart inside Hugo

Monday, 25 January 2021 @ 09:00
tech
I didn't want to use images

Overall Picture

Hugo+ChartJS

I wanted to add easily and in a markdown-stile way a bunch of chart in one of my blog posts.

I already knew ChartJS and that’s why I tried a different framework.

But then, while I was randomly googling I found a super-duper-easy way.

The ChartJS easy solution.

I found this cool integration: https://github.com/Shen-Yu but that wasn’t exactly what I was looking for.

I wanted a simple and markdown-style way of generating a chart.

So I knew I was going to review the code a bit

The design

I wanted a simple integration design: using markdown tables

That’s how I can invoke use the shortcode.

{ {< chart "100%" "300px" "false" >} }

|Label |Data     |
|------|---------|
| one  |7        |
| two  |7        |
|three |10       |
| four |6        |
| five |6        |

{ {< /chart-job >} } 

Parameters are:

So I simply created a shortcode, named shortcodes/chart.html

with this code.

{{ $width := default "100" (.Get 0) }}
{{ $height := default "300" (.Get 1) }}
{{ $showTable := default "true" (.Get 2)}}
{{ $r := ( .Inner | chomp ) }}
{{ $id := index (seq 999 | shuffle) 1 }}

{{ if eq $showTable "true" }}
    {{ .Inner | markdownify}}
{{ end }}


<div style="width: {{ $width }}; height: {{ $height }}; margin: 0 auto">
    <canvas id="{{ $id }}"></canvas>
</div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/Chart.min.js"></script>
<script type="text/javascript">

(function(){
    function selectColor(number) {
        const hue = number * 137.508; // use golden angle approximation
        return `hsl(${hue},50%,75%)`;
    }

    const innerString = {{$r}};
    
    const rowsString = innerString.trim().split('\n')
    let itemsString = rowsString.map(x => x.substring(1,x.length-1).trim().split('|'))
    
    // transpose
    itemsString = itemsString[0].map((_, colIndex) => itemsString.map(row => row[colIndex]));

    const labels = itemsString[0].slice(2).map(x => x.trim());
    
    let datasets = itemsString.slice(1).filter(x => x[0]);
    datasets = datasets.map((item, index) => {
        return {
            label: item[0].trim(),
            fill: false,
            borderColor: selectColor(index+1),
            data: item.slice(2).map(x => Number(x.trim()))
        };
    })

    var ctx = document.getElementById('{{ $id }}').getContext('2d');
    var options = {
        type: 'radar',
        data: {
            labels: labels,
            datasets: datasets
        },
        options: {
            maintainAspectRatio: false,
            scale: {
                angleLines: {
                    display: false
                },
                ticks: {
                    suggestedMin: 0,
                    suggestedMax: 10,
                    stepSize: 2,
                    showLabelBackdrop: false
                },
            },
            legend: {
                position: "right"
            }
        }
    };
    new Chart(ctx, options);

})();

</script>

Next Steps

I’ll probably evolve this tool and I may share this with an easier/direct installation with hugo.

But not so sure to be honest

⪡ Back