Highcharts

Creating a dynamic chart from a JSS spreadsheet data.




JavaScript example

<html>
<script src="https://jspreadsheet.com/v10/jspreadsheet.js"></script>
<link rel="stylesheet" href="https://jspreadsheet.com/v10/jspreadsheet.css" type="text/css" />
<script src="https://jsuites.net/v5/jsuites.js"></script>
<link rel="stylesheet" href="https://jsuites.net/v5/jsuites.css" type="text/css" />

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>

<div id="spreadsheet"></div>

<script>
var data = [
    ['Tokyo', 7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6],
    ['New York', -0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5],
    ['Berlin', -0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0],
    ['London', 3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8],
];

var update = function (instance, cell, x, y, value) {
    // If the related series does not exists create a new one
    if (! chart.series[y]) {
        // Create a new series row
        var row = [];
        for (i = 1; i < data[y].length; i++) {
            row.push(parseFloat(data[y][i]));
        }
        // Append new series to the chart
        chart.addSeries({ name:data[y][0], data:row });
    } else {
        if (x == 0) {
            // Update legend
            chart.series[y].update({ name:value });
        } else {
            // Update chart data
            chart.series[y].data[x-1].update({ y:parseFloat(value) });
        }
    }
}

jspreadsheet.setLicense('ZWI0OGNjODljN2UwNGY3NWZhZTZhOTIzM2VmMjZiYTMzOTA5YjNhYjNhMmUzZGQ3YTZhODI4MTc5NzdiNDdhOWNmMmE3NTVmNTkwYmQ3NThlYWFhZGM2ODg0N2MzMDcwZjkzNDQ1ZjBmOTBmNGQwMzQ1ZmU5YzI4YmQyMDBkZGEsZXlKdVlXMWxJam9pU25Od2NtVmhaSE5vWldWMElpd2laR0YwWlNJNk1UY3hNRGt4TVRZME55d2laRzl0WVdsdUlqcGJJbXB6Y0hKbFlXUnphR1ZsZEM1amIyMGlMQ0pqYjJSbGMyRnVaR0p2ZUM1cGJ5SXNJbXB6YUdWc2JDNXVaWFFpTENKamMySXVZWEJ3SWl3aWQyVmlJaXdpYkc5allXeG9iM04wSWwwc0luQnNZVzRpT2lJek5DSXNJbk5qYjNCbElqcGJJblkzSWl3aWRqZ2lMQ0oyT1NJc0luWXhNQ0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklsMHNJbVJsYlc4aU9uUnlkV1Y5');

jspreadsheet(document.getElementById('spreadsheet'), {
    worksheets: [{
        data:data,
        columns: [
            { type: 'text', width:'200' },
        ],
    }],
    onchange: update,
});

var chart = null;

chart = Highcharts.chart('container', {
    title: {
        text: 'Monthly Average Temperature',
        x: -20 //center
    },
    subtitle: {
        text: 'Source: WorldClimate.com',
        x: -20
    },
    xAxis: {
        categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
            'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
    },
    yAxis: {
        title: {
            text: 'Temperature (°C)'
        },
        plotLines: [{
            value: 0,
            width: 1,
            color: '#808080'
        }]
    },
    tooltip: {
        valueSuffix: '°C'
    },
    legend: {
        layout: 'vertical',
        align: 'right',
        verticalAlign: 'middle',
        borderWidth: 0
    },
    series: [{
        name: 'Tokyo',
        data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
    }, {
        name: 'New York',
        data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5]
    }, {
        name: 'Berlin',
        data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0]
    }, {
        name: 'London',
        data: [3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8]
    }]
});
</script>
</html>
See this example on codesandbox

React example

import React, { useRef } from "react";
import { Spreadsheet, Worksheet } from "@jspreadsheet/react";
import HighchartsReact from "highcharts-react-official";
import Highcharts from "highcharts";

const license = 'ZWI0OGNjODljN2UwNGY3NWZhZTZhOTIzM2VmMjZiYTMzOTA5YjNhYjNhMmUzZGQ3YTZhODI4MTc5NzdiNDdhOWNmMmE3NTVmNTkwYmQ3NThlYWFhZGM2ODg0N2MzMDcwZjkzNDQ1ZjBmOTBmNGQwMzQ1ZmU5YzI4YmQyMDBkZGEsZXlKdVlXMWxJam9pU25Od2NtVmhaSE5vWldWMElpd2laR0YwWlNJNk1UY3hNRGt4TVRZME55d2laRzl0WVdsdUlqcGJJbXB6Y0hKbFlXUnphR1ZsZEM1amIyMGlMQ0pqYjJSbGMyRnVaR0p2ZUM1cGJ5SXNJbXB6YUdWc2JDNXVaWFFpTENKamMySXVZWEJ3SWl3aWQyVmlJaXdpYkc5allXeG9iM04wSWwwc0luQnNZVzRpT2lJek5DSXNJbk5qYjNCbElqcGJJblkzSWl3aWRqZ2lMQ0oyT1NJc0luWXhNQ0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklsMHNJbVJsYlc4aU9uUnlkV1Y5'

const chartOptions = {
    title: {
        text: "Monthly Average Temperature",
        x: -20 //center
    },
    subtitle: {
        text: "Source: WorldClimate.com",
        x: -20
    },
    xAxis: {
        categories: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
    },
    yAxis: {
        title: {
            text: "Temperature (°C)"
        },
        plotLines: [{
            value: 0,
            width: 1,
            color: "#808080"
        }]
    },
    tooltip: {
        valueSuffix: "°C"
    },
    legend: {
        layout: "vertical",
        align: "right",
        verticalAlign: "middle",
        borderWidth: 0
    },
    series: [{
        name: "Tokyo",
        data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
    },
    {
        name: "New York",
        data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5]
    },
    {
        name: "Berlin",
        data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0]
    },
    {
        name: "London",
        data: [3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8]
    }
    ]
};

export default function App() {
    // Spreadsheet array of worksheets
    const chart = useRef();
    const spreadsheet = useRef();
    // Data
    const data = [
        [chartOptions.series[0].name, ...chartOptions.series[0].data],
        [chartOptions.series[1].name, ...chartOptions.series[1].data],
        [chartOptions.series[2].name, ...chartOptions.series[2].data],
        [chartOptions.series[3].name, ...chartOptions.series[3].data]
    ];
    // Columns
    const columns = [{
        type: "text",
        width: "200"
    }];
    // Updates
    const updates = (instance, cell, x, y, value) => {
        const component = chart.current.chart;
        // If the related series does not exists create a new one
        if (!component.series[y]) {
            // Create a new series row
            var row = [];
            for (let i = 1; i < data[y].length; i++) {
                // @ts-ignore
                row.push(parseFloat(data[y][i]));
            }
            // Append new series to the chart
            component.addSeries({
                name: data[y][0],
                data: row
            });
        } else {
            if (x < 1) {
                // Update legend
                component.series[y].update({
                    name: value
                });
            } else {
                // Update chart data
                component.series[y].data[x - 1].update({
                    y: parseFloat(value)
                });
            }
        }
    };
    
    // Render data grid component
    return (
        <>
            <HighchartsReact ref={chart} highcharts={Highcharts} options={chartOptions} />
            <Spreadsheet ref={spreadsheet} license={license} onchange={updates}>
                <Worksheet data={data} columns={columns} minDimensions={[0, 4]} />
            </Spreadsheet>
        </>
        );
    }
See this example on codesandbox

Vue example

<template>
    <div>
      <highcharts ref="chart" :options="chartOptions" />
      <spreadsheet ref="spreadsheet" :license="license" :onchange="updates">
        <worksheet :data="data" :columns="columns" />
      </spreadsheet>
    </div>
</template>
      
<script>
import { Chart } from 'highcharts-vue'
import { Spreadsheet, Worksheet } from "@jspreadsheet/vue";

const chartOptions = {
  title: {
    text: "Monthly Average Temperature",
    x: -20 //center
  },
  subtitle: {
    text: "Source: WorldClimate.com",
    x: -20
  },
  xAxis: {
    categories: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
  },
  yAxis: {
    title: {
      text: "Temperature (°C)"
    },
    plotLines: [{
      value: 0,
      width: 1,
      color: "#808080"
    }]
  },
  tooltip: {
    valueSuffix: "°C"
  },
  legend: {
    layout: "vertical",
    align: "right",
    verticalAlign: "middle",
    borderWidth: 0
  },
  series: [{
    name: "Tokyo",
    data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
  },
  {
    name: "New York",
    data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5]
  },
  {
    name: "Berlin",
    data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0]
  },
  {
    name: "London",
    data: [3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8]
  }
  ]
};

const license = 'ZWI0OGNjODljN2UwNGY3NWZhZTZhOTIzM2VmMjZiYTMzOTA5YjNhYjNhMmUzZGQ3YTZhODI4MTc5NzdiNDdhOWNmMmE3NTVmNTkwYmQ3NThlYWFhZGM2ODg0N2MzMDcwZjkzNDQ1ZjBmOTBmNGQwMzQ1ZmU5YzI4YmQyMDBkZGEsZXlKdVlXMWxJam9pU25Od2NtVmhaSE5vWldWMElpd2laR0YwWlNJNk1UY3hNRGt4TVRZME55d2laRzl0WVdsdUlqcGJJbXB6Y0hKbFlXUnphR1ZsZEM1amIyMGlMQ0pqYjJSbGMyRnVaR0p2ZUM1cGJ5SXNJbXB6YUdWc2JDNXVaWFFpTENKamMySXVZWEJ3SWl3aWQyVmlJaXdpYkc5allXeG9iM04wSWwwc0luQnNZVzRpT2lJek5DSXNJbk5qYjNCbElqcGJJblkzSWl3aWRqZ2lMQ0oyT1NJc0luWXhNQ0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklsMHNJbVJsYlc4aU9uUnlkV1Y5'

