javascript - 使用谷歌表格数据的自定义图表
问题描述
我是新手,所以请多多包涵:)
我有一个带有列的谷歌表:'姓名,A-Score,T-Score,R-Score,P-Score'
分数是从 0 到 20 的数值。这些数据需要转换为一个特殊但非常简单的图表,我认为在现有的图表选项中不可用。我试图编写一些代码(即从许多堆栈溢出答案组装)来构建我需要的图形:
问题:
我是否错过了现有图表选项中的一些基本内容,可以让我以这种方式绘制图表?
...如果不是,这可以在带有 google-scripts 或扩展的工作表中完成吗?
我如何才能有效地为几百行创建单独的图表(导出为 png);也许通过某种方式重用我到目前为止的代码。
非常感谢!
//javascript
//data from sheets
var Name = "santayan";
var Activist = 12;
var Theorist = 9;
var Reflector = 14;
var Pragmatist = 12;
//set up canvas
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
//set up click target
var link = document.getElementById("link");
//reset coordinates and white bg
ctx.translate(200, 200);
ctx.beginPath();
ctx.rect(-200, -200, 400, 400);
ctx.fillStyle = "white";
ctx.fill();
//plot main graph
ctx.lineCap = "round";
ctx.lineWidth = 5;
ctx.strokeStyle = "#806";
ctx.beginPath();
ctx.moveTo(Theorist * 10, 0);
ctx.lineTo(0, Reflector * 10);
ctx.lineTo(Activist * -10, 0);
ctx.lineTo(0, Pragmatist * -10);
ctx.closePath();
ctx.stroke();
//plot axes and labels
ctx.strokeStyle = "#d3d3d3";
ctx.lineWidth = 1;
ctx.moveTo(-200, 0);
ctx.lineTo(200, 0);
ctx.moveTo(0, -200);
ctx.lineTo(0, 200);
ctx.stroke();
ctx.font = "1em Helvetica";
ctx.textAlign = "right";
ctx.fillStyle = "#806";
ctx.fillText(Name, 195, -185);
ctx.font = ".5em Helvetica";
ctx.fillText("LEARNING STYLE", 195, -170);
ctx.fillStyle = "#000";
ctx.textAlign = "center";
ctx.fillText("ACTIVIST", -170, 12);
ctx.fillText("THEORIST", 170, -5);
ctx.rotate(Math.PI / 2);
ctx.fillText("PRAGMATIST", -165, 12);
ctx.fillText("REFLECTOR", 170, -5);
//click handler
function downloadImage() {
link.setAttribute("download", Name + " LearningStyle.png");
link.setAttribute(
"href",
canvas.toDataURL("image/png").replace("image/png", "image/octet-stream")
);
}
//html
<div class="container"> <a id="link" OnClick=downloadImage()><canvas id="myCanvas" width="400" height="400" </canvas></a> click on the image to download</div>
//css
a{cursor:pointer}body{font-family:Helvetica,Sans;font-size:.8em;text-align:right;background-color:#888;margin:0}.container{width:440px;height:460px;display:block;background-color:#aaa;margin:0 auto;padding:10px}canvas{box-sizing:border-box;background:#fff;padding:20px;margin:0 auto;border:1px solid grey;border-box:inner}
解决方案
这种类型没有谷歌图表,但你可以用你建议的方法来实现你的目标。
不幸的是,谷歌目前没有此类图表的选项。尽管您的代码看起来画得很好!要使用工作表进行此操作,您需要使用HtmlService来呈现客户端 HTML 和 JavaScript。然后要在客户端和服务器之间进行通信(与您的工作表和驱动器交互的应用程序脚本),您将使用google.script.run...
,请参阅客户端服务器通信。
这是最有效的方法吗?可能不是。然而,这是完全在 Apps Script 中执行此操作的一种相当简洁的方式。
我会用 10 行,然后是 20 行,然后是 50 行等来测试它。以防它被太多的东西淹没。
工作样本
您的 Apps 脚本项目中需要两个文件:
图表.html
<!DOCTYPE html>
<html>
<head>
<style>
a {cursor:pointer;}body{font-family:Helvetica,Sans;font-size:.8em;text-align:right;background-color:#888;margin:0}.container{width:440px;height:460px;display:block;background-color:#aaa;margin:0 auto;padding:10px}canvas{box-sizing:border-box;background:#fff;padding:20px;margin:0 auto;border:1px solid grey;border-box:inner}
</style>
</head>
<body>
<div class="container">
<canvas id="myCanvas" width="400" height="400"></canvas>
</div>
</body>
<script>
// Your drawing code wrapped in a function
function drawChart(Name, Activist, Theorist, Reflector, Pragmatist){
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
//reset coordinates and white bg
ctx.translate(200, 200);
ctx.beginPath();
ctx.rect(-200, -200, 400, 400);
ctx.fillStyle = "white";
ctx.fill();
//plot main graph
ctx.lineCap = "round";
ctx.lineWidth = 5;
ctx.strokeStyle = "#806";
ctx.beginPath();
ctx.moveTo(Theorist * 10, 0);
ctx.lineTo(0, Reflector * 10);
ctx.lineTo(Activist * -10, 0);
ctx.lineTo(0, Pragmatist * -10);
ctx.closePath();
ctx.stroke();
//plot axes and labels
ctx.strokeStyle = "#d3d3d3";
ctx.lineWidth = 1;
ctx.moveTo(-200, 0);
ctx.lineTo(200, 0);
ctx.moveTo(0, -200);
ctx.lineTo(0, 200);
ctx.stroke();
ctx.font = "1em Helvetica";
ctx.textAlign = "right";
ctx.fillStyle = "#806";
ctx.fillText(Name, 195, -185);
ctx.font = ".5em Helvetica";
ctx.fillText("LEARNING STYLE", 195, -170);
ctx.fillStyle = "#000";
ctx.textAlign = "center";
ctx.fillText("ACTIVIST", -170, 12);
ctx.fillText("THEORIST", 170, -5);
ctx.rotate(Math.PI / 2);
ctx.fillText("PRAGMATIST", -165, 12);
ctx.fillText("REFLECTOR", 170, -5);
// Had to add this to reset the canvas properly
ctx.resetTransform();
}
function getImage(Name) {
var canvas = document.getElementById("myCanvas");
var dataURL = canvas.toDataURL("image/png");
return dataURL;
}
function notification(msg){
let message = document.createElement("p");
message.textContent = msg
document.body.appendChild(message)
}
function main(data){
// data is 2D array
data.forEach(row => {
drawChart(row[0], row[1], row[2], row[3], row[4]);
let png = getImage();
google.script.run.withSuccessHandler(notification).saveToDrive(row[0], png)
})
}
google.script.run.withSuccessHandler(main).getData();
</script>
</html>
代码.gs
function getData() {
let file = SpreadsheetApp.getActive();
let sheet = file.getSheetByName("Sheet1");
let range = sheet.getDataRange();
let values = range.getValues();
// Get rid of headers
values.shift()
return values;
}
function saveToDrive(name, dataURL){
// https://stackoverflow.com/questions/56092146/convert-data-uri-using-google-apps-script-blob
var type = (dataURL.split(";")[0]).replace('data:','');
var imageUpload = Utilities.base64Decode(dataURL.split(",")[1]);
var blob = Utilities.newBlob(imageUpload, type, name + ".png");
let newFile = DriveApp.createFile(blob);
newFile.setName(name)
return name + "'s chart saved!"
}
function main(){
let html = HtmlService.createHtmlOutputFromFile("chart.html");
SpreadsheetApp.getUi().showSidebar(html);
}
电子表格如下所示:
脚本的操作顺序
- 通过运行并授权来
main
启动脚本。Code.gs
- 创建一个 HTML 输出,使用客户端 JS 完成,如上所示。
- 在工作表的侧边栏中加载该 HTML
SpreadsheetApp.getUi().showSidebar(html);
- 然后,客户端 HTML 向主 Apps 脚本 (
google.script.run
) 发送一个异步请求,以从电子表格中获取所有数据,并以二维数组的形式接收这些数据。 - 一个数据返回,客户端 JS 将遍历每一行,绘制图表,将其保存为 dataURL 字符串,然后向 Apps Script 发送另一个异步请求,将 dataURL 转换为 png blob,将其保存在驱动器中,并返回一条消息说它已完成。
笔记
- 尝试将其从客户端作为 blob 发送,但我遇到了奇怪的错误,因此默认使用 dataURL。
- 必须添加
ctx.resetTransform();
并结束绘图功能才能正确重置 ctx。 - 列的索引号是硬编码的,因此请注意,只有当您的电子表格格式完全相同时,此脚本才能按原样工作。
结果
出现侧栏和图表。对于这么少的图纸,我只看到它从白色到最终图表。之后,在图表下方,开始出现完成消息:
然后,如果您转到主驱动器文件夹,您应该会看到 PNG 文件!
参考
推荐阅读
- ios - Alamofire 5 AF.upload() 无法将图像发送到具有无效证书的服务器
- python - 在给定特定值的情况下比较两个熊猫系列元素
- mysql - 从远程网络连接到 MySQL 服务器 8.0 (windows 10)
- pdf - 将 PDF 的 0.00pt 行更改为更大的尺寸
- python - 如何从客户端更改 python 中的服务器目录?
- javascript - 如何在电子中单击按钮时打开第二个窗口
- javascript - 有没有办法清除输入自动完成的缓存历史记录
- azure - Azure - 发布 Web API - 编译
- .net - 如何从多个解决方案/项目中删除 nuget 包?
- r - R Shiny 应用程序不会上传文件或显示绘图