垂直显示嵌入的组合图表
Display vertically an embedded combo chart
我正在尝试使用 EmbeddedComboChartBuilder 显示组合成一条线的条形图。
为此,我使用了以下代码和数据:
function createChartSerie() {
var ss = SpreadsheetApp.openById('XXX...');
var sheet = ss.getSheetByName("sheet1");
var chartTableXRange = sheet.getRange("A1:A24");
var chartTableYRange = sheet.getRange("B1:C24");
var chart = sheet.newChart()
.setOption('useFirstColumnAsDomain', true)
.setOption('hAxis', {
title: 'X',
format: '#,##'
})
.setOption('vAxes', {0: {
title: 'Y', format: '#,##'
}})
.setChartType(Charts.ChartType.COMBO)
.addRange(chartTableXRange) // x axis
.addRange(chartTableYRange) //first y data
.setPosition(5, 5, 0, 0)
.setOption('orientation', 'vertical')
.setOption('series', {
0: {
type: 'line',
color: 'red'
},
1: {
type: 'bars',
color: 'blue'
}
})
.build();
sheet.insertChart(chart);
}
用于显示组合图的数据范围:
A B C
1 0.0001 0
1.5 0.0009 0.0006
2 0.0044 0.0037
2.5 0.0175 0.0133
3 0.054 0.0236
3.5 0.1296 0.0533
4 0.242 0.0073
4.5 0.3522 0.2468
5 0.399 0.0843
5.5 0.3522 0.3352
6 0.242 0.2201
6.5 0.1296 0.0607
7 0.054 0.0256
7.5 0.0175 0.0006
8 0.0044 0.003
8.5 0.0009 0.0005
9 0.0001 0.0001
似乎选项.setOption('orientation', 'vertical')没有效果,如下图所示:
此选项在与 google 可视化一起使用时效果很好,就像您在 this JSFiddle 中看到的那样。
回答
很遗憾 Sheets API 不支持此选项 (see the embedded charts resource)。
好像有一个feature request in Google’s Issue Tracker。您可以单击白色开始 (☆),以便 Google 知道您希望完成此操作。
解决方法
有 2 种解决方法:在网络上使用 Google Charts 本身(与 WebApps 和模态一起使用),并使用 Google Charts 生成图表,将页面上的 SVG 转换为 PNG 和将其嵌入到电子表格中。生成 PNG 需要制作模态,因此此设置说明适用于两种解决方法。
第 1 步:制作一个使用 Google Charts 制作图表的页面
获取一些模拟数据并制作图表,根据自己的喜好进行设计,并确保一切正常。
第 2 步:使用模式显示它
添加一个名为 Chart
的新 HTML 文件(您可以更改名称,但需要在代码中进行更改)并粘贴您制作的代码。
有了模拟图表后,我们需要使用模式来显示它。我们首先需要在电子表格中添加一个菜单:
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('Chart generator')
.addItem('Create and insert chart', 'showChart')
.addToUi()
}
然后我们添加显示模态的函数:
function showChart() {
const html = HtmlService.createHtmlOutputFromFile('Chart')
.setWidth(900)
.setHeight(600)
SpreadsheetApp.getUi().showModalDialog(html, 'Chart')
}
您还可以使用相同的模板设置 WebApp:
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('Chart')
.setWidth(900)
.setHeight(600)
}
第 3 步:从电子表格中获取数据
现在是删除模拟数据并获取实际数据的时候了。为此,我们将使用 google.script.run
函数异步加载数据。此示例使用异步逻辑,因此它可以并行加载图表库和数据。
google.charts.load('current', {'packages':['corechart']})
const readyPromise = toAsync(resolve => google.charts.setOnLoadCallback(resolve))
const dataPromise = toAsync((resolve, reject) => {
google.script.run
.withSuccessHandler(resolve)
.withFailureHandler(reject)
.getData()
})
toAsync
是一个辅助函数,它确保在出现失败回调未处理的错误时拒绝:
function toAsync(callback) {
return new Promise((resolve, reject) => {
try {
callback(resolve, reject)
} catch(e) {
reject(e)
}
})
}
然后我们需要在 Google Apps 脚本中添加实际从电子表格中读取数据的函数:
function getData() {
return SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('Sheet1')
.getRange('A1:C18')
.getValues()
}
然后在主函数中简单地使用两者:
async function drawVisualization() {
const el = document.getElementById('chart_div')
await readyPromise
const data = google.visualization.arrayToDataTable(await dataPromise)
const options = { … }
new google.visualization.ComboChart(el).draw(data, options)
}
确保调用处理承诺拒绝,否则您可能会在不知不觉中消除错误:
document.addEventListener('DOMContentLoaded', () => drawVisualization().catch(console.error))
(可选)第 4 步:将图表嵌入为 PNG
Google 图表生成 SVG。不幸的是,我们无法嵌入 SVG,因此我们需要将其转换为 PNG。最简单的方法是使用像 canvg
这样的外部库,它允许我们将 SVG 绘制成 canvas。然后我们可以将 canvas 导出为 PNG。
将 canvas 添加到您的 body 并将图书馆添加到您的头上。
然后您可以使用(附加到 drawVisualization
)在 canvas 上绘制:
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
v = canvg.Canvg.fromString(ctx, el.getElementsByTagName('svg')[0].outerHTML)
v.start()
await v.ready()
这将绘制它并等待它完成。
现在我们需要一种将生成的图像发送到 GAS 以便它可以嵌入的方法。值得庆幸的是,我们可以获得 PNG 的 base64 并将其发送到那里:
const base64 = canvas.toDataURL('image/png').split(';base64,')[1]
await toAsync((resolve, reject) => {
google.script.run
.withSuccessHandler(resolve)
.withFailureHandler(reject)
.insertChart(base64)
})
并且在 Google Apps 脚本中,我们定义 insertChart
:
function insertChart(base64png) {
const blob = Utilities.newBlob(
Utilities.base64Decode(base64png, Utilities.Charset.US_ASCII),
'image/png',
'chart.png'
)
SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('Sheet1')
.insertImage(blob, 5, 5, 0, 0)
}
(可选)第 5 步:在生成图表时关闭模态并隐藏图表
既然插入了,我喜欢自动关闭模态框。为此,只需将其附加到 drawVisualization
:
google.script.host.close()
我也喜欢在处理时不显示图表。一点 CSS 就足够了:
canvas, #chart_div {
visibility: hidden;
}
body {
overflow: hidden;
}
您不能使用 display: none
,因为那样会生成错误大小的图表。设置溢出是为了避免滚动条变成空
您还可以将屏幕标题甚至加载动画更改为模态。
参考资料
- Google 工作区中的自定义菜单(Google 开发人员)
- 将 HTML 作为 Google 文档、Sheet、幻灯片或表单用户界面(Google 开发人员)
- HtmlService.createHtmlOutputFromFile(Google 开发人员)
- 作为 Web 应用程序提供 HTML(Google 开发人员)
- google.script.run(Google 开发人员)
- 范围 getValues()(Google 开发人员)
- Utilities.newBlob(数据、内容类型、名称)(Google 开发人员)
- Utilities.base64Decode(已编码,字符集)(Google 开发人员)
- Sheet insertImage(blobSource,列,行)(Google 开发人员)
- google.script.host close() (Google 开发人员)
- Canvas toDataURL (MDN)
- 承诺 (MDN)
我正在尝试使用 EmbeddedComboChartBuilder 显示组合成一条线的条形图。 为此,我使用了以下代码和数据:
function createChartSerie() {
var ss = SpreadsheetApp.openById('XXX...');
var sheet = ss.getSheetByName("sheet1");
var chartTableXRange = sheet.getRange("A1:A24");
var chartTableYRange = sheet.getRange("B1:C24");
var chart = sheet.newChart()
.setOption('useFirstColumnAsDomain', true)
.setOption('hAxis', {
title: 'X',
format: '#,##'
})
.setOption('vAxes', {0: {
title: 'Y', format: '#,##'
}})
.setChartType(Charts.ChartType.COMBO)
.addRange(chartTableXRange) // x axis
.addRange(chartTableYRange) //first y data
.setPosition(5, 5, 0, 0)
.setOption('orientation', 'vertical')
.setOption('series', {
0: {
type: 'line',
color: 'red'
},
1: {
type: 'bars',
color: 'blue'
}
})
.build();
sheet.insertChart(chart);
}
用于显示组合图的数据范围:
A B C
1 0.0001 0
1.5 0.0009 0.0006
2 0.0044 0.0037
2.5 0.0175 0.0133
3 0.054 0.0236
3.5 0.1296 0.0533
4 0.242 0.0073
4.5 0.3522 0.2468
5 0.399 0.0843
5.5 0.3522 0.3352
6 0.242 0.2201
6.5 0.1296 0.0607
7 0.054 0.0256
7.5 0.0175 0.0006
8 0.0044 0.003
8.5 0.0009 0.0005
9 0.0001 0.0001
似乎选项.setOption('orientation', 'vertical')没有效果,如下图所示:
此选项在与 google 可视化一起使用时效果很好,就像您在 this JSFiddle 中看到的那样。
回答
很遗憾 Sheets API 不支持此选项 (see the embedded charts resource)。
好像有一个feature request in Google’s Issue Tracker。您可以单击白色开始 (☆),以便 Google 知道您希望完成此操作。
解决方法
有 2 种解决方法:在网络上使用 Google Charts 本身(与 WebApps 和模态一起使用),并使用 Google Charts 生成图表,将页面上的 SVG 转换为 PNG 和将其嵌入到电子表格中。生成 PNG 需要制作模态,因此此设置说明适用于两种解决方法。
第 1 步:制作一个使用 Google Charts 制作图表的页面
获取一些模拟数据并制作图表,根据自己的喜好进行设计,并确保一切正常。
第 2 步:使用模式显示它
添加一个名为 Chart
的新 HTML 文件(您可以更改名称,但需要在代码中进行更改)并粘贴您制作的代码。
有了模拟图表后,我们需要使用模式来显示它。我们首先需要在电子表格中添加一个菜单:
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('Chart generator')
.addItem('Create and insert chart', 'showChart')
.addToUi()
}
然后我们添加显示模态的函数:
function showChart() {
const html = HtmlService.createHtmlOutputFromFile('Chart')
.setWidth(900)
.setHeight(600)
SpreadsheetApp.getUi().showModalDialog(html, 'Chart')
}
您还可以使用相同的模板设置 WebApp:
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('Chart')
.setWidth(900)
.setHeight(600)
}
第 3 步:从电子表格中获取数据
现在是删除模拟数据并获取实际数据的时候了。为此,我们将使用 google.script.run
函数异步加载数据。此示例使用异步逻辑,因此它可以并行加载图表库和数据。
google.charts.load('current', {'packages':['corechart']})
const readyPromise = toAsync(resolve => google.charts.setOnLoadCallback(resolve))
const dataPromise = toAsync((resolve, reject) => {
google.script.run
.withSuccessHandler(resolve)
.withFailureHandler(reject)
.getData()
})
toAsync
是一个辅助函数,它确保在出现失败回调未处理的错误时拒绝:
function toAsync(callback) {
return new Promise((resolve, reject) => {
try {
callback(resolve, reject)
} catch(e) {
reject(e)
}
})
}
然后我们需要在 Google Apps 脚本中添加实际从电子表格中读取数据的函数:
function getData() {
return SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('Sheet1')
.getRange('A1:C18')
.getValues()
}
然后在主函数中简单地使用两者:
async function drawVisualization() {
const el = document.getElementById('chart_div')
await readyPromise
const data = google.visualization.arrayToDataTable(await dataPromise)
const options = { … }
new google.visualization.ComboChart(el).draw(data, options)
}
确保调用处理承诺拒绝,否则您可能会在不知不觉中消除错误:
document.addEventListener('DOMContentLoaded', () => drawVisualization().catch(console.error))
(可选)第 4 步:将图表嵌入为 PNG
Google 图表生成 SVG。不幸的是,我们无法嵌入 SVG,因此我们需要将其转换为 PNG。最简单的方法是使用像 canvg
这样的外部库,它允许我们将 SVG 绘制成 canvas。然后我们可以将 canvas 导出为 PNG。
将 canvas 添加到您的 body 并将图书馆添加到您的头上。
然后您可以使用(附加到 drawVisualization
)在 canvas 上绘制:
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
v = canvg.Canvg.fromString(ctx, el.getElementsByTagName('svg')[0].outerHTML)
v.start()
await v.ready()
这将绘制它并等待它完成。
现在我们需要一种将生成的图像发送到 GAS 以便它可以嵌入的方法。值得庆幸的是,我们可以获得 PNG 的 base64 并将其发送到那里:
const base64 = canvas.toDataURL('image/png').split(';base64,')[1]
await toAsync((resolve, reject) => {
google.script.run
.withSuccessHandler(resolve)
.withFailureHandler(reject)
.insertChart(base64)
})
并且在 Google Apps 脚本中,我们定义 insertChart
:
function insertChart(base64png) {
const blob = Utilities.newBlob(
Utilities.base64Decode(base64png, Utilities.Charset.US_ASCII),
'image/png',
'chart.png'
)
SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('Sheet1')
.insertImage(blob, 5, 5, 0, 0)
}
(可选)第 5 步:在生成图表时关闭模态并隐藏图表
既然插入了,我喜欢自动关闭模态框。为此,只需将其附加到 drawVisualization
:
google.script.host.close()
我也喜欢在处理时不显示图表。一点 CSS 就足够了:
canvas, #chart_div {
visibility: hidden;
}
body {
overflow: hidden;
}
您不能使用 display: none
,因为那样会生成错误大小的图表。设置溢出是为了避免滚动条变成空
您还可以将屏幕标题甚至加载动画更改为模态。
参考资料
- Google 工作区中的自定义菜单(Google 开发人员)
- 将 HTML 作为 Google 文档、Sheet、幻灯片或表单用户界面(Google 开发人员)
- HtmlService.createHtmlOutputFromFile(Google 开发人员)
- 作为 Web 应用程序提供 HTML(Google 开发人员)
- google.script.run(Google 开发人员)
- 范围 getValues()(Google 开发人员)
- Utilities.newBlob(数据、内容类型、名称)(Google 开发人员)
- Utilities.base64Decode(已编码,字符集)(Google 开发人员)
- Sheet insertImage(blobSource,列,行)(Google 开发人员)
- google.script.host close() (Google 开发人员)
- Canvas toDataURL (MDN)
- 承诺 (MDN)