export default {
  name: 'App',
  components: {
    Spreadsheet,
    Worksheet,
    highcharts: Chart,
  },
  methods: {
    updates(instance, cell, x, y, value) {
      const component = this.$refs.chart.chart;
        // If the related series does not exists create a new one
        if (!component.series[y]) {
            // Create a new series row
            var row = [];
            for (let i = 1; i < data[y].length; i++) {
                row.push(parseFloat(data[y][i]));
            }
            component.addSeries({
                name: data[y][0],
                data: row
            });
        } else {
            if (x < 1) {
                // Update legend
                component.series[y].update({
                    name: value
                });
            } else {
                // Update chart data
                component.series[y].data[x - 1].update({
                    y: parseFloat(value)
                });
            }
        }
    },
  },
  data() {
    return {
      columns: [{
        type: "text",
        width: "200"
      }],
      data: [
        [chartOptions.series[0].name, ...chartOptions.series[0].data],
        [chartOptions.series[1].name, ...chartOptions.series[1].data],
        [chartOptions.series[2].name, ...chartOptions.series[2].data],
        [chartOptions.series[3].name, ...chartOptions.series[3].data]
      ],
      license,
      chartOptions,
    };
  },
}
</script>

Angular example

import { Component, ViewChild, ElementRef } from "@angular/core";
import { Chart } from 'highcharts'
import * as jspreadsheet from "jspreadsheet";
import * as charts from "@jspreadsheet/charts";

// Set the license
jspreadsheet.setLicense('ZWI0OGNjODljN2UwNGY3NWZhZTZhOTIzM2VmMjZiYTMzOTA5YjNhYjNhMmUzZGQ3YTZhODI4MTc5NzdiNDdhOWNmMmE3NTVmNTkwYmQ3NThlYWFhZGM2ODg0N2MzMDcwZjkzNDQ1ZjBmOTBmNGQwMzQ1ZmU5YzI4YmQyMDBkZGEsZXlKdVlXMWxJam9pU25Od2NtVmhaSE5vWldWMElpd2laR0YwWlNJNk1UY3hNRGt4TVRZME55d2laRzl0WVdsdUlqcGJJbXB6Y0hKbFlXUnphR1ZsZEM1amIyMGlMQ0pqYjJSbGMyRnVaR0p2ZUM1cGJ5SXNJbXB6YUdWc2JDNXVaWFFpTENKamMySXVZWEJ3SWl3aWQyVmlJaXdpYkc5allXeG9iM04wSWwwc0luQnNZVzRpT2lJek5DSXNJbk5qYjNCbElqcGJJblkzSWl3aWRqZ2lMQ0oyT1NJc0luWXhNQ0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklsMHNJbVJsYlc4aU9uUnlkV1Y5');

const chartOptions = {
    title: {
        text: "Monthly Average Temperature",
        x: -20 //center
    },
    subtitle: {
        text: "Source: WorldClimate.com",
        x: -20
    },
    xAxis: {
        categories: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
    },
    yAxis: {
        title: {
            text: "Temperature (°C)"
        },
        plotLines: [{
            value: 0,
            width: 1,
            color: "#808080"
        }]
    },
    tooltip: {
        valueSuffix: "°C"
    },
    legend: {
        layout: "vertical",
        align: "right",
        verticalAlign: "middle",
        borderWidth: 0
    },
    series: [{
            name: "Tokyo",
            data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
        },
        {
            name: "New York",
            data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5]
        },
        {
            name: "Berlin",
            data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0]
        },
        {
            name: "London",
            data: [3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8]
        }
    ]
};

// Create the data grid component
@Component({
    selector: "app-root",
    template: `<div #chartContainer></div>
        <div #spreadsheet></div>`;
})
export class AppComponent {
    @ViewChild("spreadsheet") spreadsheet: ElementRef;
    @ViewChild("chartContainer") chartContainer: ElementRef;
    // Worksheets
    worksheets: jspreadsheet.worksheetInstance[];
    // Create a new data grid
    ngOnInit() {
        // Create summary spreadsheet
        this.worksheets = jspreadsheet(this.spreadsheet.nativeElement, {
            worksheets: [{
                data: [
                    [ chartOptions.series[0].name, ...chartOptions.series[0].data ],
                    [ chartOptions.series[1].name, ...chartOptions.series[1].data ],
                    [ chartOptions.series[2].name, ...chartOptions.series[2].data ],
                    [ chartOptions.series[3].name, ...chartOptions.series[3].data ]
                ],
                columns: [
                    { type: 'text', width:'200' },
                ],
            }],
            onchange: (instance, cell, x, y, value) => {
                // If the related series does not exists create a new one
                if (! this.chart.series[y]) {
                    // Create a new series row
                    var row = [];
                    for (i = 1; i < instance.options.data[y].length; i++) {
                        row.push(parseFloat(instance.options.data[y][i]));
                    }
                    // Append new series to the chart
                    chart.addSeries({ name: instance.options.data[y][0], data: row });
                } else {
                    if (x == 0) {
                        // Update legend
                        this.chart.series[y].update({ name:value });
                    } else {
                        // Update chart data
                        this.chart.series[y].data[x-1].update({ y:parseFloat(value) });
                    }
                }
            },
        });

        // Create external chart component
        this.chart = Highcharts.chart(this.chartContainer.nativeElement, chartOptions);

    }
}