To use the chart feature, add the SpreadJS Chart JS file link into the document's head section:
You can create a chart with the sheet.charts.add method, as shown below:
In addition, you can also specify that the data source of the chart is multiple selections
When the set data source is equal to the table structure reference, chart will automatically update the series area
You can get a chart in the sheet using the sheet.charts.get method, remove a chart using the sheet.charts.remove method, and/or also clear all your charts using the sheet.charts.clear method.
A chart is built with many sub-elements, and you can customize each one using the chart API:
Chart Title: The title of the chart
You can get or set the text, the background color, the foreground color, the font, and the font size of the chart title.
Series: The data points of a data series that are plotted on the chart
You can get, add, or remove a series item from the series collection of a chart, as well as customize the name, border, width, border color, y value, x value, and fill color of each series item.
Data Labels: You can use data labels to identify the details of a data point in a data series
You can customize the chart’s series data labels style between below options
showValue
showSeriesName
showCategoryName
showPercentage
separator
position
format
color
transparency
backColor
backColorTransparency
borderColor
borderWidth
borderColorTransparency
SpreadJS provides 28 chart types. You can get or set the current chart type using the following code:
SpreadJS supports displaying blank cells in the following ways and displaying #N/A cells as blank in the chart:
gaps: Null values are skipped.
zero: Null values are treated as having a value of zero.
connected: Null values are skipped and the line of the area chart is connected.
SpreadJS supports showing or ignoring hidden rows and columns in chart.
SpreadJS supports preserving or ignoring unsupported chart types when importing.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import './styles.css';
import { AppFunc } from './app-func';
import { App } from './app-class';
// 1. Functional Component sample
ReactDOM.render(<AppFunc />, document.getElementById('app'));
// 2. Class Component sample
// ReactDOM.render(<App />, document.getElementById('app'));
import * as React from 'react';
import { useState } from 'react';
import * as ReactDOM from 'react-dom';
import GC from '@mescius/spread-sheets';
import { SpreadSheets, Worksheet } from '@mescius/spread-sheets-react';
import '@mescius/spread-sheets-shapes';
import '@mescius/spread-sheets-charts';
import './styles.css';
const Component = React.Component;
const chartType = [
[{
typeDesc: 'Clustered Column',
type: GC.Spread.Sheets.Charts.ChartType.columnClustered
}, {
typeDesc: 'Stacked Column',
type: GC.Spread.Sheets.Charts.ChartType.columnStacked
}, {
typeDesc: '100% Stacked Column',
type: GC.Spread.Sheets.Charts.ChartType.columnStacked100
}],
[{
typeDesc: 'Line',
type: GC.Spread.Sheets.Charts.ChartType.line
}, {
typeDesc: 'Stacked Line',
type: GC.Spread.Sheets.Charts.ChartType.lineStacked
}, {
typeDesc: '100% Stacked Line',
type: GC.Spread.Sheets.Charts.ChartType.lineStacked100
}, {
typeDesc: 'Line With Markers',
type: GC.Spread.Sheets.Charts.ChartType.lineMarkers
}, {
typeDesc: 'Stacked Line With Markers',
type: GC.Spread.Sheets.Charts.ChartType.lineMarkersStacked
}, {
typeDesc: '100% Stacked Line With Markers',
type: GC.Spread.Sheets.Charts.ChartType.lineMarkersStacked100
}],
[{
typeDesc: 'Pie',
type: GC.Spread.Sheets.Charts.ChartType.pie
}, {
typeDesc: 'Doughnut',
type: GC.Spread.Sheets.Charts.ChartType.doughnut
}],
[{
typeDesc: 'Clustered Bar',
type: GC.Spread.Sheets.Charts.ChartType.barClustered
}, {
typeDesc: 'Stacked Bar',
type: GC.Spread.Sheets.Charts.ChartType.barStacked
}, {
typeDesc: '100% Stacked Bar',
type: GC.Spread.Sheets.Charts.ChartType.barStacked100
}],
[{
typeDesc: 'Area',
type: GC.Spread.Sheets.Charts.ChartType.area
}, {
typeDesc: 'Stacked Area',
type: GC.Spread.Sheets.Charts.ChartType.areaStacked
}, {
typeDesc: '100% Stacked Area',
type: GC.Spread.Sheets.Charts.ChartType.areaStacked100
}],
[{
typeDesc: 'Scatter',
type: GC.Spread.Sheets.Charts.ChartType.xyScatter
}, {
typeDesc: 'Scatter With Smooth Lines And Markers',
type: GC.Spread.Sheets.Charts.ChartType.xyScatterSmooth
}, {
typeDesc: 'Scatter With Smooth Lines',
type: GC.Spread.Sheets.Charts.ChartType.xyScatterSmoothNoMarkers
}, {
typeDesc: 'Scatter With Straight Lines And Markers',
type: GC.Spread.Sheets.Charts.ChartType.xyScatterLines
}, {
typeDesc: 'Scatter With Straight Lines',
type: GC.Spread.Sheets.Charts.ChartType.xyScatterLinesNoMarkers
}, {
typeDesc: 'Bubble',
type: GC.Spread.Sheets.Charts.ChartType.bubble
}],
[{
typeDesc: 'High-Low-Close',
type: GC.Spread.Sheets.Charts.ChartType.stockHLC
}, {
typeDesc: 'Open-High-Low-Close',
type: GC.Spread.Sheets.Charts.ChartType.stockOHLC
}, {
typeDesc: 'Volume-High-Low-Close',
type: GC.Spread.Sheets.Charts.ChartType.stockVHLC
}, {
typeDesc: 'Volume-Open-High-Low-Close',
type: GC.Spread.Sheets.Charts.ChartType.stockVOHLC
}]
];
function _getElementById(id) {
return document.getElementById(id);
}
export function AppFunc() {
const [spread, setSpread] = useState(null);
const [ignoreHidden, setIgnoreHidden] = useState(true);
let initSpread = function (value) {
setSpread(value);
value.suspendPaint();
value.setSheetCount(3);
let sheet1 = value.getSheet(0);
sheet1.name("Common Chart");
let sheet2 = value.getSheet(1);
sheet2.name("Custom Chart");
let sheet3 = value.getSheet(2);
sheet3.name("Table Binding Chart");
initSheet(sheet1);
initSheet(sheet2);
initBindingTable(sheet3);
//add chart
initChart(sheet1);
initChart(sheet2);
initBindingChart(sheet3);
//custom chart
customChartStyle(sheet2);
value.resumePaint();
changeTypeSelect();
}
let initSheet = function (sheet) {
sheet.suspendPaint();
//prepare data for chart
let dataArray = [
["", 'Chrome', 'FireFox', 'IE', 'Safari', 'Edge', 'Opera', 'Other'],
["2015", 0.5651, 0.1734, 0.1711, 0.427, 0, 0.184, 0.293],
["2016", 0.6230, 0.1531, 0.1073, 0.464, 0.311, 0.166, 0.225],
["2017", 0.6360, 0.1304, 0.834, 0.589, 0.443, 0.223, 0.246]
];
sheet.setArray(0, 0, dataArray);
sheet.resumePaint();
}
let initBindingTable = function(sheet) {
sheet.suspendPaint();
let data = {
name: 'Jones',
region: 'East',
sales: [{
orderDate: '1/6/2013',
item: 'Pencil',
units: 95,
cost: 1.99
},
{
orderDate: '4/1/2013',
item: 'Binder',
units: 60,
cost: 4.99
},
{
orderDate: '6/8/2013',
item: 'Pen Set',
units: 16,
cost: 17.99
},
{
orderDate: '7/8/2013',
item: 'ball-point pen',
units: 16,
cost: 8.99
},
{
orderDate: '8/8/2013',
item: 'writing brush',
units: 16,
cost: 18.99
},
{
orderDate: '9/8/2013',
item: 'painting brush',
units: 16,
cost: 10.99
}
]
};
let tableColumns = [],
names = ['orderDate', 'item', 'units', 'cost'],
labels = ['Order Date', 'Item', 'Units', 'Cost'];
let table = sheet.tables.add('tableRecords', 0, 0, 4, 4);
table.autoGenerateColumns(false);
names.forEach(function (name, index) {
let tableColumn = new GC.Spread.Sheets.Tables.TableColumn();
tableColumn.name(labels[index]);
tableColumn.dataField(name);
tableColumns.push(tableColumn);
});
table.bindColumns(tableColumns);
table.bindingPath('sales');
let source = new GC.Spread.Sheets.Bindings.CellBindingSource(data);
sheet.setDataSource(source);
let button = sheet.shapes.addFormControl("button", GC.Spread.Sheets.Shapes.FormControlType.button, 500, 10, 150, 50);
button.text("Set Table Data Source");
let style = button.style();
style.textEffect.color = "rgb(0, 0, 0)";
style.textEffect.font = "bold 15px Calibri";
style.textFrame.vAlign = GC.Spread.Sheets.VerticalAlign.center;
style.textFrame.hAlign = GC.Spread.Sheets.HorizontalAlign.center;
button.style(style);
sheet.bind(GC.Spread.Sheets.Events.FormControlButtonClicked, function () {
let length = Math.floor(Math.random() * 20) + 1
data.sales = generateTestData(length, 10, 20);
let source = new GC.Spread.Sheets.Bindings.CellBindingSource(data);
sheet.setDataSource(source);
});
sheet.resumePaint();
}
let initChart = function (sheet) {
//add common chart
sheet.charts.add('Chart1', GC.Spread.Sheets.Charts.ChartType.columnClustered, 0, 100, 800, 300, "A1:H4");
}
let initBindingChart = function(sheet) {
//add table binding chart
sheet.charts.add('Chart1', GC.Spread.Sheets.Charts.ChartType.columnClustered, 250, 80, 800, 300, "tableRecords[[#Headers], [#Data], [Item]],tableRecords[[#Headers], [#Data], [Units]],tableRecords[[#Headers], [#Data], [Cost]]");
}
let customChartStyle = function (sheet) {
let changeChart = sheet.charts.all()[0];
changeChartStyle(changeChart);
}
let changeChartStyle = function (chart) {
//change orientation
switchOrientation(chart);
//change legend
changeChartLegend(chart);
//change chartArea
changeChartArea(chart);
//change chartTitle
changeChartTitle(chart);
//change dataLabels
changeChartDataLabels(chart);
//change axisTitles
changeChartAxisTitles(chart);
//change axesLine
changeChartAxesLine(chart);
//change series
changeSeries(chart);
//change gridLine
changeGridLine(chart);
//change seriesBorder
changeSeriesBorder(chart);
}
let switchOrientation = function (chart) {
chart.switchDataOrientation();
}
let changeChartLegend = function (chart) {
let legend = chart.legend();
legend.visible = true;
let legendPosition = GC.Spread.Sheets.Charts.LegendPosition;
legend.position = legendPosition.top;
chart.legend(legend);
}
let changeChartArea = function (chart) {
let chartArea = chart.chartArea();
chartArea.backColor = "rgba(93,93,93,1)";
chartArea.color = "rgba(255,255,255,1)";
chartArea.fontSize = 14;
chart.chartArea(chartArea);
}
let changeChartTitle = function (chart) {
let title = chart.title();
title.text = "Browser Market Share";
title.fontSize = 18;
chart.title(title);
}
let changeChartDataLabels = function (chart) {
let dataLabels = chart.dataLabels();
dataLabels.showValue = true;
dataLabels.showSeriesName = false;
dataLabels.showCategoryName = false;
dataLabels.format = "0.00%";
let dataLabelPosition = GC.Spread.Sheets.Charts.DataLabelPosition;
dataLabels.position = dataLabelPosition.outsideEnd;
chart.dataLabels(dataLabels);
let series0 = chart.series().get(0);
series0.dataLabels = {
showSeriesName: true,
showCategoryName: true,
separator: ";",
position: GC.Spread.Sheets.Charts.DataLabelPosition.Center,
color: "red",
backColor: "white",
borderColor: "blue",
borderWidth: 2
};
chart.series().set(0, series0);
let series2 = chart.series().get(2);
series2.dataLabels = {
showSeriesName: true,
separator: "/",
position: GC.Spread.Sheets.Charts.DataLabelPosition.insideEnd,
color: "yellow",
backColor: "white",
borderColor: "green",
borderWidth: 1
};
chart.series().set(2, series2);
let series4 = chart.series().get(4);
series4.dataLabels = {
showCategoryName: true,
separator: ":",
position: GC.Spread.Sheets.Charts.DataLabelPosition.above,
color: "blue",
backColor: "white",
borderColor: "red",
borderWidth: 2.5
};
chart.series().set(4, series4);
}
let changeChartAxisTitles = function (chart) {
let axes = chart.axes();
axes.primaryCategory.title.text = 'Year';
axes.primaryCategory.title.fontSize = 14;
chart.axes(axes);
}
let changeChartAxesLine = function (chart) {
let axes = chart.axes();
axes.primaryValue.format = "0%";
chart.axes(axes);
}
let changeSeries = function (chart) {
let series = chart.series();
let seriesItem = series.get(6);
seriesItem.backColor = "#a3cf62";
series.set(6, seriesItem);
}
let changeGridLine = function (chart) {
let axes = chart.axes();
axes.primaryCategory.majorGridLine.visible = false;
axes.primaryValue.majorGridLine.visible = false;
chart.axes(axes);
}
let changeSeriesBorder = function (chart) {
let series = chart.series().get();
for (let i = 0; i < series.length; i++) {
let seriesItem = series[i];
seriesItem.border.color = 'rgb(255,255,255)';
seriesItem.border.width = 1;
chart.series().set(i, seriesItem);
}
}
let getActiveChart = function (sheet) {
let activeChart = null;
sheet.charts.all().forEach(function (chart) {
if (chart.isSelected()) {
activeChart = chart;
}
});
return activeChart;
}
let judgeIsEmptyOneCell = function (sheet, range) {
if (range.rowCount === 1 && range.colCount === 1) {
let cell = sheet.getCell(range.row, range.col);
if (!cell.text()) {
return true;
}
}
return false;
}
let changeTypeSelect = function (e) {
let index = parseInt(e && e.target.value || 0);
if (index !== null && index !== undefined && index < chartType.length) {
_getElementById('typeSelect').innerHTML = '';
let typeArray = chartType[index];
for (let i = 0; i < typeArray.length; i++) {
let item = typeArray[i];
let option = document.createElement('option');
let value = document.createAttribute('value');
value.nodeValue = i;
option.setAttributeNode(value);
option.innerHTML = item.typeDesc;
_getElementById('typeSelect').appendChild(option);
}
}
}
let insertChart = function (chartInfo) {
let activeSheet = spread.getActiveSheet();
let dataRanges = activeSheet.getSelections();
let dataFormulas = [];
if (dataRanges) {
dataRanges.forEach((dataRange) => {
if (!judgeIsEmptyOneCell(activeSheet, dataRange)) {
let rangeToFormula = GC.Spread.Sheets.CalcEngine.rangeToFormula;
dataFormulas.push(rangeToFormula(dataRange));
}
})
}
let groupIndex = parseInt(chartInfo.groupType);
let typeIndex = parseInt(chartInfo.chartType);
if (groupIndex < chartType.length) {
let typeArray = chartType[groupIndex];
if (typeIndex < typeArray.length) {
let type = typeArray[typeIndex].type;
try {
activeSheet.charts.add('', type, 30, 120, 500, 300, dataFormulas.join(','), GC.Spread.Sheets.Charts.RowCol.rows);
} catch (e) {
alert(e.message);
}
}
}
}
let switchRowColumn = function (e) {
let activeSheet = spread.getActiveSheet();
let activeChart = getActiveChart(activeSheet);
if (activeChart) {
let isSwitched = activeChart.switchDataOrientation();
if (!isSwitched) {
alert("'Can't switch row/column");
}
}
}
let removeChart = function () {
let activeSheet = spread.getActiveSheet();
let activeChart = getActiveChart(activeSheet);
if (activeChart) {
activeSheet.charts.remove(activeChart.name());
}
}
let removeAllChart = function () {
let activeSheet = spread.getActiveSheet();
activeSheet.charts.clear();
}
let ignoreHiddenRowAndColumn = function (e) {
let activeSheet = spread.getActiveSheet();
let activeChart = getActiveChart(activeSheet);
let checked = e.target.checked;
activeChart && activeChart.ignoreHidden(checked);
setIgnoreHidden(checked);
}
let displayBlanksCells = function (e) {
let activeSheet = spread.getActiveSheet();
let activeChart = getActiveChart(activeSheet);
let index = parseInt(e.target.value);
if (index !== null && index !== undefined) {
activeChart && activeChart.displayBlanksAs(index);
}
}
let showNAAsBlanks = function (e) {
let activeSheet = spread.getActiveSheet();
let activeChart = getActiveChart(activeSheet);
activeChart && activeChart.displayNaNAsBlank(e.target.checked);
}
let generateTestData = function(length, maxUnits, maxCost) {
const testData = [];
const items = [
'apple', 'banana', 'orange', 'strawberry', 'grape', 'mango', 'watermelon',
'pineapple', 'kiwi', 'pear', 'peach', 'blueberry', 'cherry', 'lemon', 'lime',
'plum', 'raspberry', 'blackberry', 'pomegranate', 'coconut'
];
for (let i = 0; i < length; i++) {
const orderDate = new Date().toISOString().slice(0, 10);
const item = items[Math.floor(Math.random() * items.length)];
const units = Math.floor(Math.random() * maxUnits) + 1;
const cost = Math.floor(Math.random() * maxCost) + 1;
const order = {
orderDate: orderDate,
item: item,
units: units,
cost: cost
};
testData.push(order);
}
return testData;
}
return (<div class="sample-tutorial">
<div class="sample-spreadsheets">
<SpreadSheets workbookInitialized={spread => initSpread(spread)}>
<Worksheet />
</SpreadSheets>
</div>
<Panel
ignoreHidden={ignoreHidden}
insertChart={(e) => { insertChart(e) }}
switchRowColumn={(e) => { switchRowColumn(e) }}
removeChart={(e) => { removeChart(e) }}
removeAllChart={(e) => { removeAllChart(e) }}
changeTypeSelect={(e) => { changeTypeSelect(e) }}
displayBlanksCells={(e) => { displayBlanksCells(e) }}
showNAAsBlanks={(e) => { showNAAsBlanks(e) }}
ignoreHiddenRowAndColumn={(e) => { ignoreHiddenRowAndColumn(e) }}
/>
</div>);
}
class Panel extends Component {
constructor(props) {
super(props);
this.state = {
groupType: '0',
chartType: '0'
}
}
render() {
return (
<div class="options-container">
<p>Highlight a range of cells, select a chart group and chart type then click “Add Chart” to add the chart to the sheet.
Switch the axes with “Switch row/column” or remove the chart(s) with “Remove chart” or “Remove all charts”.
</p>
<div class="option-row">
<label>Group:</label>
<select id="groupSelect" style={{ width: "160px" }} value={this.state.groupType} onChange={(e) => {
this.setState({ groupType: e.target.value })
this.props.changeTypeSelect(e);
}}>
<option value="0">Column</option>
<option value="1">Line</option>
<option value="2">Pie</option>
<option value="3">Bar</option>
<option value="4">Area</option>
<option value="5">Scatter</option>
<option value="6">Stock</option>
</select>
</div>
<div class="option-row">
<label>Type:</label>
<select id="typeSelect" style={{ width: "160px" }} value={this.state.chartType} onChange={(e) => { this.setState({ chartType: e.target.value }) }}></select>
</div>
<div class="option-row">
<input type="button" style={{ width: "150px", margin: "5px", "margin-bottom": "15px" }} value="Add Chart" id="insertChart" onClick={(e) => { this.props.insertChart(this.state) }} />
<input type="button" style={{ width: "150px", margin: "5px" }} value="Switch row/column" id="switchRowColumn" onClick={(e) => { this.props.switchRowColumn(e) }} />
<input type="button" style={{ width: "150px", margin: "5px" }} value="Remove chart" id="removeChart" onClick={(e) => { this.props.removeChart(e) }} />
<input type="button" style={{ width: "150px", margin: "5px" }} value="Remove all charts" id="removeAllCharts" onClick={(e) => { this.props.removeAllChart(e) }} />
</div>
<div class="option-row">
<label>Display Blanks Cells As:</label>
<select id="displayBlanksCells" style={{ width: "80px" }} onChange={(e) => { this.props.displayBlanksCells(e) }}>
<option value="1" selected="selected">Gaps</option>
<option value="2">Zero</option>
<option value="0">Connect</option>
</select>
</div>
<div class="option-row">
<input type="checkbox" id="showNAAsBlanks" onClick={(e) => { this.props.showNAAsBlanks(e) }}></input>
<label for="showNAAsBlanks">Display #N/A Cells As Blank Cells</label>
</div>
<div class="option-row">
<input type="checkbox" id="ignoreHidden" checked={this.props.ignoreHidden} onClick={(e) => { this.props.ignoreHiddenRowAndColumn(e) }}></input>
<label for="ignoreHidden">Ingore Hidden Rows And Columns</label>
</div>
</div>
)
}
}
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import GC from '@mescius/spread-sheets';
import { SpreadSheets, Worksheet } from '@mescius/spread-sheets-react';
import '@mescius/spread-sheets-shapes';
import '@mescius/spread-sheets-charts';
import './styles.css';
const Component = React.Component;
const chartType = [
[{
typeDesc: 'Clustered Column',
type: GC.Spread.Sheets.Charts.ChartType.columnClustered
}, {
typeDesc: 'Stacked Column',
type: GC.Spread.Sheets.Charts.ChartType.columnStacked
}, {
typeDesc: '100% Stacked Column',
type: GC.Spread.Sheets.Charts.ChartType.columnStacked100
}],
[{
typeDesc: 'Line',
type: GC.Spread.Sheets.Charts.ChartType.line
}, {
typeDesc: 'Stacked Line',
type: GC.Spread.Sheets.Charts.ChartType.lineStacked
}, {
typeDesc: '100% Stacked Line',
type: GC.Spread.Sheets.Charts.ChartType.lineStacked100
}, {
typeDesc: 'Line With Markers',
type: GC.Spread.Sheets.Charts.ChartType.lineMarkers
}, {
typeDesc: 'Stacked Line With Markers',
type: GC.Spread.Sheets.Charts.ChartType.lineMarkersStacked
}, {
typeDesc: '100% Stacked Line With Markers',
type: GC.Spread.Sheets.Charts.ChartType.lineMarkersStacked100
}],
[{
typeDesc: 'Pie',
type: GC.Spread.Sheets.Charts.ChartType.pie
}, {
typeDesc: 'Doughnut',
type: GC.Spread.Sheets.Charts.ChartType.doughnut
}],
[{
typeDesc: 'Clustered Bar',
type: GC.Spread.Sheets.Charts.ChartType.barClustered
}, {
typeDesc: 'Stacked Bar',
type: GC.Spread.Sheets.Charts.ChartType.barStacked
}, {
typeDesc: '100% Stacked Bar',
type: GC.Spread.Sheets.Charts.ChartType.barStacked100
}],
[{
typeDesc: 'Area',
type: GC.Spread.Sheets.Charts.ChartType.area
}, {
typeDesc: 'Stacked Area',
type: GC.Spread.Sheets.Charts.ChartType.areaStacked
}, {
typeDesc: '100% Stacked Area',
type: GC.Spread.Sheets.Charts.ChartType.areaStacked100
}],
[{
typeDesc: 'Scatter',
type: GC.Spread.Sheets.Charts.ChartType.xyScatter
}, {
typeDesc: 'Scatter With Smooth Lines And Markers',
type: GC.Spread.Sheets.Charts.ChartType.xyScatterSmooth
}, {
typeDesc: 'Scatter With Smooth Lines',
type: GC.Spread.Sheets.Charts.ChartType.xyScatterSmoothNoMarkers
}, {
typeDesc: 'Scatter With Straight Lines And Markers',
type: GC.Spread.Sheets.Charts.ChartType.xyScatterLines
}, {
typeDesc: 'Scatter With Straight Lines',
type: GC.Spread.Sheets.Charts.ChartType.xyScatterLinesNoMarkers
}, {
typeDesc: 'Bubble',
type: GC.Spread.Sheets.Charts.ChartType.bubble
}],
[{
typeDesc: 'High-Low-Close',
type: GC.Spread.Sheets.Charts.ChartType.stockHLC
}, {
typeDesc: 'Open-High-Low-Close',
type: GC.Spread.Sheets.Charts.ChartType.stockOHLC
}, {
typeDesc: 'Volume-High-Low-Close',
type: GC.Spread.Sheets.Charts.ChartType.stockVHLC
}, {
typeDesc: 'Volume-Open-High-Low-Close',
type: GC.Spread.Sheets.Charts.ChartType.stockVOHLC
}]
];
function _getElementById(id) {
return document.getElementById(id);
}
export class App extends Component {
constructor(props) {
super(props);
this.spread = null;
this.state = { ignoreHidden: true };
}
render() {
return (<div class="sample-tutorial">
<div class="sample-spreadsheets">
<SpreadSheets workbookInitialized={spread => this.initSpread(spread)}>
<Worksheet />
</SpreadSheets>
</div>
<Panel
ignoreHidden={this.state.ignoreHidden}
insertChart={(e) => { this.insertChart(e) }}
switchRowColumn={(e) => { this.switchRowColumn(e) }}
removeChart={(e) => { this.removeChart(e) }}
removeAllChart={(e) => { this.removeAllChart(e) }}
changeTypeSelect={(e) => { this.changeTypeSelect(e) }}
displayBlanksCells={(e) => { this.displayBlanksCells(e) }}
showNAAsBlanks={(e) => { this.showNAAsBlanks(e) }}
ignoreHiddenRowAndColumn={(e) => { this.ignoreHiddenRowAndColumn(e) }}
/>
</div>);
}
initSpread(spread) {
this.spread = spread;
spread.suspendPaint();
spread.setSheetCount(3);
let sheet1 = spread.getSheet(0);
sheet1.name("Common Chart");
let sheet2 = spread.getSheet(1);
sheet2.name("Custom Chart");
let sheet3 = spread.sheets[2];
sheet3.name("Table Binding Chart");
this.initSheet(sheet1);
this.initSheet(sheet2);
this.initBindingTable(sheet3);
//add chart
this.initChart(sheet1);
this.initChart(sheet2);
this.initBindingChart(sheet3);
//custom chart
this.customChartStyle(sheet2);
spread.resumePaint();
this.changeTypeSelect();
}
initSheet(sheet) {
sheet.suspendPaint();
//prepare data for chart
let dataArray = [
["", 'Chrome', 'FireFox', 'IE', 'Safari', 'Edge', 'Opera', 'Other'],
["2015", 0.5651, 0.1734, 0.1711, 0.427, 0, 0.184, 0.293],
["2016", 0.6230, 0.1531, 0.1073, 0.464, 0.311, 0.166, 0.225],
["2017", 0.6360, 0.1304, 0.834, 0.589, 0.443, 0.223, 0.246]
];
sheet.setArray(0, 0, dataArray);
sheet.resumePaint();
}
initBindingTable(sheet) {
let self = this;
sheet.suspendPaint();
let data = {
name: 'Jones',
region: 'East',
sales: [{
orderDate: '1/6/2013',
item: 'Pencil',
units: 95,
cost: 1.99
},
{
orderDate: '4/1/2013',
item: 'Binder',
units: 60,
cost: 4.99
},
{
orderDate: '6/8/2013',
item: 'Pen Set',
units: 16,
cost: 17.99
},
{
orderDate: '7/8/2013',
item: 'ball-point pen',
units: 16,
cost: 8.99
},
{
orderDate: '8/8/2013',
item: 'writing brush',
units: 16,
cost: 18.99
},
{
orderDate: '9/8/2013',
item: 'painting brush',
units: 16,
cost: 10.99
}
]
};
let tableColumns = [],
names = ['orderDate', 'item', 'units', 'cost'],
labels = ['Order Date', 'Item', 'Units', 'Cost'];
let table = sheet.tables.add('tableRecords', 0, 0, 4, 4);
table.autoGenerateColumns(false);
names.forEach(function (name, index) {
let tableColumn = new GC.Spread.Sheets.Tables.TableColumn();
tableColumn.name(labels[index]);
tableColumn.dataField(name);
tableColumns.push(tableColumn);
});
table.bindColumns(tableColumns);
table.bindingPath('sales');
let source = new GC.Spread.Sheets.Bindings.CellBindingSource(data);
sheet.setDataSource(source);
let button = sheet.shapes.addFormControl("button", GC.Spread.Sheets.Shapes.FormControlType.button, 500, 10, 150, 50);
button.text("Set Table Data Source");
let style = button.style();
style.textEffect.color = "rgb(0, 0, 0)";
style.textEffect.font = "bold 15px Calibri";
style.textFrame.vAlign = GC.Spread.Sheets.VerticalAlign.center;
style.textFrame.hAlign = GC.Spread.Sheets.HorizontalAlign.center;
button.style(style);
sheet.bind(GC.Spread.Sheets.Events.FormControlButtonClicked, function () {
let length = Math.floor(Math.random() * 20) + 1
data.sales = self.generateTestData(length, 10, 20);
let source = new GC.Spread.Sheets.Bindings.CellBindingSource(data);
sheet.setDataSource(source);
});
sheet.resumePaint();
}
initChart(sheet) {
//add common chart
sheet.charts.add('Chart1', GC.Spread.Sheets.Charts.ChartType.columnClustered, 0, 100, 800, 300, "A1:H4");
}
initBindingChart(sheet) {
//add table binding chart
sheet.charts.add('Chart1', GC.Spread.Sheets.Charts.ChartType.columnClustered, 250, 80, 800, 300, "tableRecords[[#Headers], [#Data], [Item]],tableRecords[[#Headers], [#Data], [Units]],tableRecords[[#Headers], [#Data], [Cost]]");
}
customChartStyle(sheet) {
let changeChart = sheet.charts.all()[0];
this.changeChartStyle(changeChart);
}
changeChartStyle(chart) {
//change orientation
this.switchOrientation(chart);
//change legend
this.changeChartLegend(chart);
//change chartArea
this.changeChartArea(chart);
//change chartTitle
this.changeChartTitle(chart);
//change dataLabels
this.changeChartDataLabels(chart);
//change axisTitles
this.changeChartAxisTitles(chart);
//change axesLine
this.changeChartAxesLine(chart);
//change series
this.changeSeries(chart);
//change gridLine
this.changeGridLine(chart);
//change seriesBorder
this.changeSeriesBorder(chart);
}
switchOrientation(chart) {
chart.switchDataOrientation();
}
changeChartLegend(chart) {
let legend = chart.legend();
legend.visible = true;
let legendPosition = GC.Spread.Sheets.Charts.LegendPosition;
legend.position = legendPosition.top;
chart.legend(legend);
}
changeChartArea(chart) {
let chartArea = chart.chartArea();
chartArea.backColor = "rgba(93,93,93,1)";
chartArea.color = "rgba(255,255,255,1)";
chartArea.fontSize = 14;
chart.chartArea(chartArea);
}
changeChartTitle(chart) {
let title = chart.title();
title.text = "Browser Market Share";
title.fontSize = 18;
chart.title(title);
}
changeChartDataLabels(chart) {
let dataLabels = chart.dataLabels();
dataLabels.showValue = true;
dataLabels.showSeriesName = false;
dataLabels.showCategoryName = false;
dataLabels.format = "0.00%";
let dataLabelPosition = GC.Spread.Sheets.Charts.DataLabelPosition;
dataLabels.position = dataLabelPosition.outsideEnd;
chart.dataLabels(dataLabels);
let series0 = chart.series().get(0);
series0.dataLabels = {
showSeriesName: true,
showCategoryName: true,
separator: ";",
position: GC.Spread.Sheets.Charts.DataLabelPosition.Center,
color: "red",
backColor: "white",
borderColor: "blue",
borderWidth: 2
};
chart.series().set(0, series0);
let series2 = chart.series().get(2);
series2.dataLabels = {
showSeriesName: true,
separator: "/",
position: GC.Spread.Sheets.Charts.DataLabelPosition.insideEnd,
color: "yellow",
backColor: "white",
borderColor: "green",
borderWidth: 1
};
chart.series().set(2, series2);
let series4 = chart.series().get(4);
series4.dataLabels = {
showCategoryName: true,
separator: ":",
position: GC.Spread.Sheets.Charts.DataLabelPosition.above,
color: "blue",
backColor: "white",
borderColor: "red",
borderWidth: 2.5
};
chart.series().set(4, series4);
}
changeChartAxisTitles(chart) {
let axes = chart.axes();
axes.primaryCategory.title.text = 'Year';
axes.primaryCategory.title.fontSize = 14;
chart.axes(axes);
}
changeChartAxesLine(chart) {
let axes = chart.axes();
axes.primaryValue.format = "0%";
chart.axes(axes);
}
changeSeries(chart) {
let series = chart.series();
let seriesItem = series.get(6);
seriesItem.backColor = "#a3cf62";
series.set(6, seriesItem);
}
changeGridLine(chart) {
let axes = chart.axes();
axes.primaryCategory.majorGridLine.visible = false;
axes.primaryValue.majorGridLine.visible = false;
chart.axes(axes);
}
changeSeriesBorder(chart) {
let series = chart.series().get();
for (let i = 0; i < series.length; i++) {
let seriesItem = series[i];
seriesItem.border.color = 'rgb(255,255,255)';
seriesItem.border.width = 1;
chart.series().set(i, seriesItem);
}
}
getActiveChart(sheet) {
let activeChart = null;
sheet.charts.all().forEach(function (chart) {
if (chart.isSelected()) {
activeChart = chart;
}
});
return activeChart;
}
judgeIsEmptyOneCell(sheet, range) {
if (range && range.rowCount === 1 && range.colCount === 1) {
let cell = sheet.getCell(range.row, range.col);
if (!cell.text()) {
return true;
}
}
return false;
}
changeTypeSelect(e) {
let index = parseInt(e && e.target.value || 0);
if (index !== null && index !== undefined && index < chartType.length) {
_getElementById('typeSelect').innerHTML = '';
let typeArray = chartType[index];
for (let i = 0; i < typeArray.length; i++) {
let item = typeArray[i];
let option = document.createElement('option');
let value = document.createAttribute('value');
value.nodeValue = i;
option.setAttributeNode(value);
option.innerHTML = item.typeDesc;
_getElementById('typeSelect').appendChild(option);
}
}
}
insertChart(chartInfo) {
let activeSheet = this.spread.getActiveSheet();
let dataRanges = activeSheet.getSelections();
let dataFormulas = [];
if (dataRanges) {
dataRanges.forEach((dataRange) => {
if (!this.judgeIsEmptyOneCell(activeSheet, dataRange)) {
let rangeToFormula = GC.Spread.Sheets.CalcEngine.rangeToFormula;
dataFormulas.push(rangeToFormula(dataRange));
}
})
}
let groupIndex = parseInt(chartInfo.groupType);
let typeIndex = parseInt(chartInfo.chartType);
if (groupIndex < chartType.length) {
let typeArray = chartType[groupIndex];
if (typeIndex < typeArray.length) {
let type = typeArray[typeIndex].type;
try {
activeSheet.charts.add('', type, 30, 120, 500, 300, dataFormulas.join(','), GC.Spread.Sheets.Charts.RowCol.rows);
} catch (e) {
alert(e.message);
}
}
}
}
switchRowColumn(e) {
let activeSheet = this.spread.getActiveSheet();
let activeChart = this.getActiveChart(activeSheet);
if (activeChart) {
let isSwitched = activeChart.switchDataOrientation();
if (!isSwitched) {
alert("'Can't switch row/column");
}
}
}
removeChart() {
let activeSheet = this.spread.getActiveSheet();
let activeChart = this.getActiveChart(activeSheet);
if (activeChart) {
activeSheet.charts.remove(activeChart.name());
}
}
removeAllChart() {
let activeSheet = this.spread.getActiveSheet();
activeSheet.charts.clear();
}
ignoreHiddenRowAndColumn(e) {
let activeSheet = this.spread.getActiveSheet();
let activeChart = this.getActiveChart(activeSheet);
let checked = e.target.checked;
activeChart && activeChart.ignoreHidden(checked);
this.setState(() => ({
ignoreHidden: checked
}));
}
displayBlanksCells(e) {
let activeSheet = this.spread.getActiveSheet();
let activeChart = this.getActiveChart(activeSheet);
let index = parseInt(e.target.value);
if (index !== null && index !== undefined) {
activeChart && activeChart.displayBlanksAs(index);
}
}
showNAAsBlanks(e) {
let activeSheet = this.spread.getActiveSheet();
let activeChart = this.getActiveChart(activeSheet);
activeChart && activeChart.displayNaNAsBlank(e.target.checked);
}
generateTestData(length, maxUnits, maxCost) {
const testData = [];
const items = [
'apple', 'banana', 'orange', 'strawberry', 'grape', 'mango', 'watermelon',
'pineapple', 'kiwi', 'pear', 'peach', 'blueberry', 'cherry', 'lemon', 'lime',
'plum', 'raspberry', 'blackberry', 'pomegranate', 'coconut'
];
for (let i = 0; i < length; i++) {
const orderDate = new Date().toISOString().slice(0, 10);
const item = items[Math.floor(Math.random() * items.length)];
const units = Math.floor(Math.random() * maxUnits) + 1;
const cost = Math.floor(Math.random() * maxCost) + 1;
const order = {
orderDate: orderDate,
item: item,
units: units,
cost: cost
};
testData.push(order);
}
return testData;
}
}
class Panel extends Component {
constructor(props) {
super(props);
this.state = {
groupType: '0',
chartType: '0'
}
}
render() {
return (
<div class="options-container">
<p>Highlight a range of cells, select a chart group and chart type then click “Add Chart” to add the chart to the sheet.
Switch the axes with “Switch row/column” or remove the chart(s) with “Remove chart” or “Remove all charts”.
</p>
<div class="option-row">
<label>Group:</label>
<select id="groupSelect" style={{ width: "160px" }} value={this.state.groupType} onChange={(e) => {
this.setState({ groupType: e.target.value })
this.props.changeTypeSelect(e);
}}>
<option value="0">Column</option>
<option value="1">Line</option>
<option value="2">Pie</option>
<option value="3">Bar</option>
<option value="4">Area</option>
<option value="5">Scatter</option>
<option value="6">Stock</option>
</select>
</div>
<div class="option-row">
<label>Type:</label>
<select id="typeSelect" style={{ width: "160px" }} value={this.state.chartType} onChange={(e) => { this.setState({ chartType: e.target.value }) }}></select>
</div>
<div class="option-row">
<input type="button" style={{ width: "150px", margin: "5px", "margin-bottom": "15px" }} value="Add Chart" id="insertChart" onClick={(e) => { this.props.insertChart(this.state) }} />
<input type="button" style={{ width: "150px", margin: "5px" }} value="Switch row/column" id="switchRowColumn" onClick={(e) => { this.props.switchRowColumn(e) }} />
<input type="button" style={{ width: "150px", margin: "5px" }} value="Remove chart" id="removeChart" onClick={(e) => { this.props.removeChart(e) }} />
<input type="button" style={{ width: "150px", margin: "5px" }} value="Remove all charts" id="removeAllCharts" onClick={(e) => { this.props.removeAllChart(e) }} />
</div>
<div class="option-row">
<label>Display Blanks Cells As:</label>
<select id="displayBlanksCells" style={{ width: "80px" }} onChange={(e) => { this.props.displayBlanksCells(e) }}>
<option value="1" selected="selected">Gaps</option>
<option value="2">Zero</option>
<option value="0">Connect</option>
</select>
</div>
<div class="option-row">
<input type="checkbox" id="showNAAsBlanks" onClick={(e) => { this.props.showNAAsBlanks(e) }}></input>
<label for="showNAAsBlanks">Display #N/A Cells As Blank Cells</label>
</div>
<div class="option-row">
<input type="checkbox" id="ignoreHidden" checked={this.props.ignoreHidden} onClick={(e) => { this.props.ignoreHiddenRowAndColumn(e) }}></input>
<label for="ignoreHidden">Ingore Hidden Rows And Columns</label>
</div>
</div>
)
}
}
<!doctype html>
<html style="height:100%;font-size:14px;">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/react/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css">
<!-- SystemJS -->
<script src="$DEMOROOT$/en/react/node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('$DEMOROOT$/en/lib/react/license.js').then(function () {
System.import('./src/app');
});
</script>
</head>
<body>
<div id="app"></div>
</body>
</html>
.sample-tutorial {
position: relative;
height: 100%;
overflow: hidden;
}
.sample-spreadsheets {
width: calc(100% - 280px);
height: 100%;
overflow: hidden;
float: left;
}
.options-container {
float: right;
width: 280px;
padding: 12px;
height: 100%;
box-sizing: border-box;
background: #fbfbfb;
overflow: auto;
}
.option-row {
font-size: 14px;
padding: 2px;
margin-top: 2px;
}
.sample-options {
z-index: 1000;
}
label {
margin-bottom: 6px;
}
p{
padding:2px 10px;
background-color:#F4F8EB;
}
input {
padding: 2px 6px;
}
input[type=button] {
margin-top: 6px;
display: block;
}
body {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
#app {
height: 100%;
}
(function (global) {
System.config({
transpiler: 'plugin-babel',
babelOptions: {
es2015: true,
react: true
},
meta: {
'*.css': { loader: 'css' }
},
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
'@mescius/spread-sheets-shapes': 'npm:@mescius/spread-sheets-shapes/index.js',
'@mescius/spread-sheets-charts': 'npm:@mescius/spread-sheets-charts/index.js',
'@mescius/spread-sheets': 'npm:@mescius/spread-sheets/index.js',
'@mescius/spread-sheets-react': 'npm:@mescius/spread-sheets-react/index.js',
'@grapecity/jsob-test-dependency-package/react-components': 'npm:@grapecity/jsob-test-dependency-package/react-components/index.js',
'react': 'npm:react/umd/react.production.min.js',
'react-dom': 'npm:react-dom/umd/react-dom.production.min.js',
'css': 'npm:systemjs-plugin-css/css.js',
'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js',
'systemjs-babel-build':'npm:systemjs-plugin-babel/systemjs-babel-browser.js'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
src: {
defaultExtension: 'jsx'
},
"node_modules": {
defaultExtension: 'js'
},
}
});
})(this);