I have one download button and table that store user data in user.component.html file and when user clicks on the download button then it exports all the table's data into an Excel file.
I want to display a loading spinner when the download takes longer than 1.5 seconds to start.
I am using angular 8.
user.component.html file:
<div class ="container">
<button (click)="generateExcel()">
Generate Excel</button>
<table>
-----table related data
<\table>
</div>
user.component.ts file:
generateExcel() {
//Excel Title, Header, Data
const title = 'Car buyers Report';
const header = ["Year", "Month", "User", "Model"]
const data = [
[2007, 1, "jo", "Volkswagen Passat"],
[2007, 1, "mike ", "Toyota Rav4"],
[2007, 1, "david", "Toyota Avensis"],
[2007, 1, "milenda ", "Volkswagen Gol"]
];
//Create workbook and worksheet
let workbook = new Workbook();
let worksheet = workbook.addWorksheet('Car Data');
//Add Row and formatting
let titleRow = worksheet.addRow([title]);
titleRow.font = { name: 'Comic Sans MS', family: 4, size: 16, underline: 'double', bold: true }
worksheet.addRow([]);
let subTitleRow = worksheet.addRow(['Date : ' + this.datePipe.transform(new Date(), 'medium')])
//Add Image
let logo = workbook.addImage({
base64: logoFile.logoBase64,
extension: 'png',
});
worksheet.addImage(logo, 'E1:F3');
worksheet.mergeCells('A1:D2');
//Blank Row
worksheet.addRow([]);
//Add Header Row
let headerRow = worksheet.addRow(header);
// Cell Style : Fill and Border
headerRow.eachCell((cell, number) => {
cell.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFFFFF00' },
bgColor: { argb: 'FF0000FF' }
}
cell.border = { top: { style: 'thin' }, left: { style: 'thin' }, bottom: { style: 'thin' }, right: { style: 'thin' } }
})
// worksheet.addRows(data);
// Add Data and Conditional Formatting
data.forEach(d => {
let row = worksheet.addRow(d);
let qty = row.getCell(5);
let color = 'FF99FF99';
if (+qty.value < 500) {
color = 'FF9999'
}
qty.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: color }
};
});
worksheet.getColumn(3).width = 30;
worksheet.getColumn(4).width = 30;
worksheet.addRow([]);
//Footer Row
let footerRow = worksheet.addRow(['This is system generated excel sheet.']);
footerRow.getCell(1).fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFCCFFE5' }
};
footerRow.getCell(1).border = { top: { style: 'thin' }, left: { style: 'thin' }, bottom: { style: 'thin' }, right: { style: 'thin' } }
//Merge Cells
worksheet.mergeCells(`A${footerRow.number}:F${footerRow.number}`);
//Generate Excel File with given name
workbook.xlsx.writeBuffer().then((data) => {
let blob = new Blob([data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
fs.saveAs(blob, 'CarData.xlsx');
})
}
I imagine your writeBuffer call is what takes you the most time.
As writeBuffer is asynchronous, you could use rxjs observables which allow you to have more complex behaviors than a classic async/await.
First convert your promise to an observable :
// here you have a promise
const wBufferPromise = workbook.xlsx.writeBuffer();
// and here you have an observable, hence the $ char in the variable name
const wBufferObservable = from(wBufferPromise );
You can then probably user timeoutWith from RxJS (which i never used so I won't be able to help you here.
Another possible solution would be to call setTimeout(myFunc,1500) where myFunc sets your spinner visibility if needed.
Edit :
Please have a look at Eliseo's comment.
Related
uplot is used to dislay timeseries data from VictoriaMetrics database.
For the backend Node-Red is used to forward and recieve the query with node-red-contrib-uibuilder.
It works basically and is very fast.
The problem is, when I try to zoom into the uplot graph, my browser (Chrome, Firefox, Edge) freezes. It seems to run out of memory.
Here are parts of my code, using svelte.
<script>
import { onMount } from "svelte";
import { query } from "../lib/uibStore";
import { transformToUplot } from "../lib/helper";
// import uPlot from "uplot";
import Browsebar from "../components/Browsebar.svelte";
import TimerangeSelect from "../components/TimerangeSelect.svelte";
let uplotdiv; //
let opts = {
title: "Temperaturen1",
id: "chart1",
class: "my-chart",
width: 1000,
height: 600,
series: [
{},
{
show: true, // initial toggled state (optional)
spanGaps: true,
label: "RT",
stroke: "red", // series style
scale: "Temperature",
value: (self, rawValue) => rawValue.toFixed(1) + "°C",
},
{
show: true,
spanGaps: true,
label: "KT",
stroke: "green",
scale: "Temperature",
value: (self, rawValue) => rawValue.toFixed(1) + "°C",
},
{
show: true,
spanGaps: true,
label: "VT",
stroke: "blue",
scale: "Temperature",
value: (self, rawValue) => rawValue.toFixed(1) + "°C",
},
],
scales: {
x: { time: true },
Temperature: {
auto: true,
// range: [-10, 20],
side: 3,
},
},
axes: [
{},
{
scale: "Temperature",
values: (self, ticks) => ticks.map((rawValue) => rawValue.toFixed(1) + "°C"),
},
],
cursor: { drag: { x: true, y: true } },
};
let plot; // = new uPlot(opts);
let uPlot;
let d = [[0], [0], [0], [0]];
let resolved = false;
$: uisend($query); //use uibilder.send, if query changes which occurs when timerange or nav index changes
//send a victoriametrics query to the backend, _q is part of query
function uisend(_q) {
// Example 'uvr_prozess_celsius{ort="1"}&start=-3d&step=60s'
uibuilder.send({ topic: "getVMetrics", payload: _q });
}
onMount(async () => {
uisend($query);
const uplotModule = await import("https://unpkg.com/uplot#1.6.22/dist/uPlot.esm.js");
uPlot = uplotModule.default;
plot = new uPlot(opts, [[0], [0], [0], [0]], uplotdiv);
});
uibuilder.onChange("msg", function (msg) {
// load Metrics via Node-Red's uibuilder, serverside
if (msg.topic === "getVMetrics") {
resolved = true;
if (msg.payload.data.result.length > 0) {
d = transformToUplot(msg.payload.data);
plot.setData(d);
}
}
});
</script>
<svelte:head>
<link rel="stylesheet" href="https://unpkg.com/uplot#1.6.22/dist/uPlot.min.css" />
</svelte:head>
<Browsebar>
<TimerangeSelect />
</Browsebar>
<hr />
<div bind:this={uplotdiv} />
{#if resolved}
<code>{$query}</code>
{:else}
<h4>lade Metriken... {$query}</h4>
{/if}
<hr />
Has anyone experienced freezing with uplot? What did you do?
Lucky me, I found the problem. It had to do with the way I transformed the victoriametrics data. On every timestamp I did Number(timestamp).toFixed(0). Without toFixed(0) it is working now. :)
//transform raw data from metrics query to the uplot format
export function transformToUplot(dt) {
let udata = []; //2d data array, conforming uPlot
let tsd = []; //timestamp array
//from first result take only the timestamps
for (let t of dt.result[0].values) {
// tsd.push(Number(t[0]).toFixed(0)); //this was bad!!!!, it lead to freezing
tsd.push(Number(t[0]));
}
udata.push(tsd);
//then the values
for (let r of dt.result) {
let sd = [];
for (let d of r.values) {
let val = Number(d[1]);
sd.push(val);
}
udata.push(sd);
}
return udata;
}
Thanks for your interest!
hi i want charting stock data in web page.
i found sample project in github
https://github.com/tvjsx/tvjs-xp
i change code and connect the binance and receive and charting real time data.
i have some problem after add online receive data chart lagend bouttun not work and i cant add layer.
please help me.
thanks
<trading-vue :data="dc" :width="this.width" :height="this.height"
title-txt="TVJS XP" :key="resetkey"
:chart-config="{DEFAULT_LEN:70}"
ref="tvjs"
:legend-buttons="['display', 'settings', 'up', 'down', 'add', 'remove']"
:toolbar="true"
:index-based="index_based"
:color-back="colors.colorBack"
:color-grid="colors.colorGrid"
:color-text="colors.colorText"
:extensions="ext"
:overlays="ovs"
:x-settings="xsett">
</trading-vue>
<span class="gc-mode">
<input type="checkbox" v-model="index_based">
<label>Index Based</label>
</span>
export default {
name: 'DataHelper',
icon: '⚡',
description: 'Real-time updates. Play with DataCube in the console',
props: ['night', 'ext', 'resetkey'],
components: {
TradingVue
},
mounted() {
window.addEventListener('resize', this.onResize)
this.onResize()
// Load the last data chunk & init DataCube:
let now = Utils.now()
this.load_chunk([now - Const.HOUR4, now]).then(data => {
this.dc = new DataCube({
ohlcv: data['dc.data'],
// onchart: [{
// type: 'EMAx6',
// name: 'Multiple EMA',
// data: []
// }],
offchart: [
// {
// type: 'BuySellBalance',
// name: 'Buy/Sell Balance, $lookback',
// data: [],
// settings: {}
// },
{
name: "RSI, 20",
type: "Range",
data: [],
settings: {
"upper": 70,
"lower": 30,
"backColor": "#9b9ba316",
"bandColor": "#666"
}
},
],
datasets: [{
type: 'Trades',
id: 'binance-btcusdt',
data: []
}]
}, { aggregation: 100 })
// Register onrange callback & And a stream of trades
this.dc.onrange(this.load_chunk)
this.$refs.tvjs.resetChart()
this.stream = new Stream(WSS)
this.stream.ontrades = this.on_trades
window.dc = this.dc // Debug
window.tv = this.$refs.tvjs // Debug
})
},
methods: {
onResize(event) {
this.width = window.innerWidth
this.height = window.innerHeight - 50
},
// New data handler. Should return Promise, or
// use callback: load_chunk(range, tf, callback)
async load_chunk(range) {
let [t1, t2] = range
let x = 'BTCUSDT'
let q = `${x}&interval=1m&startTime=${t1}&endTime=${t2}`
let r = await fetch(URL + q).then(r => r.json())
return this.format(this.parse_binance(r))
},
// Parse a specific exchange format
parse_binance(data) {
if (!Array.isArray(data)) return []
return data.map(x => {
for (var i = 0; i < x.length; i++) {
x[i] = parseFloat(x[i])
}
return x.slice(0,6)
})
},
format(data) {
// Each query sets data to a corresponding overlay
return {
'dc.data': data
// other onchart/offchart overlays can be added here,
// but we are using Script Engine to calculate some:
// see EMAx6 & BuySellBalance
}
},
on_trades(trade) {
this.dc.update({
t: trade.T, // Exchange time (optional)
price: parseFloat(trade.p), // Trade price
volume: parseFloat(trade.q), // Trade amount
'datasets.binance-btcusdt': [ // Update dataset
trade.T,
trade.m ? 0 : 1, // Sell or Buy
parseFloat(trade.q),
parseFloat(trade.p)
],
// ... other onchart/offchart updates
})
}
},
beforeDestroy() {
window.removeEventListener('resize', this.onResize)
if (this.stream) this.stream.off()
},
computed: {
colors() {
return this.$props.night ? {} : {
colorBack: '#fff',
colorGrid: '#eee',
colorText: '#333'
}
},
},
data() {
return {
dc: {},
width: window.innerWidth,
height: window.innerHeight,
index_based: false,
xsett: {
'grid-resize': { min_height: 30 }
},
ovs: Object.values(Overlays),
}
}
}
I want to put thick border in all my cells. this is an angular project, I am using typescript.
I can do this for 1 cell,
worksheet.getCell('A1').border = {
top: { style: 'thick' },
left: { style: 'thick' },
bottom: { style: 'thick' },
right: { style: 'thick' }
};
But I want to do something like 2 nested for loops . For each row , make each cell thick
Here is I tried : app.component.ts
import { Component, OnInit } from '#angular/core';
import { DataService } from '../data.service';
import * as jspdf from 'jspdf';
import html2canvas from 'html2canvas';
// import * as XLSX from 'xlsx';
import * as ExcelJS from 'exceljs';
import * as FileSaver from 'file-saver';
import { ViewChild, ElementRef } from '#angular/core';
#Component({
selector: 'app-items-report',
templateUrl: './items-report.component.html',
styleUrls: ['./items-report.component.css']
})
export class ItemsReportComponent implements OnInit {
purchases: any;
constructor(private dataService: DataService) {
this.GetPurchases();
}
ngOnInit(): void {
}
async GetPurchases() {
const response = await this.dataService.GetPurchases();
const dataService = await response.json();
this.purchases = dataService;
}
downloadPDF() {
const data = document.getElementById('purchaseTable'); // Id of the table
html2canvas(data).then(canvas => {
// Few necessary setting options
const imgWidth = 208;
const pageHeight = 295;
const imgHeight = canvas.height * imgWidth / canvas.width;
const heightLeft = imgHeight;
const contentDataURL = canvas.toDataURL('image/png');
// Your 1st parameter (landscape [l] or portrait [p]) determines what becomes the width and the height.
const pdf = new jspdf('p', 'mm', 'a4'); // A4 size page of PDF
const position = 0;
/* addImage explained below:
param 1 -> image in code format
param 2 -> type of the image. SVG not supported. needs to be either PNG or JPEG.
all params are specified in integer
param 3 -> X axis margin from left
param 4 -> Y axis margin from top
param 5 -> width of the image
param 6 -> height of the image
*/
// pdf.addImage(contentDataURL, 'PNG', 0, position, imgWidth, imgHeight);
// pdf.addImage(contentDataURL, 'PNG', 18, 30, imgWidth - 17, imgHeight);
pdf.addImage(contentDataURL, 'PNG', 18, 30, imgWidth - 21, imgHeight);
pdf.save('MYPdf.pdf'); // Generated PDF
});
}
downloadExcel() {
const date = new Date().toISOString().slice(0, 10).split('-').reverse().join('/');
console.log(date);
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('My Sheet');
worksheet.columns = [
{ header: 'Id', key: 'id', width: 10},
{ header: 'Name', key: 'name', width: 32 },
{ header: 'Quantity', key: 'quantity', width: 15 },
{ header: 'Rate', key: 'rate', width: 15 },
{ header: 'Date', key: 'date', width: 15 },
{ header: 'Total', key: 'total', width: 15 }
];
for (const purchase of this.purchases) {
worksheet.addRow({
id: purchase.item_id ,
date: purchase.item_purchase_date.toString().slice(0, 10).split('-').reverse().join('/'),
name: purchase.item_name,
quantity: purchase.item_quantity,
rate: purchase.item_rate,
total: purchase.item_rate * purchase.item_quantity
})
.alignment = { horizontal: 'left' };
}
worksheet.getRow(1).font = { bold: true };
// Iterate over all rows (including empty rows) in a worksheet
worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => {
console.log('Row ' + rowNumber + ' = ' + JSON.stringify(row.values));
row.eachCell({ includeEmpty: true }, (cell, rowNumber) => {
// ...please make my cell thick here
// i cant no longer write a1 or b1
// i need to access all cells - including empty cells
});
});
book.xlsx.readFile('export.xlsx');
}
I need to make each of my cells thick, inside for loop. So please help me how to access each cell in a loop without writing a1 or b1
Worksheet gives you a columns property on which you can iterate and use it like :-
worksheet.columns.forEach(column => {
column.border = {
top: { style: "thick" },
left: { style: "thick" },
bottom: { style: "thick" },
right: { style: "thick" }
};
});
To put border in all cells :-
exceljs version 1.12.0
worksheet.columns.forEach((col) => {
col.style.font = { name: 'Comic Sans MS' };
col.style.border = { top: { style: 'thin' }, left: { style: 'thin' }, bottom: { style: 'thin' }, right: { style: 'thin' } };
})
I am developing a small dashboard in ASP.NET and with the help of C# and I am presenting a problem by generating a stacked horizontal bar graph properly.
I am using the chart.js library
Library chart.js
I enclose an example image of what I want to do I have the data of some technicians who were assigned a certain amount of tickets, which according to the image correspond to the Y axis of the graph A, B, C, D represent each technician and the datasets they represent the state in which it is, what I want to obtain in the graph is the amount of tickets that each technician has for his state.
Example image:
Error:
Kinda complicated to explain, I am doing the expected horizontal bar graph as I indicated in the previous example but I have not been able to see the datasets and their colors correctly.
What I have achieved so far is to see the technicians with the amount of tickets that each one has, but the dataset that I represent with the state at the bottom of the graph is repeated, in addition to ASIGNADO I have other states and each dataset that is each state has to be represented by a color.
The following is the table where I am getting the information I want to show, where TK_HD_TICKETS_ID are the tickets that are registered and where I want to get the amount, in TK_CT_STATUS_ID which the status of the ticket is stored and in TK_BT_EMPLOYEES_ID is the technician who has that ticket
TK_DT_RECORDS
Where TK_HD_TICKETS_ID are the tickets that are registered and where do I want to get the amount, in TK_CT_STATUS_ID which the state of the ticket is stored and in TK_BT_EMPLOYEES_ID is the technician who has that ticket
The following is the query with which I am obtaining the data so far
DashboardModel.cs
public class DashboardResult : Result
{
public List<TicketsDashboardAux> DashboardTicketList { set; get; }
/// <summary>
/// Object with the results for the reports
/// </summary>
public DashboardResult()
{
DashboardTicketList = new List<TicketsDashboardAux>();
}
}
/// <summary>
/// Auxiliary Object to obtain the consultation for the basic report
/// </summary>
public class TicketsDashboardAux
{
public string TicketsAsignedTo { set; get; }
public int TicketsCount { set; get; }
public string TicketsClasificationType { set; get; }
}
public class DashboardModel
{
/// <summary>
/// Query for ticket board by employee status
/// </summary>
/// <param name="refreshType"></param>
/// <param name="area"></param>
/// <returns></returns>
public static DashboardResult GetEmployeeByStatus(string refreshType, string area)
{
var result = new DashboardResult();
using (var db = new dbGoldenTicket())
{
var subQuery =
from tblTickets in db.TK_HD_TICKETS
join tblRecords in db.TK_DT_RECORDS on tblTickets.TK_HD_TICKETS_ID equals tblRecords
.TK_HD_TICKETS_ID
join tblStatus in db.TK_CT_STATUS on tblRecords.TK_CT_STATUS_ID equals tblStatus.
TK_CT_STATUS_ID
join tblEmployee in db.TK_BT_EMPLOYEES on tblRecords.TK_BT_EMPLOYEES_ID equals tblEmployee
.TK_BT_EMPLOYEES_ID into tempEmplo
from tblEmployee in tempEmplo.DefaultIfEmpty()
where crationDateTickets.Contains(tblTickets.TK_HD_TICKETS_ID)
&& tblRecords.TK_DT_RECORDS_ID == (
from tblTicketAux in db.TK_HD_TICKETS
join tblRecordAux in db.TK_DT_RECORDS on tblTicketAux.TK_HD_TICKETS_ID equals tblRecordAux
.TK_HD_TICKETS_ID
where tblTickets.TK_HD_TICKETS_ID == tblTicketAux.TK_HD_TICKETS_ID
select tblRecordAux.TK_DT_RECORDS_ID
).Max()
select new
{
tblRecords.TK_HD_TICKETS_ID,
tblEmployee.FULLNAME,
tblStatus.NAME,
};
var queryTicketsList = (from subquery in subQuery
group subquery by new { subquery.FULLNAME, subquery.NAME }
into grp
select new TicketsDashboardAux()
{
TicketsAsignedTo = grp.Key.FULLNAME,
TicketsClasificationType = grp.Key.NAME,
TicketsCount = grp.Count()
}).ToList();
foreach (TicketsDashboardAux rowAux in queryTicketsList)
{
rowAux.TicketsAsignedTo = rowAux.TicketsAsignedTo.IsEmpty() ? "Sin asignar" : rowAux.TicketsAsignedTo;
result.DashboardTicketList.Add(rowAux);
}
result.Success = true;
result.Message = "op_exitosa";
}
return result;
}
The following is the Javascript function with which I will load the data in the graph
function loadEmployeesChart() {
document.getElementById("chart-employee").remove();
let auxCanvasEmployee = document.createElement('canvas');
auxCanvasEmployee.setAttribute('id', 'chart-employee');
auxCanvasEmployee.setAttribute('style', 'width: 720px; height: 600px');
document.querySelector('#chartEmployeeContainer').appendChild(auxCanvasEmployee);
var canvas = document.getElementById("chart-employee");
var ctx = canvas.getContext("2d");
var dataEmployee;
var myNewChart;
$.ajax({
url: document.getElementById("employeeChart").value,
type: "POST",
dataType: "json",
data: {
refreshType: document.getElementById("dataOption").value
},
success: function (data) {
var dataChart = [];
var label = [];
var datalabels = [];
var stacks = []
for (let idx in data.DashboardTicketList) {
if (data.DashboardTicketList.hasOwnProperty(idx)) {
dataChart.push(data.DashboardTicketList[idx].TicketsCount);
label.push(data.DashboardTicketList[idx].TicketsAsignedTo);
datalabels.push(data.DashboardTicketList[idx].TicketsClasificationType);
}
}
var count = false;
for (let idx in dataChart) {
if (dataChart[idx] > 0) {
count = true;
break;
}
}
if (count) {
document.getElementById('noDataEmployee').style.display = 'none';
} else {
document.getElementById('noDataEmployee').style.display = 'block';
}
dataEmployee = {
labels: label,
datasets: [{
label: datalabels,
data: dataChart,
}],
};
myNewChart = new Chart(ctx, {
type: 'horizontalBar',
data: dataEmployee,
options: {
maintainAspectRatio: false,
scales: {
xAxes: [{
stacked: true // this should be set to make the bars stacked
}],
yAxes: [{
stacked: true // this also..
}]
},
legend: {
position: 'bottom',
padding: 5,
labels:
{
pointStyle: 'circle',
usePointStyle: true
}
}
},
});
}, error: function () {
}
});
}
I hope I understood your question and your data strucure (as I said in my comment to your question).
Bringing your data structure to the one chart.js is expecting is not so easy. That's why my code looks very difficult. That's why I put a few comments in there and I let all the console.logs in there so you can easily see what is happening.
Feel free to ask any questions you have. I'm sure it takes some time to understand all.
Complete code in the JSBin
let canvas = document.getElementById("chart");
let ctx = canvas.getContext("2d");
let data = {}
data.DashboardTicketList = {
0: {
TicketsAssignedTo: 'Tim',
TicketsClassificationType: 'TERMINADO',
TicketsCount: 1,
},
1: {
TicketsAssignedTo: 'Tim',
TicketsClassificationType: 'ASIGNADO',
TicketsCount: 7
},
2: {
TicketsAssignedTo: 'Tim',
TicketsClassificationType: 'CERRADO',
TicketsCount: 5
},
3: {
TicketsAssignedTo: 'Melanie',
TicketsClassificationType: 'ASIGNADO',
TicketsCount: 7
},
4: {
TicketsAssignedTo: 'Melanie',
TicketsClassificationType: 'CERRADO',
TicketsCount: 7
},
5: {
TicketsAssignedTo: 'Steffen',
TicketsClassificationType: 'TERMINADO',
TicketsCount: 0
},
6: {
TicketsAssignedTo: 'Steffen',
TicketsClassificationType: 'ASIGNADO',
TicketsCount: 10
},
7: {
TicketsAssignedTo: 'Steffen',
TicketsClassificationType: 'CERRADO',
TicketsCount: 7
},
8: {
TicketsAssignedTo: 'Talia',
TicketsClassificationType: 'TERMINADO',
TicketsCount: 5
},
9: {
TicketsAssignedTo: 'Talia',
TicketsClassificationType: 'ASIGNADO',
TicketsCount: 7
},
10: {
TicketsAssignedTo: 'Talia',
TicketsClassificationType: 'EN ESPERA USUARIO',
TicketsCount: 6
}
}
const status = [
'ABIERTO',
'ASIGNADO',
'EN PROCESO',
'EN ESPERA USUARIO',
'TERMINADO',
'CERRADO'
]
const colors = {
'ASIGNADO': '#F7A65C',
'ABIERTO': '#F76363',
'CERRADO': '#6CE5CE',
'TERMINADO': '#4285f4',
'EN PROCESO': '#F2CB5F',
'EN ESPERA USUARIO': '#B283ED'
}
let peopleData = {}
let classificationData = {}
let chartData = {
labels: [],
datasets: []
}
// loop through complete data
for (let idx in data.DashboardTicketList) {
let cData = data.DashboardTicketList[idx]
//console.log(cData)
// change data structure to all people
if (!peopleData.hasOwnProperty(cData.TicketsAssignedTo)) {
peopleData[cData.TicketsAssignedTo] = {}
}
peopleData[cData.TicketsAssignedTo][cData.TicketsClassificationType] = cData.TicketsCount
// Get all different TicketsClassificationTypes (object to eliminate duplicates)
if (!classificationData.hasOwnProperty(cData.TicketsClassificationType)) {
classificationData[cData.TicketsClassificationType] = true
}
}
// Get array of all different TicketsClassificationTypes
let classificationDataArray = Object.keys(classificationData)
//console.log('classData', classificationData)
//console.log('classDataArray', classificationDataArray)
//console.log('peopleData', peopleData)
// Assign 0 to all people with no specific TicketsClassificationType; may be improved
for (let idx in peopleData) {
let cPerson = peopleData[idx]
for (let i = 0; i < classificationDataArray.length; i++) {
if (!cPerson.hasOwnProperty(classificationDataArray[i])) {
cPerson[classificationDataArray[i]] = 0
}
}
}
// Get chart labels from peopleData
chartData.labels = Object.keys(peopleData)
// Sort TicketsClassificationType to order from status array; may be improved
for (let i = 0; i < status.length; i++) {
for (let j = 0; j < classificationDataArray.length; j++) {
if (status[i] === classificationDataArray[j]) {
let cClass = classificationDataArray[j]
//console.log('cClass', cClass)
let cData = []
for (let idx2 in peopleData) {
//console.log('peopleData[idx2]', peopleData[idx2])
cData.push(peopleData[idx2][cClass])
}
chartData.datasets.push({
label: cClass,
data: cData,
backgroundColor: colors[cClass]
})
break
}
}
}
/*
let count = false;
for (let idx in dataChart) {
if (dataChart[idx] > 0) {
count = true;
break;
}
}
if (count) {
document.getElementById('noDataEmployee').style.display = 'none';
} else {
document.getElementById('noDataEmployee').style.display = 'block';
}
*/
let options = {
responsive: true,
//maintainAspectRatio: false,
scales: {
xAxes: [{
stacked: true,
ticks: {
beginAtZero: true
}
}],
yAxes: [{
stacked: true,
ticks: {
beginAtZero: true
}
}]
},
legend: {
position: 'bottom',
padding: 5,
labels: {
pointStyle: 'circle',
usePointStyle: true
}
}
}
let myNewChart = new Chart(ctx, {
type: 'horizontalBar',
data: chartData,
options: options,
});
I am working with the google slides API and attempting to make a slide based on user inputted text. This is my text creating function,
var num = 1;
function createSlide(auth) {
//AUTHENTICATION
const slides = google.slides({version: 'v1', auth});
//CHANGING VARS
var slideId = 'slide_' + num;
var pageId = slideId;;
var textId = 'text_box_' + num;
var elementId = textId;
var iIndex = num;
//SIZING
var pt350 = {
magnitude: 350,
unit: 'PT',
};
//ALL REQUESTS GO IN requests
var requests = [{
createSlide: {
insertionIndex: iIndex,
objectId: pageId,
slideLayoutReference: {
predefinedLayout: 'BLANK'
}
},
//CREATE THE TEXTBOX
createShape: {
objectId: elementId,
shapeType: 'TEXT_BOX',
elementProperties: {
pageObjectId: pageId,
size: {
height: pt350,
width: pt350,
},
transform: {
scaleX: 1,
scaleY: 1,
translateX: 350,
translateY: 100,
unit: 'PT',
},
},
},
},
//INSERT TEXT
{
insertText: {
objectId: elementId,
insertionIndex: iIndex,
text: txt,
},
}];
//BATCH UPDATE
return slides.presentations.batchUpdate({
presentationId,
resource: {
requests,
},
}, (err, res) => {
if (err) {
error(err);
}else{
console.log('Success');
//INCREASES COUNTER BY 1
num = num + 1;
//ASKS IF A NEW SLIDE WANTS TO BE CREATED
askYOrN ();}});}
And it produces this error:
Error: Invalid value at 'requests[0]' (oneof), oneof field 'kind' is already set. Cannot set 'createShape'
The text is inputted and stored correctly. Does anyone have a solution? Thanks in advance.
How about this modification?
Modification points:
Put createSlide, createShape and insertText to each element in the array of requests.
insertionIndex at insertText starts from 0.
Modified script:
Please modify requests as follows.
var requests = [
{
createSlide: {
insertionIndex: iIndex,
objectId: pageId,
slideLayoutReference: {
predefinedLayout: 'BLANK',
},
},
},
{
//CREATE THE TEXTBOX
createShape: {
objectId: elementId,
shapeType: 'TEXT_BOX',
elementProperties: {
pageObjectId: pageId,
size: {
height: pt350,
width: pt350,
},
transform: {
scaleX: 1,
scaleY: 1,
translateX: 350,
translateY: 100,
unit: 'PT',
},
},
},
},
{
//INSERT TEXT
insertText: {
objectId: elementId,
insertionIndex: iIndex - 1,
text: txt,
},
}
];
Note:
This modified script supposes that Slides API is enabled and the scope of https://www.googleapis.com/auth/presentations is included in the scopes.
References:
presentations.batchUpdate
InsertTextRequest
If this was not what you want, I'm sorry.