My code looks like:
var check = parametrTable.length -1;
var data = [];
$.each(parametrTable, function(i, x) { // NOTE: x = parametrTable[i]
$.getJSON("myurlwithparametr", function(json) {
$.each(json, function(j, d) {
data[j] = data[j] || {};
data[j]["count" + i] = d.count;
if (i == 0) {
data[j].category = d.column;
}
});
if(i == check){
loadChart(data);
}
});
});
This part generate data from my amchart, next if 'i' == 'check' (end of .each loop) i send generate data to function 'loadChart' with parametr 'data'.
Code for my function:
AmCharts.ready(function() {
chart = new AmCharts.AmSerialChart();
chart.dataProvider = data;
chart.categoryField = "category";
chart.startDuration = 1;
chart.type = "serial";
var categoryAxis = chart.categoryAxis;
categoryAxis.labelRotation = 90;
categoryAxis.axisAlpha = 1;
categoryAxis.insie = true;
categoryAxis.gridPosition = "start";
var valueAxis = new AmCharts.ValueAxis();
valueAxis.title = "title";
valueAxis.axisAlpha = 1;
chart.addValueAxis(valueAxis);
for (i=0;i<data.length;++i) {
var graph = new AmCharts.AmGraph();
graph.valueField = "count"+i+"";
graph.balloonText = "[[value]]";
graph.bullet = "round";
graph.type = "smoothedLine";
graph.lineAlpha = 1;
graph.connect = true;
graph.lineThickness = '2';
//graph.fillAlphas = 1;
chart.addGraph(graph);
}
chart.write('chartdiv');
});
On my page i have div with id = 'chartdiv'. When I check in the function the values in the table (data) its look ok, but my chart does not regenerate. :( When I skip
AmCharts.ready(function() {
chart is generated, but not all the values. Any sugestions?
It's hard to tell without seeing your actual data, but it seems that the issue is how you crate your graphs. Right now you are creating a separate graph for each data point in your data. That does not seem right. You should create for each item in parametrTable:
for (i=0;i<=check;++i) {
var graph = new AmCharts.AmGraph();
graph.valueField = "count"+i+"";
graph.balloonText = "[[value]]";
graph.bullet = "round";
graph.type = "smoothedLine";
graph.lineAlpha = 1;
graph.connect = true;
graph.lineThickness = '2';
//graph.fillAlphas = 1;
chart.addGraph(graph);
}
Additionally, jQuery AJAX calls are asynchronous. Meaning that the your .each() cycle completes before actual data is loaded.
You need to keep separate iterator to keep track of number of loaded items. I.e.:
var check = parametrTable.length -1;
var loaded = 0;
var data = [];
$.each(parametrTable, function(i, x) { // NOTE: x = parametrTable[i]
$.getJSON("myurlwithparametr", function(json) {
loaded++;
$.each(json, function(j, d) {
data[j] = data[j] || {};
data[j]["count" + i] = d.count;
if (i == 0) {
data[j].category = d.column;
}
});
if(loaded == check){
loadChart(data);
}
});
});
Related
I'm writing a google docs apps script in making a google docs add-on. When the user clicks a button in the sidebar, an apps script function is called named executeSpellChecking. This apps script function makes a remote POST call after getting the document's text.
total time = time that takes from when user clicks the button, until the .withSuccessHandler(, that means until executeSpellChecking returns = 2000 ms
function time = time that takes for the executeSpellChecking call to complete from its start to its end = 1400 ms
t3 = time that takes for the remote POST call to be completed = 800ms
t4 = time that takes for the same remote POST call to complete in a VB.NET app = 200ms
Problems:
Why total time to complete is bigger than total function time by a staggering 600ms, what else happens there? shouldn't they be equal? How can I improve it?
Why t3 is bigger than t4 ? Shouldn't they be equal? Is there something wrong with POST requests when happening from .gs? How can I improve it ?
the code is (sidebar.html):
function runSpellChecking() {
gb_IsSpellcheckingRunning = true;
//gb_isAutoCorrecting = false;
gi_CorrectionCurrWordIndex = -1;
$("#btnStartCorr").attr("disabled", true);
$("#divMistakes").html("");
this.disabled = true;
//$('#error').remove();
var origin = $('input[name=origin]:checked').val();
var dest = $('input[name=dest]:checked').val();
var savePrefs = $('#save-prefs').is(':checked');
//var t1 = new Date().getTime();
console.time("total time");
google.script.run
.withSuccessHandler(
function(textAndTranslation, element) {
if (gb_IsSpellCheckingEnabled) {
console.timeEnd("total time");
//var t2 = new Date().getTime();
go_TextAndTranslation = JSON.parse(JSON.stringify(textAndTranslation));
var pagewords = textAndTranslation.pagewords;
var spellchecked = textAndTranslation.spellchecked;
//alert("total time to complete:" + (t2-t1) + "###" + go_TextAndTranslation.time);
//irrelevant code follows below...
}
})
.withFailureHandler(
function(msg, element) {
showError(msg, $('#button-bar'));
element.disabled = false;
})
.withUserObject(this)
.executeSpellChecking(origin, dest, savePrefs);
}
and the called function code is (spellcheck.gs):
function executeSpellChecking(origin, dest, savePrefs) {
//var t1 = new Date().getTime();
console.time("function time");
var body = DocumentApp.getActiveDocument().getBody();
var alltext = body.getText();
var lastchar = alltext.slice(-1);
if (lastchar != " " && lastchar != "\n") {
body.editAsText().insertText(alltext.length, "\n");
alltext = body.getText();
}
var arr_alltext = alltext.split(/[\s\n]/);
var pagewords = new Object;
var pagewordsOrig = new Object;
var pagewordsOrigOffset = new Object;
var offset = 0;
var curWord = "";
var cnt = 0;
for (var i = 0; i < arr_alltext.length; i++) {
curWord = arr_alltext[i];
if (StringHasSimeioStiksis(curWord)) {
curWord = replaceSimeiaStiksis(curWord);
var arr3 = curWord.split(" ");
for (var k = 0; k < arr3.length; k++) {
curWord = arr3[k];
pagewords["" + (cnt+1).toString()] = curWord.replace(/[`~##$%^&*()_|+\-="<>\{\}\[\]\\\/]/gi, '');
pagewordsOrig["" + (cnt+1).toString()] = curWord;
pagewordsOrigOffset["" + (cnt+1).toString()] = offset;
offset += curWord.length;
cnt++;
}
offset++;
} else {
pagewords["" + (cnt+1).toString()] = curWord.replace(/[`~##$%^&*()_|+\-="<>\{\}\[\]\\\/\n]/gi, '');
pagewordsOrig["" + (cnt+1).toString()] = curWord;
pagewordsOrigOffset["" + (cnt+1).toString()] = offset;
offset += curWord.length + 1;
cnt++;
}
}
var respTString = "";
var url = 'https://www.example.org/spellchecker.php';
var data = {
"Text" : JSON.stringify(pagewords),
"idOffset" : "0",
"lexID" : "8",
"userEmail" : "test#example.org"
};
var payload = JSON.stringify(data);
var options = {
"method" : "POST",
"contentType" : "application/json",
"payload" : payload
};
//var t11 = new Date().getTime();
console.time("POST time");
var response = UrlFetchApp.fetch(url, options);
console.timeEnd("POST time");
//var t22 = new Date().getTime();
var resp = response.getContentText();
respTString = resp;
var spellchecked = JSON.parse(respTString);
var style = {};
for (var k in pagewords){
if (pagewords.hasOwnProperty(k)) {
if (spellchecked.hasOwnProperty(k)) {
if (spellchecked[k].substr(0, 1) == "1") {
style[DocumentApp.Attribute.FOREGROUND_COLOR] = "#000000";
}
if (spellchecked[k].substr(0, 1) == "0") {
style[DocumentApp.Attribute.FOREGROUND_COLOR] = "#FF0000";
}
if (spellchecked[k].substr(0, 1) == "4") {
style[DocumentApp.Attribute.FOREGROUND_COLOR] = "#0000FF";
}
if (pagewordsOrigOffset[k] < alltext.length) {
body.editAsText().setAttributes(pagewordsOrigOffset[k], pagewordsOrigOffset[k] + pagewordsOrig[k].length, style);
}
}
}
}
//var t2 = new Date().getTime();
console.timeEnd("function time")
return {
"pagewords" : pagewords,
"pagewordsOrig" : pagewordsOrig,
"pagewordsOrigOffset" : pagewordsOrigOffset,
"spellchecked" : spellchecked
}
}
Thank you in advance for any help.
EDIT: I updated the code to use console.time according to the suggestion, the results are:
total time: 2048.001953125 ms
Jun 21, 2021, 3:01:40 PM Debug POST time: 809ms
Jun 21, 2021, 3:01:41 PM Debug function time: 1408ms
So the problem is not how time is measured. function time is 1400ms, while the time it takes to return is 2000ms, a difference of 600ms and the POST time is a staggering 800ms, instead of 200ms it takes in VB.net to make the exact same POST call.
Use console.time() and console.timeEnd():
https://developers.google.com/apps-script/reference/base/console
I modified the code for you. console.timeEnd() outputs the time duration in the console automatically, so I removed the alert for you that showed the time difference.
You might want the strings that I used as the parameter as some sort of constant variable, so there are no magic strings used twice. I hope this is of use to you.
function runSpellChecking() {
gb_IsSpellcheckingRunning = true;
//gb_isAutoCorrecting = false;
gi_CorrectionCurrWordIndex = -1;
$("#btnStartCorr").attr("disabled", true);
$("#divMistakes").html("");
this.disabled = true;
//$('#error').remove();
var origin = $('input[name=origin]:checked').val();
var dest = $('input[name=dest]:checked').val();
var savePrefs = $('#save-prefs').is(':checked');
console.time("total time");
google.script.run
.withSuccessHandler(
function(textAndTranslation, element) {
if (gb_IsSpellCheckingEnabled) {
console.timeEnd("total time");
go_TextAndTranslation = JSON.parse(JSON.stringify(textAndTranslation));
var pagewords = textAndTranslation.pagewords;
var spellchecked = textAndTranslation.spellchecked;
//irrelevant code follows below...
}
})
.withFailureHandler(
function(msg, element) {
showError(msg, $('#button-bar'));
element.disabled = false;
})
.withUserObject(this)
.executeSpellChecking(origin, dest, savePrefs);
}
function executeSpellChecking(origin, dest, savePrefs) {
console.time("function time");
var body = DocumentApp.getActiveDocument().getBody();
var alltext = body.getText();
var lastchar = alltext.slice(-1);
if (lastchar != " " && lastchar != "\n") {
body.editAsText().insertText(alltext.length, "\n");
alltext = body.getText();
}
var arr_alltext = alltext.split(/[\s\n]/);
var pagewords = new Object;
var pagewordsOrig = new Object;
var pagewordsOrigOffset = new Object;
var offset = 0;
var curWord = "";
var cnt = 0;
for (var i = 0; i < arr_alltext.length; i++) {
curWord = arr_alltext[i];
if (StringHasSimeioStiksis(curWord)) {
curWord = replaceSimeiaStiksis(curWord);
var arr3 = curWord.split(" ");
for (var k = 0; k < arr3.length; k++) {
curWord = arr3[k];
pagewords["" + (cnt+1).toString()] = curWord.replace(/[`~##$%^&*()_|+\-="<>\{\}\[\]\\\/]/gi, '');
pagewordsOrig["" + (cnt+1).toString()] = curWord;
pagewordsOrigOffset["" + (cnt+1).toString()] = offset;
offset += curWord.length;
cnt++;
}
offset++;
} else {
pagewords["" + (cnt+1).toString()] = curWord.replace(/[`~##$%^&*()_|+\-="<>\{\}\[\]\\\/\n]/gi, '');
pagewordsOrig["" + (cnt+1).toString()] = curWord;
pagewordsOrigOffset["" + (cnt+1).toString()] = offset;
offset += curWord.length + 1;
cnt++;
}
}
var respTString = "";
var url = 'https://www.example.org/spellchecker.php';
var data = {
"Text" : JSON.stringify(pagewords),
"idOffset" : "0",
"lexID" : "8",
"userEmail" : "test#example.org"
};
var payload = JSON.stringify(data);
var options = {
"method" : "POST",
"contentType" : "application/json",
"payload" : payload
};
console.time("POST time");
var response = UrlFetchApp.fetch(url, options);
console.timeEnd("POST time");
var resp = response.getContentText();
respTString = resp;
var spellchecked = JSON.parse(respTString);
var style = {};
for (var k in pagewords){
if (pagewords.hasOwnProperty(k)) {
if (spellchecked.hasOwnProperty(k)) {
if (spellchecked[k].substr(0, 1) == "1") {
style[DocumentApp.Attribute.FOREGROUND_COLOR] = "#000000";
}
if (spellchecked[k].substr(0, 1) == "0") {
style[DocumentApp.Attribute.FOREGROUND_COLOR] = "#FF0000";
}
if (spellchecked[k].substr(0, 1) == "4") {
style[DocumentApp.Attribute.FOREGROUND_COLOR] = "#0000FF";
}
if (pagewordsOrigOffset[k] < alltext.length) {
body.editAsText().setAttributes(pagewordsOrigOffset[k], pagewordsOrigOffset[k] + pagewordsOrig[k].length, style);
}
}
}
}
console.timeEnd("function time");
return {
"pagewords" : pagewords,
"pagewordsOrig" : pagewordsOrig,
"pagewordsOrigOffset" : pagewordsOrigOffset,
"spellchecked" : spellchecked
}
}
I have a graph with two "series", only when one has value and the other does not, it breaks and has no background. How to fix it? I've tried several posts from various sites, videos and also read the documentation a lot. No example seems to work, so I don't know exactly what to do. If it has value it looks like it looks normal.
Javascript
function initChartVendas() {
am4core.useTheme(am4themes_animated);
let chart = am4core.create(this.chartElement.nativeElement, am4charts.XYChart);
chart.data = this.generatechartData();
chart.numberFormatter.numberFormat = "'R$ ' #,###.##";
// Create axes
let dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.startLocation = 0.5;
dateAxis.endLocation = 0.5;
dateAxis.extraMax = null;
dateAxis.extraMin = null;
dateAxis.dateFormats.setKey('day', 'dd');
// Create value axis
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.baseValue = 900;
// Create series
let series = chart.series.push(new am4charts.LineSeries());
series.name = 'Pagos ';
series.dataFields.valueY = 'valor';
series.dataFields.dateX = 'dia';
series.strokeWidth = 3;
series.tooltipText = '{valueY.value}';
series.fillOpacity = 0.1;
series.tensionX = 0.8;
series.tensionY = 1;
series.fill = am4core.color('#5770ef');
series.stroke = am4core.color('#5867dd');
// Create series 2
if (this.dataCancelados) {
let seriesCancelados = chart.series.push(new am4charts.LineSeries());
seriesCancelados.name = 'Cancelados ';
seriesCancelados.dataFields.valueY = 'cancelado';
seriesCancelados.dataFields.dateX = 'dia';
seriesCancelados.strokeWidth = 3;
seriesCancelados.tooltipText = '{valueY.value}';
seriesCancelados.fillOpacity = 0.1;
seriesCancelados.tensionX = 0.8;
seriesCancelados.tensionY = 1;
seriesCancelados.fill = am4core.color('#f96191');
seriesCancelados.stroke = am4core.color('#fd397a');
}
// Add cursor
chart.cursor = new am4charts.XYCursor();
chart.cursor.behavior = 'none';
series.tooltip.getFillFromObject = false;
series.tooltip.adapter.add('x', (x, target) => {
// #ts-ignore
const valueY = series.tooltip.tooltipDataItem.valueY;
if (valueY < 0) {
series.tooltip.background.fill = chart.colors.getIndex(4);
} else {
series.tooltip.background.fill = am4core.color('#5770ef');
}
return x;
});
if (this.dataCancelados) {
chart.legend = new am4charts.Legend();
}
}
Image 1
Image 2
I found the solution the dates should be ordered. Before they were not, for example, the 20th came before the 16th. That's why the problem. My ordering solution is this (it only matters the day)
chartData.sort((v1, v2) => (v1.dia.getDate() > v2.dia.getDate() ? 1 : -1));
The columns that have (maximum Additional Hedging) are sometimes on the chart and sometimes not this is determined on the dynamic data that can be changed constantly via a draggable bar above the chart.
I want to be able have the legend of the chart to remove these items when they aren't on the and bring them back when they are on the chart.
This is currently working on the AmCharts3 version of the chart but I am upgrading them.
var chart = am4core.create("fxExposureHedgingChart", am4charts.XYChart);
let title = chart.titles.create();
title.text = this.props.title;
title.fontSize = 25;
title.marginBottom = 30;
chart.data = this.props.dataProvider;
chart.dateFormatter.inputDateFormat = "yyyy-MM-dd";
chart.orderByField = "name"
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "category";
categoryAxis.title.text = "Time";
categoryAxis.renderer.startLocation = 0;
categoryAxis.renderer.cellStartLocation = 0.10;
categoryAxis.renderer.cellEndLocation = 0.90;
categoryAxis.renderer.labels.template.location = 0.5 ;
categoryAxis.renderer.labels.template.wrap = false;
categoryAxis.renderer.labels.template.truncate = false;
categoryAxis.renderer.minGridDistance = 30;
categoryAxis.layout = "horizontal";
// Create value axis
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.title.text = "Amount " + this.state.displayCurrency;
valueAxis.max = 140000;
valueAxis.min = 0;
let valueAxis2 = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis2.title.text = "Rate";
valueAxis2.renderer.opposite = true;
valueAxis2.min = 1.1000;
valueAxis2.max = 1.4500;
let createColumnSeries = () => {
var series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.valueY = "exposure";
series.dataFields.categoryX = "category";
series.name = "Forecasted Cashflows";
series.yAxis = valueAxis;
series.columns.template.width = am4core.percent(85);
series.stacked = false;
series.tooltip.dy = -8;
series.tooltip.pointerOrientation = "vertical";
var columnTemplate = series.columns.template;
columnTemplate.column.fillOpacity = 0.8;
columnTemplate.tooltipText = "{name} ({category}): {valueY}";
columnTemplate.tooltipY = 0;
var columnHoverState = columnTemplate.column.states.create("hover");
columnHoverState.properties.fillOpacity = 1;
columnHoverState.properties.cornerRadiusTopLeft = 35;
columnHoverState.properties.cornerRadiusTopRight = 35;
return series;
}
let createLineSeries1 = () => {
var series = chart.series.push(new am4charts.LineSeries());
series.dataFields.valueY = "achieveableRate";
series.dataFields.categoryX = "category";
series.name = "Achieveable Rate";
series.tooltipText = "{valueY.value}";
series.strokeWidth = 2;
series.yAxis = valueAxis2;
let bullet = series.bullets.push(new am4charts.Bullet());
let square = bullet.createChild(am4core.Rectangle);
square.width = 5;
square.height = 5;
square.horizontalCenter = "middle";
square.verticalCenter = "middle";
series.bullets.getIndex(0).tooltipText = "{name}: {valueY}";
return series;
}
let getDealGraphInfo = (classIds,data) =>{
let maxHedgingClassIDs = classIds.map( id => (data.reduce((accum, row) => accum+ (row["maxAmount_"+id]),0)) > 0 ? id: null);
let maxAmounts = maxHedgingClassIDs.map((id, index) => {
if(id === null){} else {
let HedgingSeries = chart.series.push(new am4charts.ColumnSeries());
HedgingSeries.dataFields.valueY = "maxAmount_" + id;
HedgingSeries.dataFields.categoryX = "category";
HedgingSeries.name = classIDtoDisplayName(id).replace(/FX\s/,"") + " (Maximum Additional Hedging)";
HedgingSeries.tooltip.dy = -8;
HedgingSeries.tooltip.pointerOrientation = "vertical";
HedgingSeries.columns.template.width = am4core.percent(70);
HedgingSeries.id = classIDtoDisplayName(id).replace(/\s/g,"").toLowerCase() + "_maxAmount";
HedgingSeries.stacked = true;
var columnTemplate = HedgingSeries.columns.template;
columnTemplate.column.fillOpacity = 0.8;
columnTemplate.tooltipText = HedgingSeries.name;
columnTemplate.tooltipY = 0;
}}).filter(c => c);
return classIds.map((id, index) => {
let Series = chart.series.push(new am4charts.ColumnSeries());
Series.dataFields.valueY = "amount_" + id;
Series.dataFields.categoryX = "category";
Series.name = classIDtoDisplayName(id).replace(/FX\s/,"");
Series.tooltip.dy = -8;
Series.tooltip.pointerOrientation = "vertical";
Series.columns.template.width = am4core.percent(70);
Series.id = classIDtoDisplayName(id).replace(/\s/g,"").toLowerCase();
Series.strokewidth = 1;
Series.stacked = true;
var columnTemplate = Series.columns.template;
columnTemplate.column.fillOpacity = 0.8;
columnTemplate.tooltipText = Series.name;
columnTemplate.tooltipY = 0;
return Series;
}).concat(maxAmounts).sort((a,b) => (a.name < b.name ? -1:1));
}
let budgetRateName = getBudgetRateName(this.props.budgetRate);
getDealGraphInfo(this.props.dealClassIds,this.state.data).concat(createColumnSeries(),
createLineSeries1(),
createLineSeries2(),
createLineSeries3(),
createLineSeries4(budgetRateName)
).sort((a,b) => (a.name < b.name ? -1:1));
chart.legend = new am4charts.Legend();
chart.legend.itemContainers.template.paddingTop = 5;
chart.legend.itemContainers.template.paddingBottom = 5;
chart.legend.labels.template.wrap = true;
chart.legend.labels.template.maxWidth = 350;
chart.legend.labels.template.truncate = true;
chart.legend.useDefaultMarker = true;
chart.exporting.menu = new am4core.ExportMenu();
var plugin = chart.plugins.push(new am4plugins_annotation.Annotation());
var markerTemplate = chart.legend.markers.template
markerTemplate.width = 10;
markerTemplate.height = 10;
this.setState({chart: chart})
}
componentDidUpdate(oldProps, prevState){
if (oldProps.dataProvider !== this.props.dataProvider){
this.state.chart.data = this.props.dataProvider;
}
}
componentWillUnmount() {
if (this.chart) {
this.chart.dispose();
}
}
getDealGraphInfo are the columns that are being added/removed. Note, the object always has these columns but when they have no value it is set to "null" otherwise it has a value.
When I drag the bar above the chart I am using componentDidUpdate to change the data on the chart. So I believe the solution could have something to do in here.
I have found a temp fix where in componentDidUpdate I dispose the chart and recreate the whole chart when I receive new props. But this is very laggy when using the slider. I would prefer to just have the legend/data in the chart update, than needing to recreate the chart every time.
I have created an Excel document using javascript and I open that document but I want it to open/save as PDF not as excel document I have tried many different ways but it didn't work can anyone help.
This is the code that I use.
function exportToExcelPdf() {
input_box = confirm("Експортирај во Microsoft Excel?");
if (input_box == true) {
var xlApp = new ActiveXObject("Excel.Application");
xlApp.DisplayAlerts = false;
var xlBook = xlApp.Workbooks.Add();
xlBook.worksheets("Sheet1").activate;
var XlSheet = xlBook.activeSheet;
XlSheet.Name = "Sheet Name";
var myRange = XlSheet.Range("A1:L1");
myRange.merge();
myRange.value = "Something Some Text";
myRange.font.size = 14;
myRange.font.bold = "true";
myRange.HorizontalAlignment = -4108;
myRange.interior.colorindex = "37";
var myRange = XlSheet.Range("A3:L3");
myRange.merge();
myRange.value = "Something Some Text";
myRange.font.size = 11;
myRange.font.bold = "true";
myRange.HorizontalAlignment = -4108;
myRange.interior.colorindex = "37";
var dt = document.getElementById('<%= GridView1.ClientID %>');
for (var y = 1; y < dt.rows.length; y++)
// detailsTable is the table where the content to be exported is
{
for (var x = 0; x < dt.rows(y).cells.length; x++) {
XlSheet.Cells(y + 18, x + 1) = dt.rows(y).cells(x).innerText;
XlSheet.Cells(y + 18, x + 1).HorizontalAlignment = -4108;
}
}
//autofit the columns
XlSheet.columns.autofit;
xlApp.ActiveWindow.DisplayGridlines = false;
// Make visible:
xlApp.visible = true;
xlApp.DisplayAlerts = true;
CollectGarbage();
//xlApp.Quit();
}
}
[EDIT] Full application available at: http://bit.ly/1CGZzym
I'm receiving the error:
Uncaught TypeError: Cannot set property '0' of undefined
with the following code. I believe it is due to my not declaring the child array of the 2D array properly but I am really confused as to where I should be declaring this. Any ideas would be excellent.
// Create an array for the tiles we're about to draw
var tileArray = []
is declared out side of the function.
I assume it is because I am trying to create child elements within each [col] so I guess I need to declare each col number somewhere but nothing I attempt seems to be working.
function drawGrid()
{
// Draw diamond grid
var col = 0;
var row = 0;
topTileX = (viewWidth/2);
topTileY = 0;
var nextX = 0;
var nextY = 0;
var getCols = 0;
while (topTileX > -1)
{
tileArray[col][row] = new DiamondTile(topTileX, topTileY, tileWidth, true, col, row);
tileArray[col][row].draw();
while (tileArray[col][row].xPos + tileArray[col][row].tileWidth < (viewWidth) + tileWidth)
{
col++;
nextX = tileArray[col-1][row].xPos + tileArray[col-1][row].tileWidth / 2;
nextY = tileArray[col-1][row].yPos + tileArray[col-1][row].tileHeight / 2;
tileArray[col][row] = new DiamondTile(nextX, nextY, tileWidth, true, col, row);
tileArray[col][row].draw();
if (col == getCols)
{
break;
}
}
row++;
getCols = col;
col = 0;
topTileX = topTileX - tileWidth/2;
topTileY = topTileY + tileHeight/2;
}
};
For the purpose of demonstration, the DiamondTile function is as follows:
function DiamondTile(xPos,yPos,width,interactive,myCol,myRow)
{
// Set x and y position for this sprite
this.xPos = xPos;
this.yPos = yPos;
this.myRow = myRow;
this.myCol = myCol;
// Used for AI pathfinding
this.isObstacle = false;
this.isStart = false;
this.isEnd = false;
this.gValue = 0;
this.hValue = 0;
this.fCost = 0;
this.tileWidth = width;
this.tileHeight = this.tileWidth/2;
var self = this;
// Create sprite
this.spriteObj = new PIXI.Sprite(grass);
this.spriteObj.interactive = interactive;
this.spriteObj.anchor = new PIXI.Point(0.5,0);
this.spriteObj.hitArea = new PIXI.Polygon([
new PIXI.Point(0,0),
new PIXI.Point(100,50),
new PIXI.Point(0,100),
new PIXI.Point(-100,50)
]);
this.spriteObj.mouseover = function()
{
if (self.spriteObj.tint == 0xFFFFFF)
{
self.spriteObj.tint = 0xA7E846;
}
text2.setText(self.myCol + "," + self.myRow + " Start: " + self.isStart);
}
this.spriteObj.mouseout = function()
{
if (self.spriteObj.tint == 0xA7E846)
{
self.spriteObj.tint = 0xFFFFFF;
}
}
this.spriteObj.click = function()
{
if (startStage === true)
{
startStage = false;
self.isStart = true;
self.spriteObj.tint = 0x1AFF00;
text.setText("Now select an end point");
endStage = true;
return true;
}
if (endStage === true)
{
endStage = false;
self.isEnd = true;
self.spriteObj.tint = 0xFF0000;
text.setText("Now place some obstacles");
obsStage = true;
return true;
}
if (obsStage ===true)
{
self.isObstacle = true;
self.spriteObj.tint = 0x3B3B3B;
text.setText("Press 'C' to calculate path");
return true;
}
}
};
That is a multi-dimensional array and you have not initialized the first dimension array correctly. In the while loop you have to initialize the first dimension to be able to access a second dimension element with an index:
while (topTileX > -1)
{
if (tileArray[col] == null)
tileArray[col] = [];
tileArray[col][row] = new DiamondTile(topTileX, topTileY, tileWidth, true, col, row);
tileArray[col][row].draw();
// omitted other code for brevity
}
Javascript arrays are dynamic and it's enough to initialize the first dimension array elements in this case. You don't have to initialize the individual items in the second dimension.
Update: here is a fiddle with working code http://jsfiddle.net/0qbq0fts/2/
In addition your semantics is wrong. By the book, the first dimension of a 2-dimensional array should be rows, and the second dimension should be columns.
You have to explicit create the elements representing the second dimension, e.g.:
function make2DArray(rows, cols) {
var r = Array(rows);
for (var i = 0; i < rows; ++i) {
r[i] = Array(cols);
}
return r;
}
If you don't know in advance how many columns, just use this:
function make2DArray(rows) {
var r = Array(rows);
for (var i = 0; i < rows; ++i) {
r[i] = [];
}
return r;
}
The individual rows can each have independent lengths, and will grow as you add values to them.
Similarly, if you just need to add a new (empty) row, you can just do:
tileArray.push([]);
This should probably me a comment, but SO has crashed on my side. JavaScript might be throwing an exception on your stated line, but the problem may be with the 'DiamondTile' function.