Google Apps Script does not recognize tables in my document - javascript

First of all, I would like to thank you for your help in solving problems prior to this project, which was of great value in solving past problems.
I'm working with google apps script to format the titles of a document within tables.
The normal text is this:
After the script runs it looks like this:
The script is inserting the text inside tables in a normal way, as desired, however in addition to this formatting, I need to style the titles. Example: Title 1 usually has an Arial 18 font, without boldface and I want to change that to a Roboto 18 font with boldface.
I tried to work with custom styles of google apps, but in the script processing the formatting is lost specifically when it passes through this line of code.
I have already tried to recover the tables and format them after the update process, but the system does not recognize the tables as tables after the update process, and only the last formatted title remains in the desired format, as shown in the second image. See some prints of my debugging process.
The first title is changed and placed within the table and the formatting is applied and the inserted table is recognized:
When the script reaches the saveAndClose () point of the second method, the customization of the previous title disappears:
At the end of the process, only the last customized title remains in the desired format.
I already tried to recover the inserted tables to perform the update in the style of the text of the second column, but the script does not recognize the tables. It recognizes only one, and in fact, in this document I have 4 tables.
Here is a script for verification:
function verifiStyle(){
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var paragrafs = body.getParagraphs();
for(var i = paragrafs.length - 1; i >= 0; i--){
var attr = paragrafs[i].getAttributes();
for(var at in attr){
if(at == "HEADING" & attr[at] == "HEADING1"){
VerifTitle1(i);
}
else if(at == "HEADING" & attr[at] == "HEADING2"){
VerifTitle2(i);
}
else if(at == "HEADING" & attr[at] == "HEADING3"){
VerifTitle3(i);
}
else if(at == "HEADING" & attr[at] == "HEADING4"){
VerifTitle4(i);
}
else if(at == "HEADING" & attr[at] == "NORMAL"){
VerifTextoNormal(i);
}
}
}
var tables = body.getTables();
}
function VerifTitle1(value){
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var texto = body.getChild(value);
var ttt = texto.getText();
var cells = [
['', '']
];
var styleCell1 = {};
styleCell1[DocumentApp.Attribute.FONT_SIZE] = 20;
styleCell1[DocumentApp.Attribute.VERTICAL_ALIGNMENT] = DocumentApp.VerticalAlignment.CENTER;
styleCell1[DocumentApp.Attribute.FOREGROUND_COLOR]='#888888';
styleCell1[DocumentApp.Attribute.FONT_FAMILY]='Roboto';
var styleCell = {};
styleCell[DocumentApp.Attribute.VERTICAL_ALIGNMENT] = DocumentApp.VerticalAlignment.CENTER;
styleCell[DocumentApp.Attribute.FONT_FAMILY]='Roboto';
styleCell[DocumentApp.Attribute.FONT_SIZE] = 18;
styleCell[DocumentApp.Attribute.FOREGROUND_COLOR]='#000000';
styleCell[DocumentApp.Attribute.HEIGHT] = 0.5;
body.removeChild(body.getChild(value));
var table = body.insertTable(value, cells);
table.getRow(0).getCell(1).appendParagraph(ttt).setHeading(DocumentApp.ParagraphHeading.HEADING2);
table.getRow(0).getCell(1).setAttributes(styleCell);
table.getRow(0).getCell(0).setWidth(2);
table.getRow(0).getCell(0).setAttributes(styleCell1);
table.setBorderColor('#ffffff');
table.getRow(0).editAsText().setBold(true);
const index = body.getChildIndex(table);
const documentId = doc.getId();
doc.saveAndClose();
const tableStart = Docs.Documents.get(documentId).body.content[index + 1].startIndex;
const tempStyle = {width: {magnitude :0, unit: "PT"}, dashStyle: "SOLID", color: {color: {rgbColor: {blue: 0}}}};
const resource = {requests: [
{updateTableCellStyle: {
tableStartLocation: {index: tableStart},
tableCellStyle: {borderTop: tempStyle, borderBottom: tempStyle, borderLeft: tempStyle, borderRight: tempStyle},
fields: "borderTop,borderBottom,borderLeft,borderRight"
}},
{updateTableCellStyle: {
tableRange: {
tableCellLocation: {tableStartLocation: {index: tableStart}, rowIndex: 0, columnIndex: 0}, rowSpan: 1, columnSpan: 1},
tableCellStyle: {
borderRight: {dashStyle: "SOLID", width: {magnitude: 3, unit: "PT"}, color: {color: {rgbColor: {red: 0.9372549019607843, green: 0.3254901960784314, blue: 0.3137254901960784}}}}
},
fields: "borderRight"
}}
]};
Docs.Documents.batchUpdate(resource, documentId);
table = body.getChild(value).asTable();
}
function VerifTitle2(value){
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var texto = body.getChild(value);
var ttt = texto.getText();
var cells = [
['', '']
];
var styleCell1 = {};
styleCell1[DocumentApp.Attribute.FONT_SIZE] = 18;
styleCell1[DocumentApp.Attribute.VERTICAL_ALIGNMENT] = DocumentApp.VerticalAlignment.CENTER;
styleCell1[DocumentApp.Attribute.FOREGROUND_COLOR]='#888888';
styleCell1[DocumentApp.Attribute.FONT_FAMILY]='Roboto';
var styleCell = {};
styleCell[DocumentApp.Attribute.VERTICAL_ALIGNMENT] = DocumentApp.VerticalAlignment.CENTER;
styleCell[DocumentApp.Attribute.FONT_FAMILY]='Roboto';
styleCell[DocumentApp.Attribute.FONT_SIZE] = 15;
styleCell[DocumentApp.Attribute.FOREGROUND_COLOR]='#000000';
styleCell[DocumentApp.Attribute.HEIGHT] = 0.5;
body.removeChild(body.getChild(value));
var table = body.insertTable(value, cells);
table.getRow(0).getCell(1).appendParagraph(ttt).setHeading(DocumentApp.ParagraphHeading.HEADING2);
table.getRow(0).getCell(1).setAttributes(styleCell);
table.getRow(0).getCell(0).setWidth(2);
table.getRow(0).getCell(0).setAttributes(styleCell1);
table.setBorderColor('#ffffff');
table.getRow(0).editAsText().setBold(true);
const index = body.getChildIndex(table);
const documentId = doc.getId();
doc.saveAndClose();
const tableStart = Docs.Documents.get(documentId).body.content[index + 1].startIndex;
const tempStyle = {width: {magnitude :0, unit: "PT"}, dashStyle: "SOLID", color: {color: {rgbColor: {blue: 0}}}};
const resource = {requests: [
{updateTableCellStyle: {
tableStartLocation: {index: tableStart},
tableCellStyle: {borderTop: tempStyle, borderBottom: tempStyle, borderLeft: tempStyle, borderRight: tempStyle},
fields: "borderTop,borderBottom,borderLeft,borderRight"
}},
{updateTableCellStyle: {
tableRange: {
tableCellLocation: {tableStartLocation: {index: tableStart}, rowIndex: 0, columnIndex: 0}, rowSpan: 1, columnSpan: 1},
tableCellStyle: {
borderRight: {dashStyle: "SOLID", width: {magnitude: 3, unit: "PT"}, color: {color: {rgbColor: {red: 0.9372549019607843, green: 0.3254901960784314, blue: 0.3137254901960784}}}}
},
fields: "borderRight"
}}
]};
Docs.Documents.batchUpdate(resource, documentId);
}
function VerifTitle3(value){
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var texto = body.getChild(value);
var ttt = texto.getText();
var cells = [
['', '']
];
var styleCell1 = {};
styleCell1[DocumentApp.Attribute.FONT_SIZE] = 16;
styleCell1[DocumentApp.Attribute.VERTICAL_ALIGNMENT] = DocumentApp.VerticalAlignment.CENTER;
styleCell1[DocumentApp.Attribute.FOREGROUND_COLOR]='#888888';
styleCell1[DocumentApp.Attribute.FONT_FAMILY]='Roboto';
var styleCell = {};
styleCell[DocumentApp.Attribute.VERTICAL_ALIGNMENT] = DocumentApp.VerticalAlignment.CENTER;
styleCell[DocumentApp.Attribute.FONT_FAMILY]='Roboto';
styleCell[DocumentApp.Attribute.FONT_SIZE] = 14;
styleCell[DocumentApp.Attribute.FOREGROUND_COLOR]='#000000';
styleCell[DocumentApp.Attribute.HEIGHT] = 0.5;
styleCell[DocumentApp.Attribute.BOLD] = true;
body.removeChild(body.getChild(value));
var table = body.insertTable(value, cells);
table.getRow(0).getCell(1).appendParagraph(ttt).setHeading(DocumentApp.ParagraphHeading.HEADING3);
table.getRow(0).getCell(1).setAttributes(styleCell);
table.getRow(0).getCell(0).setWidth(2);
table.getRow(0).getCell(0).setAttributes(styleCell1);
table.setBorderColor('#ffffff');
table.getRow(0).editAsText().setBold(true);
const index = body.getChildIndex(table);
const documentId = doc.getId();
doc.saveAndClose();
const tableStart = Docs.Documents.get(documentId).body.content[index + 1].startIndex;
const tempStyle = {width: {magnitude :0, unit: "PT"}, dashStyle: "SOLID", color: {color: {rgbColor: {blue: 0}}}};
const resource = {requests: [
{updateTableCellStyle: {
tableStartLocation: {index: tableStart},
tableCellStyle: {borderTop: tempStyle, borderBottom: tempStyle, borderLeft: tempStyle, borderRight: tempStyle},
fields: "borderTop,borderBottom,borderLeft,borderRight"
}},
{updateTableCellStyle: {
tableRange: {
tableCellLocation: {tableStartLocation: {index: tableStart}, rowIndex: 0, columnIndex: 0}, rowSpan: 1, columnSpan: 1},
tableCellStyle: {
borderRight: {dashStyle: "SOLID", width: {magnitude: 3, unit: "PT"}, color: {color: {rgbColor: {red: 0.9372549019607843, green: 0.3254901960784314, blue: 0.3137254901960784}}}}
},
fields: "borderRight"
}}
]};
Docs.Documents.batchUpdate(resource, documentId);
}
function VerifTitle4(value){
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var texto = body.getChild(value);
var ttt = texto.getText();
var cells = [
['', '']
];
var styleCell1 = {};
styleCell1[DocumentApp.Attribute.FONT_SIZE] = 14;
styleCell1[DocumentApp.Attribute.VERTICAL_ALIGNMENT] = DocumentApp.VerticalAlignment.CENTER;
styleCell1[DocumentApp.Attribute.FOREGROUND_COLOR]='#888888';
styleCell1[DocumentApp.Attribute.FONT_FAMILY]='Roboto';
var styleCell = {};
styleCell[DocumentApp.Attribute.VERTICAL_ALIGNMENT] = DocumentApp.VerticalAlignment.CENTER;
styleCell[DocumentApp.Attribute.FONT_FAMILY]='Roboto';
styleCell[DocumentApp.Attribute.FONT_SIZE] = 12;
styleCell[DocumentApp.Attribute.FOREGROUND_COLOR]='#000000';
styleCell[DocumentApp.Attribute.HEIGHT] = 0.5;
body.removeChild(body.getChild(value));
var table = body.insertTable(value, cells);
var tables = body.getTables();
table.getRow(0).getCell(1).appendParagraph(ttt).setHeading(DocumentApp.ParagraphHeading.HEADING2);
table.getRow(0).getCell(1).setAttributes(styleCell);
table.getRow(0).getCell(0).setWidth(2);
table.getRow(0).getCell(0).setAttributes(styleCell1);
table.setBorderColor('#ffffff');
table.getRow(0).editAsText().setBold(true);
const index = body.getChildIndex(table);
const documentId = doc.getId();
doc.saveAndClose();
const tableStart = Docs.Documents.get(documentId).body.content[index + 1].startIndex;
const tempStyle = {width: {magnitude :0, unit: "PT"}, dashStyle: "SOLID", color: {color: {rgbColor: {blue: 0}}}};
const resource = {requests: [
{updateTableCellStyle: {
tableStartLocation: {index: tableStart},
tableCellStyle: {borderTop: tempStyle, borderBottom: tempStyle, borderLeft: tempStyle, borderRight: tempStyle},
fields: "borderTop,borderBottom,borderLeft,borderRight"
}},
{updateTableCellStyle: {
tableRange: {
tableCellLocation: {tableStartLocation: {index: tableStart}, rowIndex: 0, columnIndex: 0}, rowSpan: 1, columnSpan: 1},
tableCellStyle: {
borderRight: {dashStyle: "SOLID", width: {magnitude: 3, unit: "PT"}, color: {color: {rgbColor: {red: 0.9372549019607843, green: 0.3254901960784314, blue: 0.3137254901960784}}}}
},
fields: "borderRight"
}}
]};
Docs.Documents.batchUpdate(resource, documentId);
var tables1 = body.getTables();
}
function VerifTextoNormal(value){
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var para = body.getParagraphs();
var styleCell = {};
styleCell[DocumentApp.Attribute.HEADING] = DocumentApp.ParagraphHeading.NORMAL;
styleCell[DocumentApp.Attribute.VERTICAL_ALIGNMENT] = DocumentApp.VerticalAlignment.CENTER;
styleCell[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.JUSTIFY;
styleCell[DocumentApp.Attribute.FONT_FAMILY]='Arial';
styleCell[DocumentApp.Attribute.FONT_SIZE] = 12;
styleCell[DocumentApp.Attribute.FOREGROUND_COLOR]='#000000';
styleCell[DocumentApp.Attribute.INDENT_FIRST_LINE] = 15;
para[value].setAttributes(styleCell);
}

How about this answer?
Issue and workaround:
I could confirm the same issue using your shared sample Google Document. In this case, after updateTables() was finished, it seems that getTables() doesn't return the tables in the Document body. I think that this might be a bug. I thought that this might also affect to the current issue. So, in order to avoid this issue, I would like to propose to use Docs API.
At your script, when verifiStyle() is run, it updates the tables at the last line of verifiStyle(). This is a workaround.
Modified script:
When your script is modified, please modify as follows.
From:
This is the script in the last line of the function verifiStyle().
var tables = body.getTables();
}
To:
updateTables(); // Modified
}
// Added the below function.
function updateTables() {
const docId = DocumentApp.getActiveDocument().getId();
const contents = Docs.Documents.get(docId).body.content;
const reqs = contents.reduce((ar, e) => {
if ("table" in e) {
const t = e.table.tableRows[0].tableCells;
const obj = [
{updateTextStyle: {
range: {startIndex: t[0].startIndex, endIndex: t[0].endIndex},
textStyle: {bold: true, fontSize: {magnitude: 20, unit: "PT"}, weightedFontFamily: {fontFamily: "Roboto"}},fields: "bold,fontSize,weightedFontFamily"}
},
{updateTextStyle: {
range: {startIndex: t[1].startIndex, endIndex: t[1].endIndex},
textStyle: {bold: true, fontSize: {magnitude: 18, unit: "PT"}, weightedFontFamily: {fontFamily: "Roboto"}}, fields: "bold,fontSize,weightedFontFamily"}
}
];
ar = [...ar, obj];
}
return ar;
}, []);
Docs.Documents.batchUpdate({requests: reqs}, docId);
}
References:
Method: documents.batchUpdate
UpdateTextStyleRequest

Related

Display data for specific release selected in release filter at the top of page in rally dashboard

This is my code and in this the data displayed in chart is hole project data but in rally dashboard there is release filter at the top of your page. and i want my chart to show data of the the release selected by that filter and my sdk version in code is 1.33
<!DOCTYPE HTML\>
<script
src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js">
var WORKSPACE_OID = "__WORKSPACE_OID__";
var PROJECT_OID = "__PROJECT_OID__";
var PROJECT_SCOPING_UP = "__PROJECT_SCOPING_UP__";
var PROJECT_SCOPING_DOWN = "__PROJECT_SCOPING_DOWN__";
var MILS_IN_DAY = 86400000;
var DAYS_BACK = 30;
var filterChart;
var currentProjectDataSource;
var fromDate = new Date(new Date().getTime() - (MILS_IN_DAY * DAYS_BACK));
var allDefects = [];
// var currentRelease;
var onLoadAllIssues = function (result) {
// var defects = result.defects.filter(function (defect) {
// return defect.Release && defect.Release.\_refObjectName === currentRelease.Name;
// });
var labels = [];
var openDefects = [];
var closedDefects = [];
var defects = result.defects;
for (var count = 0; count < defects.length; count++) {
allDefects[allDefects.length] = defects[count];
var defect = defects[count];
labels.push(defect.CreationDate.split('T')[0]);
if (defect.ClosedDate !==null) {
closedDefects.push(defect.ClosedDate.split('T')[0]);
}
}
closedDefects.sort();
const counts = {};
labels.forEach(function (x) { counts[x] = (counts[x] || 0) + 1; });
const closedcounts = {};
closedDefects.forEach(function (x) { closedcounts[x] = (closedcounts[x] || 0) + 1; });
mychart(counts,closedcounts,labels)
};
var createCharts = function () {
var loadAllDefectsQuery = {
type: 'defect',
key: 'defects',
fetch: 'CreationDate,ClosedDate,ObjectID,FormattedID,Name,State,Priority',
order: 'CreationDate',
query: '((CreationDate != "null") OR (CreationDate > "' + dojo.date.stamp.toISOString(fromDate, { zulu: true }) +
'"))'
};
currentProjectDataSource.findAll(loadAllDefectsQuery, onLoadAllIssues);
};
var initPage = function () {
currentProjectDataSource = new rally.sdk.data.RallyDataSource(WORKSPACE_OID, PROJECT_OID, PROJECT_SCOPING_UP,
PROJECT_SCOPING_DOWN);
createCharts();
};
rally.addOnLoad(initPage);
function mychart(counts,closedcounts,labels) {
const pielable = labels;
const piedata = counts;
const closedcountsdata = closedcounts;
const data = {
datasets: [
{
label: 'Number of opened defects',
data: piedata,
},
{
label: 'Number of closed defects',
data: closedcountsdata,
}
]
};
const config = {
type: 'line',
data: data,
options: {
scales: {
x: {
min:"2022-01-01",
max:"2022-12-31",
type: 'time',
time:{
unit:'day',
},
},
y: {
beginAtZero: true,
grace: 5,
ticks: {
stepSize: 1,
},
},
},
plugins: {
legend: {
position: 'top',
},
title: {
display: true,
text: 'Defect Burndown Chart'
},
tooltip: {
yAlign: 'bottom',
titleMarginBottom: 0,
callbacks: {
title: function (context) {
return( `${context[0].label.slice(0, -13).replace(/,/g, " ")}`)
},
}
}
}
}
};
const myChart = new Chart(
document.getElementById('myChart'),
config
)
filterChart= function filterChart(date){
const year = date.value.substring(0,4);
const month = date.value.substring(5);
const lastday = (y,m)=>{
return new Date(y,m,0).getDate();
}
const startDate = `${date.value}-01`;
const endDate = `${date.value}-${lastday(year,month)}`;
myChart.config.options.scales.x.min=startDate;
myChart.config.options.scales.x.ma`your text`x=endDate;
myChart.update();
}}
</script>

