简体   繁体   English

使用谷歌表格数据的自定义图表

[英]custom chart using google sheets data

I'm new to this, so please bear with me:)我是新手,所以请多多包涵:)

I have a google sheet with columns: 'Name, A-Score,T-Score, R-Score, P-Score'我有一个带有列的谷歌表:'姓名,A-Score,T-Score,R-Score,P-Score'

Scores are numerical values from 0 to 20. This data needs to be converted to a special, but very simple graph which i don't think is available in the existing sheets charting options.分数是从 0 到 20 的数值。这些数据需要转换为一个特殊但非常简单的图表,我认为在现有的图表选项中不可用。 I've tried to write some code (ie assembled from many stack overflow answers) to construct the graph i need:我试图编写一些代码(即从许多堆栈溢出答案组装)来构建我需要的图形:

myLearningStyleDiagram我的学习风格图

myCodePenDraft myCodePenDraft

Question:问题:

  1. Have i missed something basic in the existing chart options that would let me graph this way?我是否错过了现有图表选项中的一些基本内容,可以让我以这种方式绘制图表?

    ...if not, is this possible to do in sheets with google-scripts or extensions? ...如果不是,这可以在带有 google-scripts 或扩展的工作表中完成吗?

  2. How could i go about efficiently creating individual charts (export to pngs) for a few hundred rows;我怎么能有效地为几百行创建单独的图表(导出到 png)? perhaps by somehow reusing the code i've got so far.也许通过某种方式重用我到目前为止的代码。

Thanks so much!非常感谢!

//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}

There is no Google Chart for this type, but you can achieve your goal with the method you suggested.这种类型没有谷歌图表,但你可以用你建议的方法来实现你的目标。

Unfortunately there is no option for this type of chart in Google at the moment.不幸的是,谷歌目前没有此类图表的选项。 Though your code looks like it draws it fine!尽管您的代码看起来画得很好! To get this working with a sheet you would need to use the HtmlService to render client side HTML and JavaScript.要使用工作表进行此操作,您需要使用HtmlService来呈现客户端 HTML 和 JavaScript。 Then to communicate between the client and server (Apps Script to interface with your sheet and drive), you would use google.script.run... , see Client Server Communications .然后要在客户端和服务器之间进行通信(应用脚本与您的工作表和驱动器交互),您将使用google.script.run... ,请参阅客户端服务器通信

Is this the most efficient way?这是最有效的方法吗? Probably not.可能不是。 Yet this is a reasonably concise way of doing it totally within Apps Script.然而,这是完全在 Apps Script 中执行此操作的一种相当简洁的方式。

I would test this with 10 rows, then 20, then 50 etc. In case it gets overwhelmed with too many.我会用 10 行,然后是 20 行,然后是 50 行等来测试它。以防它被太多的东西淹没。

Working Sample工作样本

You need two files in your Apps Script project:您的 Apps 脚本项目中需要两个文件:

chart.html图.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>

Code.gs代码.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);
}

Spreadsheet looks like this:电子表格如下所示:

在此处输入图像描述

Order of operations for script脚本的操作顺序

  1. Launch script by running main from Code.gs and authorize it.通过从Code.gs运行main来启动脚本并对其进行授权。
  2. Create an HTML output, complete with the client side JS as shown above.创建一个 HTML output,如上图所示使用客户端 JS 完成。
  3. Load that HTML in the sheet's sidebar SpreadsheetApp.getUi().showSidebar(html);在工作表的侧边栏中加载 HTML SpreadsheetApp.getUi().showSidebar(html);
  4. The client-side HTML then sends an asynchronous request to the main Apps Script ( google.script.run ) to get all the data from the spreadsheet, which it will receive as a two dimensional array.客户端 HTML 然后向主 Apps 脚本 ( google.script.run ) 发送异步请求,以从电子表格中获取所有数据,它将以二维数组的形式接收。
  5. One the data makes it back, client-side JS will go through each row, draw the chart, save it as a dataURL string, and sends another asynchronous request to Apps Script to convert the dataURL into a png blob, saving it in Drive, and returning a message saying that it completed.数据返回后,客户端JS将go遍历每一行,绘制图表,将其保存为dataURL字符串,并向Apps Script发送另一个异步请求,将dataURL转换为png blob,将其保存在Drive中,并返回一条消息说它已完成。

Notes笔记

  • Tried to send it from the client as a blob already, but I was getting strange errors and so defaulted to using the dataURL.尝试将其从客户端作为 blob 发送,但我遇到了奇怪的错误,因此默认使用 dataURL。
  • Had to add in ctx.resetTransform();必须添加ctx.resetTransform(); and the end of the drawing function to reset the ctx properly.并在绘图 function 的末尾正确重置 ctx。
  • The index numbers for the columns are hard-coded, so please be aware that this script will only work as-is if your spreadsheet is in exactly the same format.列的索引号是硬编码的,因此请注意,只有当您的电子表格格式完全相同时,此脚本才能按原样工作。

Result结果

The side bar appears and a chart.出现侧栏和图表。 For so few drawings, I only saw it go from white to the final chart.这么少的图纸,我只看到了从白色到最终图的go。 Afterwards, below the chart, the completion messages start to appear:之后,在图表下方,开始出现完成消息:

在此处输入图像描述

Then if you go to your main Drive folder, you should see the PNG files!然后,如果您将 go 到您的主驱动器文件夹,您应该会看到 PNG 文件!

References参考

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM