[C3.js][TypeScript] Draw line charts 2
Tags: typescript, c3js
Published: 2021-11-21 16:59:01

## Intro
This time, I will try saving the line charts as images.

* [[C3.js][TypeScript] Draw line charts 1](https://dev.to/masanori_msl/c3jstypescript-draw-line-charts-1-1g0)

## Offset

The chart what I created last time, the positions of 0 weren't at start point.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8j1k9yjhv93hbxg0zic8.png)

To set offset values as 0, add "padding" into "axis".

#### chartViewer.ts
```ts
import c3 from "c3";
import { ChartValues } from "./chart.type";

export class ChartViewer {
    private chartElement: HTMLElement;
    private chart: c3.ChartAPI|null = null;
...
    public draw(value: ChartValues): void {
        const valueXList = this.getValueX(0, 10);
        const ticksX = this.getTicks(valueXList);
        const valueYList = value.values.map(v => v.y);
        const gridLineY = valueYList.map(t => this.generateGridLine(t));
        const gridLines = valueXList.map(t => this.generateGridLine(t));

        this.chart = c3.generate({
            bindto: this.chartElement,
            data: {
                x: "x",
                columns: [
                    ["data1", ...value.values.map(v => v.y)],
                    ["x", ...value.values.map(v => v.x)],
                ],
                types: {
                    data1: "line"
                },
            },
            axis: {
                x: {
                    min: 0,
                    max: 10,
                    tick: {
                        values: [...ticksX],
                        outer: false,
                    },
                    padding: { left: 0, }
                },
                y: {
                    min: 0,
                    padding: { bottom: 0, }
                }
            },
            grid: {
                x: {
                    show: false,
                    lines: [...gridLines],
                },
                y: {
                    show: false,
                    lines: [...gridLineY],
                }
            },
            interaction: {
                enabled: false,
            },
        });
    }
...
}
```

#### Result
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l801szpcjakn4lna93pb.png)

## Save as an image

I can save the chart as an image.

#### chartViewer.ts
```ts
...
    public saveImage(): void {
        const svg = this.getSvgRoot();
        if(svg == null) {
            console.error("svg was null");            
            return;
        }
        const serializedImage = new XMLSerializer().serializeToString(svg);
        const image = new Image();
        image.onload = () => {
            const canvas = document.createElement("canvas");
            canvas.width = this.chartElement.clientWidth;
            canvas.height = this.chartElement.clientHeight;
            const ctx = canvas.getContext("2d");
            if(ctx == null) {
                console.error("ctx was null");
                return;
            }
            ctx.drawImage(image, 0, 0);
            document.body.appendChild(canvas);
        };
        image.src = "data:image/svg+xml;charset=utf-8;base64," + window.btoa(serializedImage);
    }
...
```

#### main.page.view.ts
```ts
import { ChartValues } from "./charts/chart.type";
import { ChartViewer } from "./charts/chartViewer";

export class MainPageView {
    private chartRoot: HTMLElement;
    private charts: ChartViewer[] = [];
    public constructor() {
        this.chartRoot = document.getElementById("chart_root") as HTMLElement;
    }
    public updateValues(values: readonly ChartValues[]): void {
        const sampleChart = new ChartViewer(this.chartRoot);
        sampleChart.draw(values[0]!);
        this.charts.push(sampleChart);
        // To save images, I must wait for drawing the chart.
        setTimeout(() => {
            sampleChart.saveImage();
        }, 100);    
    }
}
```

* [JSFiddle: https://jsfiddle.net/vtange/vajs3cmf/](https://jsfiddle.net/vtange/vajs3cmf/)

#### Result
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lomqej2me8b950syxdvz.png)

### Set CSS values

One problem is that the saved image doesn't reflect the CSS.
So the line what had been drawn in the image was filled and the grid lines weren't drawn.

To draw them, I have to set styles by TypeScript(JavaScript).

#### chartViewer.ts
```ts
...
    public saveImage(): void {
        const svg = this.getSvgRoot();
        if(svg == null) {
            console.error("svg was null");            
            return;
        }
        const chartPaths = this.getElementsBySelector(svg, ".c3-chart path");
        const axisPaths = this.getElementsBySelector(svg, ".c3-axis path");
        const lines = this.getElementsBySelector(svg, ".c3 line");

        const gridLines = Array.from(axisPaths).concat(Array.from(lines));
        chartPaths.forEach((element) => {
            this.setCssValue(element);
        });
        gridLines.forEach((element) => {
            this.setCssValue(element, "green");
        });

        const serializedImage = new XMLSerializer().serializeToString(svg);
        const image = new Image();
        image.onload = () => {            
...
        };
        image.src = "data:image/svg+xml;charset=utf-8;base64," + window.btoa(serializedImage);
    }
...
    private getElementsBySelector(element: SVGElement, selector: string): readonly CSSStyleDeclaration[] {
        const results: CSSStyleDeclaration[] = [];
        const nodes = element.querySelectorAll(selector);
        for(let i = 0; i < nodes.length; i++) {
            const node = nodes[i];
            // Force getting "style" attribute.
            if(node != null &&
                    (node as any)["style"] != null) {
                results.push((node as any)["style"]);
            }
        }
        return results;
    }
    private setCssValue(style: CSSStyleDeclaration, stroke?: string): void {
        style.fill = "none";
        if(stroke != null) {
            style.stroke = stroke;
        }
    }
}
```

#### Result
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qe9j650dj5ygoyhsr36r.png)

* [Exporting c3.js line charts to png images does not work - Stack Overflow](https://stackoverflow.com/questions/37701361/exporting-c3-js-line-charts-to-png-images-does-not-work)

Because I haven't set CSS values yet, next time I will try do that.