Feeding Array to a Classifier

I have an issue looping through an array using a bayesian classifier function.
Here is my array:
var data = ['good', {
dry: 1,
wet: 0,
moist:0
}, 'bad', {
dry: 0,
wet: 1,
moist: 1
}, 'neutral', {
dry: 1,
wet: 1,
moist:1
}, 'good', {
dry: 1,
wet: 0,
moist: 1
}];
Here's my classifier function:
class Bayes{
constructor(...categories) {
this.categories = {};
this.categoryCounts = {};
categories.forEach(category => {
this.categories[category] = {};
this.categoryCounts[category] = 0;
});
}
train(category, dataset) {
this.categoryCounts[category]++;
Object.keys(dataset).forEach(key => {
this.categories[category][key] = (this.categories[category][key] || '') + dataset[key];
});
};
classify(dataset) {
let scores = {};
let trainingCount = Object.values(this.categoryCounts).reduce((a, b) => a + b );
Object.keys(this.categories).forEach(category => {
scores[category] = 0;
let categoryWords = this.categories[category];
let total = Object.values(categoryWords).reduce((a, b) => a + b );
Object.keys(dataset).forEach(function (key) {
let value = dataset[key];
let s = categoryWords[key] || 0.1;
let i = 0;
while(i<value){
scores[category] += Math.log(s / parseFloat(total));
i++;
}
});
let s = this.categoryCounts[category] || 0.1;
scores[category] = (s / trainingCount);
});
return scores;
};
};
Normally, to classify the data; I'll do:
var b = new Bayes('good', 'bad', 'neutral');
b.train('good', { dry: 1, wet: 0, moist:0});
b.train('bad', {dry: 0,wet: 1,moist: 1});
b.train('neutral', {dry: 1,wet: 1,moist:1});
b.train('good', {dry: 1,wet: 0,moist: 1});
console.log(b.classify({ dry: 0, wet: 1, moist: 1}));
// good: 0.5, bad: 0.25, neutral: 0.25
But when I can't figure out how to train the data by iterating through data.
I need help to feed the array dynamically as a javascript object.
if you can guarantee the data structure consistency, such as
let data = [key, value, key, value, key, value......]
const data = ['good', { dry: 1, wet: 0, moist:0}, 'neutral', {dry: 1,wet: 1,moist:1}, 'good', {dry: 1,wet: 0,moist: 1}];
// 1: chunk it
const size = 2;
const chunks = [];
while (data.length) {
chunks.push(data.splice(0, size));
}
console.log(chunks);
// 2: loop through your train
let keys = chunks.map(val=>val[0])
let deDupeKeys = [...new Set(keys)]
console.log(keys)
console.log(deDupeKeys)
// var b = new Bayes(deDupeKeys)
chunks.forEach(chunk => {
console.log(chunk[0])
console.log(chunk[1])
// b.train(chunk[0],chunk[1]);
})
Assuming the data array will have the format: data = [category, dataset, category, dataset...], a simple solution would be to loop the data array as follows and train the classifier.
for (let i = 0; i < data.length; i = i + 2) {
console.log("category : ", data[i], "dataset : ", data[i + 1]);
b.train(data[i], data[i + 1]);
}

how do i use the numbers i key in from a form as the input data for chartjs

i am trying to use my input data as the data of the graph
i am using chartjs
please help
iv tried to split and join the numbers but nothing is showing
i am using flask as my back end
var Diadata = []
function getdata() {
Diadata[0] = document.getElementById('Carat').value;
Diadata[1] = document.getElementById("Cut").value;
Diadata[2] = document.getElementById("Color").value;
Diadata[3] = document.getElementById("Clarity").value;
Diadata[4] = document.getElementById("Depth").value;
Diadata[5] = document.getElementById("Table").value;
Diadata[6] = document.getElementById("X").value;
Diadata[7] = document.getElementById("Y").value;
Diadata[8] = document.getElementById("Z").value;
console.log("TEST: ",[Diadata.join(" ").replace(/ /g,",")])
}
var ctxL = document.getElementById("barChartHorizontal").getContext('2d');
var myLineChart = new Chart(ctxL, {
type: 'horizontalBar',
data: {
labels: ["Carat", "Cut", "Color", "Clarity", "Depth", "Table", "X", "Y", "Z"],
datasets: [
{
label: "Price",
data: [Diadata.join(" ").replace(/ /g,",")], //i want to add my input data here
backgroundColor: 'orange',
borderWidth: 0,
}
]
},
The data array is expecting an array with values so if you remove your join it should work.
You would get this:
var Diadata = []
function getdata() {
Diadata[0] = document.getElementById('Carat').value;
Diadata[1] = document.getElementById("Cut").value;
Diadata[2] = document.getElementById("Color").value;
Diadata[3] = document.getElementById("Clarity").value;
Diadata[4] = document.getElementById("Depth").value;
Diadata[5] = document.getElementById("Table").value;
Diadata[6] = document.getElementById("X").value;
Diadata[7] = document.getElementById("Y").value;
Diadata[8] = document.getElementById("Z").value;
}
getdata();
var ctxL = document.getElementById("barChartHorizontal").getContext('2d');
var myLineChart = new Chart(ctxL, {
type: 'horizontalBar',
data: {
labels: ["Carat", "Cut", "Color", "Clarity", "Depth", "Table", "X", "Y", "Z"],
datasets: [
{
label: "Price",
data: Diadata, //i want to add my input data here
backgroundColor: 'orange',
borderWidth: 0,
}
]
},

Phaser - How to make images fit on all devices

So I have a source code that I'm learning from but I'm having trouble making images such as the background and sprites fitting on various devices.
Here is what I have so far:
var game = new Phaser.Game(800, 600, Phaser.AUTO, '');
game.state.add('play', {
preload: function() {
this.game.load.image('forest-back', 'assets/parallax_forest_pack/layers/parallax-forest-back-trees.png');
this.game.load.image('forest-lights', 'assets/parallax_forest_pack/layers/parallax-forest-lights.png');
this.game.load.image('forest-middle', 'assets/parallax_forest_pack/layers/parallax-forest-middle-trees.png');
this.game.load.image('forest-front', 'assets/parallax_forest_pack/layers/parallax-forest-front-trees.png');
this.game.load.image('aerocephal', 'assets/allacrost_enemy_sprites/aerocephal.png');
this.game.load.image('arcana_drake', 'assets/allacrost_enemy_sprites/arcana_drake.png');
this.game.load.image('aurum-drakueli', 'assets/allacrost_enemy_sprites/aurum-drakueli.png');
this.game.load.image('bat', 'assets/allacrost_enemy_sprites/bat.png');
this.game.load.image('daemarbora', 'assets/allacrost_enemy_sprites/daemarbora.png');
this.game.load.image('deceleon', 'assets/allacrost_enemy_sprites/deceleon.png');
this.game.load.image('demonic_essence', 'assets/allacrost_enemy_sprites/demonic_essence.png');
this.game.load.image('dune_crawler', 'assets/allacrost_enemy_sprites/dune_crawler.png');
this.game.load.image('green_slime', 'assets/allacrost_enemy_sprites/green_slime.png');
this.game.load.image('nagaruda', 'assets/allacrost_enemy_sprites/nagaruda.png');
this.game.load.image('rat', 'assets/allacrost_enemy_sprites/rat.png');
this.game.load.image('scorpion', 'assets/allacrost_enemy_sprites/scorpion.png');
this.game.load.image('skeleton', 'assets/allacrost_enemy_sprites/skeleton.png');
this.game.load.image('snake', 'assets/allacrost_enemy_sprites/snake.png');
this.game.load.image('spider', 'assets/allacrost_enemy_sprites/spider.png');
this.game.load.image('stygian_lizard', 'assets/allacrost_enemy_sprites/stygian_lizard.png');
this.game.load.image('gold_coin', 'assets/496_RPG_icons/I_GoldCoin.png');
this.game.load.image('dagger', 'assets/496_RPG_icons/W_Dagger002.png');
this.game.load.image('swordIcon1', 'assets/496_RPG_icons/S_Sword15.png');
// build panel for upgrades
var bmd = this.game.add.bitmapData(250, 500);
bmd.ctx.fillStyle = '#9a783d';
bmd.ctx.strokeStyle = '#35371c';
bmd.ctx.lineWidth = 12;
bmd.ctx.fillRect(0, 0, 250, 500);
bmd.ctx.strokeRect(0, 0, 250, 500);
this.game.cache.addBitmapData('upgradePanel', bmd);
var buttonImage = this.game.add.bitmapData(476, 48);
buttonImage.ctx.fillStyle = '#e6dec7';
buttonImage.ctx.strokeStyle = '#35371c';
buttonImage.ctx.lineWidth = 4;
buttonImage.ctx.fillRect(0, 0, 225, 48);
buttonImage.ctx.strokeRect(0, 0, 225, 48);
this.game.cache.addBitmapData('button', buttonImage);
// the main player
this.player = {
clickDmg: 1,
gold: 50,
dps: 0
};
// world progression
this.level = 1;
// how many monsters have we killed during this level
this.levelKills = 0;
// how many monsters are required to advance a level
this.levelKillsRequired = 10;
},
create: function() {
var state = this;
this.background = this.game.add.group();
// setup each of our background layers to take the full screen
['forest-back', 'forest-lights', 'forest-middle', 'forest-front']
.forEach(function(image) {
var bg = state.game.add.tileSprite(0, 0, state.game.world.width,
state.game.world.height, image, '', state.background);
bg.tileScale.setTo(4,4);
});
this.upgradePanel = this.game.add.image(10, 70, this.game.cache.getBitmapData('upgradePanel'));
var upgradeButtons = this.upgradePanel.addChild(this.game.add.group());
upgradeButtons.position.setTo(8, 8);
var upgradeButtonsData = [
{icon: 'dagger', name: 'Attack', level: 0, cost: 5, purchaseHandler: function(button, player) {
player.clickDmg += 1;
}},
{icon: 'swordIcon1', name: 'Auto-Attack', level: 0, cost: 25, purchaseHandler: function(button, player) {
player.dps += 5;
}}
];
var button;
upgradeButtonsData.forEach(function(buttonData, index) {
button = state.game.add.button(0, (50 * index), state.game.cache.getBitmapData('button'));
button.icon = button.addChild(state.game.add.image(6, 6, buttonData.icon));
button.text = button.addChild(state.game.add.text(42, 6, buttonData.name + ': ' + buttonData.level, {font: '16px Arial Black'}));
button.details = buttonData;
button.costText = button.addChild(state.game.add.text(42, 24, 'Cost: ' + buttonData.cost, {font: '16px Arial Black'}));
button.events.onInputDown.add(state.onUpgradeButtonClick, state);
upgradeButtons.addChild(button);
});
var monsterData = [
{name: 'Aerocephal', image: 'aerocephal', maxHealth: 10},
{name: 'Arcana Drake', image: 'arcana_drake', maxHealth: 20},
{name: 'Aurum Drakueli', image: 'aurum-drakueli', maxHealth: 30},
{name: 'Bat', image: 'bat', maxHealth: 5},
{name: 'Daemarbora', image: 'daemarbora', maxHealth: 10},
{name: 'Deceleon', image: 'deceleon', maxHealth: 10},
{name: 'Demonic Essence', image: 'demonic_essence', maxHealth: 15},
{name: 'Dune Crawler', image: 'dune_crawler', maxHealth: 8},
{name: 'Green Slime', image: 'green_slime', maxHealth: 3},
{name: 'Nagaruda', image: 'nagaruda', maxHealth: 13},
{name: 'Rat', image: 'rat', maxHealth: 2},
{name: 'Scorpion', image: 'scorpion', maxHealth: 2},
{name: 'Skeleton', image: 'skeleton', maxHealth: 6},
{name: 'Snake', image: 'snake', maxHealth: 4},
{name: 'Spider', image: 'spider', maxHealth: 4},
{name: 'Stygian Lizard', image: 'stygian_lizard', maxHealth: 20}
];
this.monsters = this.game.add.group();
var monster;
monsterData.forEach(function(data) {
// create a sprite for them off screen
monster = state.monsters.create(1000, state.game.world.centerY, data.image);
// use the built in health component
monster.health = monster.maxHealth = data.maxHealth;
// center anchor
monster.anchor.setTo(0.5, 1);
// reference to the database
monster.details = data;
//enable input so we can click it!
monster.inputEnabled = true;
monster.events.onInputDown.add(state.onClickMonster, state);
// hook into health and lifecycle events
monster.events.onKilled.add(state.onKilledMonster, state);
monster.events.onRevived.add(state.onRevivedMonster, state);
});
// display the monster front and center
this.currentMonster = this.monsters.getRandom();
this.currentMonster.position.set(this.game.world.centerX + 100, this.game.world.centerY + 50);
this.monsterInfoUI = this.game.add.group();
this.monsterInfoUI.position.setTo(this.currentMonster.x - 220, this.currentMonster.y + 120);
this.monsterNameText = this.monsterInfoUI.addChild(this.game.add.text(0, 0, this.currentMonster.details.name, {
font: '48px Arial Black',
fill: '#fff',
strokeThickness: 4
}));
this.monsterHealthText = this.monsterInfoUI.addChild(this.game.add.text(0, 80, this.currentMonster.health + ' HP', {
font: '32px Arial Black',
fill: '#ff0000',
strokeThickness: 4
}));
this.dmgTextPool = this.add.group();
var dmgText;
for (var d=0; d<50; d++) {
dmgText = this.add.text(0, 0, '1', {
font: '64px Arial Black',
fill: '#fff',
strokeThickness: 4
});
// start out not existing, so we don't draw it yet
dmgText.exists = false;
dmgText.tween = game.add.tween(dmgText)
.to({
alpha: 0,
y: 100,
x: this.game.rnd.integerInRange(100, 700)
}, 1000, Phaser.Easing.Cubic.Out);
dmgText.tween.onComplete.add(function(text, tween) {
text.kill();
});
this.dmgTextPool.add(dmgText);
}
// create a pool of gold coins
this.coins = this.add.group();
this.coins.createMultiple(50, 'gold_coin', '', false);
this.coins.setAll('inputEnabled', true);
this.coins.setAll('goldValue', 1);
this.coins.callAll('events.onInputDown.add', 'events.onInputDown', this.onClickCoin, this);
this.playerGoldText = this.add.text(30, 30, 'Gold: ' + this.player.gold, {
font: '24px Arial Black',
fill: '#fff',
strokeThickness: 4
});
// 100ms 10x a second
this.dpsTimer = this.game.time.events.loop(100, this.onDPS, this);
// setup the world progression display
this.levelUI = this.game.add.group();
this.levelUI.position.setTo(this.game.world.centerX, 30);
this.levelText = this.levelUI.addChild(this.game.add.text(0, 0, 'Level: ' + this.level, {
font: '24px Arial Black',
fill: '#fff',
strokeThickness: 4
}));
this.levelKillsText = this.levelUI.addChild(this.game.add.text(0, 30, 'Kills: ' + this.levelKills + '/' + this.levelKillsRequired, {
font: '24px Arial Black',
fill: '#fff',
strokeThickness: 4
}));
},
onDPS: function() {
if (this.player.dps > 0) {
if (this.currentMonster && this.currentMonster.alive) {
var dmg = this.player.dps / 10;
this.currentMonster.damage(dmg);
// update the health text
this.monsterHealthText.text = this.currentMonster.alive ? Math.round(this.currentMonster.health) + ' HP' : 'DEAD';
}
}
},
onUpgradeButtonClick: function(button, pointer) {
// make this a function so that it updates after we buy
function getAdjustedCost() {
return Math.ceil(button.details.cost + (button.details.level * 1.46));
}
if (this.player.gold - getAdjustedCost() >= 0) {
this.player.gold -= getAdjustedCost();
this.playerGoldText.text = 'Gold: ' + this.player.gold;
button.details.level++;
button.text.text = button.details.name + ': ' + button.details.level;
button.costText.text = 'Cost: ' + getAdjustedCost();
button.details.purchaseHandler.call(this, button, this.player);
}
},
onClickCoin: function(coin) {
if (!coin.alive) {
return;
}
// give the player gold
this.player.gold += coin.goldValue;
// update UI
this.playerGoldText.text = 'Gold: ' + this.player.gold;
// remove the coin
coin.kill();
},
onKilledMonster: function(monster) {
// move the monster off screen again
monster.position.set(1000, this.game.world.centerY);
var coin;
// spawn a coin on the ground
coin = this.coins.getFirstExists(false);
coin.reset(this.game.world.centerX + this.game.rnd.integerInRange(-100, 100), this.game.world.centerY);
coin.goldValue = Math.round(this.level * 1.33);
this.game.time.events.add(Phaser.Timer.SECOND * 3, this.onClickCoin, this, coin);
this.levelKills++;
if (this.levelKills >= this.levelKillsRequired) {
this.level++;
this.levelKills = 0;
}
this.levelText.text = 'Level: ' + this.level;
this.levelKillsText.text = 'Kills: ' + this.levelKills + '/' + this.levelKillsRequired;
// pick a new monster
this.currentMonster = this.monsters.getRandom();
// upgrade the monster based on level
this.currentMonster.maxHealth = Math.ceil(this.currentMonster.details.maxHealth + ((this.level - 1) * 10.6));
// make sure they are fully healed
this.currentMonster.revive(this.currentMonster.maxHealth);
},
onRevivedMonster: function(monster) {
monster.position.set(this.game.world.centerX + 100, this.game.world.centerY + 50);
// update the text display
this.monsterNameText.text = monster.details.name;
this.monsterHealthText.text = monster.health + 'HP';
},
onClickMonster: function(monster, pointer) {
// apply click damage to monster
this.currentMonster.damage(this.player.clickDmg);
// grab a damage text from the pool to display what happened
var dmgText = this.dmgTextPool.getFirstExists(false);
if (dmgText) {
dmgText.text = this.player.clickDmg;
dmgText.reset(pointer.positionDown.x, pointer.positionDown.y);
dmgText.alpha = 1;
dmgText.tween.start();
}
// update the health text
this.monsterHealthText.text = this.currentMonster.alive ? this.currentMonster.health + ' HP' : 'DEAD';
}
});
game.state.start('play');
In your init or preload function, you should choose your scale mode. Please check the documentation to understand the different options:
//Options here are: NO_SCALE, EXACT_FIT, SHOW_ALL, RESIZE and USER_SCALE
this.scale.scaleMode = Phaser.ScaleManager.EXACT_FIT;
Please also check if you want to set pageAlignHorizontally and pageAlignVertically to true:
this.scale.pageAlignHorizontally = true;
this.scale.pageAlignVertically = true;
In some cases, you will want to call the refresh method:
this.scale.refresh();

Extracting multi-dimentsional arrays in Javascript/JQuery

I'm extracting some data from an SQL source, which I can get into a javascript script as a simple array (shown grouped by dates) which consists of week no, task number and hours spent:
mydata = [
// weekno, taskno, hours
["2014-14",160,37.5],
["2014-15",160,30],
["2014-15",243,7.5],
["2014-16",160,37.5],
["2014-17",0,7.5],
["2014-17",3,7.5],
["2014-17",321,22.5],
["2014-18",0,7.5],
["2014-18",321,30],
["2014-19",3,7.5],
["2014-19",295,30]
];
I'm going to be charting it using HighCharts, and I need to get it into two property arrays like this:
properties = {
categories: [ "2014-14","2014-15","2014-16","2014-17","2014-18","2014-19"],
series: [
// Task Week
// No 14 15 16 17 18 19
//
{ name: '0', data: [ 0, 0, 0, 7.5, 7.5, 0 ] },
{ name: '3', data: [ 0, 0, 0, 7.5, 0, 7.5 ] },
{ name: '160', data: [ 37.5, 30, 37.5, 0, 0, 0 ] },
{ name: '243', data: [ 0, 7.5, 0, 0, 0, 0 ] },
{ name: '295', data: [ 0, 0, 0, 0, 0, 30 ] },
{ name: '321', data: [ 0, 0, 0, 22.5, 30, 0 ] }
]
}
Aside from looping, am I missing some succinct, idiomatic method for doing this?
In case it's of use to anyone, here's a cobbled together solution:
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
var categories = [];
var subcategories = [];
var temp = {};
for (var i = 0; i < myChartData.length; i++) {
key = myChartData[i][0];
taskno = myChartData[i][1];
hours = myChartData[i][2];
if (taskno in temp == false) temp[taskno] = {};
if (key in temp[taskno] == false) temp[taskno][key] = 0;
temp[taskno][key] += hours;
categories.push(myChartData[i][0]);
subcategories.push(myChartData[i][1])
}
var uniqueCategories = categories.filter(onlyUnique).sort();
var uniqueSubcategories = subcategories.filter(onlyUnique).sort(function(a, b) {
return a - b
});
var series = [];
for (var i = 0; i < uniqueSubcategories.length; i++) {
subcatKey = uniqueSubcategories[i];
series[i] = { name: 'Task ' + subcatKey, data: [] };
for (var j = 0; j < uniqueCategories.length; j++) {
catKey = uniqueCategories[j];
series[i]['data'].push(temp[subcatKey][catKey] ? temp[subcatKey][catKey] : 0);
}
}
where series and uniqueCategories are the required data.

Categories