AS3 Switch conditions being ignored - actionscript-3

So recently I've been working on a game in Flash, using the program Flash Builder and the Flixel engine. I hit a strange snag though, one of the first things that runs is a parser I made to create the screen for each level based on a 2D array in a .txt file, and for some reason, the final letter in each line is being ignored in the switch statement that decides what that index stands for.
This is the part I'm having issues with (what happens in each condition is irrelevant, I just left it in for context, but they all behave correctly):
var row:int;
var column:int;
var currentColor:int = 0;
for (row = 0; row < m_levelData.length; row++) {
for (column = 0; column < m_levelData[0].length; column++) {
var offset:FlxPoint = new FlxPoint(0, 0);
var thisIndex:String = m_levelData[row][column];
//trace("This Line is " + m_levelData[row]);
trace("Current index is " + thisIndex);
//trace(row + " " + column);
switch(thisIndex) {
case Statics.GRID_BIN:
offset.y = (spaceSize.y / Statics.SPRITE_SCALE - BinFront.SIZE.y / Statics.SPRITE_SCALE) / 2;
offset.x = (spaceSize.x/Statics.SPRITE_SCALE - BinFront.SIZE.x/Statics.SPRITE_SCALE) / 2;
var color:uint;
if (m_colors.length < currentColor) {
color = Statics.COLOR_BLACK;
trace("No color found");
} else {
color = m_colors[currentColor];
currentColor++;
trace("Color is " + color);
}
makeBin(spaceSize.x * column + offset.x + levelOffset.x, spaceSize.y * row + offset.y + levelOffset.y, color);
break;
case Statics.GRID_BUILDER:
offset.y = (spaceSize.y/Statics.SPRITE_SCALE - BuilderMain.SIZE.y/Statics.SPRITE_SCALE)/2
offset.x = (spaceSize.x/Statics.SPRITE_SCALE - BuilderMain.SIZE.x/Statics.SPRITE_SCALE) / 2;
makeBuilder(spaceSize.x * column + offset.x + levelOffset.x, spaceSize.y * row + offset.y + levelOffset.y);
break;
case Statics.GRID_CONVEYOR:
var length:int = 0;
if (column == 0 || m_levelData[row][column - 1] != Statics.GRID_CONVEYOR) {
for (i = column; i < m_levelData[row].length; i++) {
if (m_levelData[row][i] == Statics.GRID_CONVEYOR) {
length++;
} else {
break;
}
}
offset.y = (spaceSize.y/Statics.SPRITE_SCALE - Statics.GRID_SIZE.y/Statics.SPRITE_SCALE)/2
offset.x = (spaceSize.x/Statics.SPRITE_SCALE - Statics.GRID_SIZE.x/Statics.SPRITE_SCALE) / 2;
makeConveyor(spaceSize.x * column + offset.x + levelOffset.x, spaceSize.y * row + offset.y + levelOffset.y, length);
}
break;
default:
trace("Nothing at this index, it was " + thisIndex);
}
Statics.GRID_BIN, Statics.GRID_CONVEYOR, and Statics.GRID_BUILDER are all constant strings ("a", "b", and "c" respectively), and I know that this all should be working because it was working before I switched to the parser. Now, your immediate response to that is that the problem is my parser, but I have suspicions that something is a little screwy other than that. Before the switch, I print the value of thisIndex..(trace("Current index is " + thisIndex);), and whenever it is the last letter in a line that was parsed (using split(","), even when it matches one of the switch conditions, the default condition is run and nothing happens.
Has anyone else seen something like this, or am I just making a really dumb mistake?

When you parse and compare strings loaded from a .txt you have to deal with various "hidden" characters. At line endings you might run into CR (\r) LF(\n) or both or the other way round.
It can get a bit fiddly to find out which applies to your system or .txt.
In the end you could probably make it work using String.replace() .
This has been discussed for example here: How do I detect and remove "\n" from given string in action script?
Apart from this it's hard to judge whether there's something wrong with your parser.
Your use of the switch{}-statement itself looks fine and should be working.
If you need to debug the code try feeding it with a hardcoded const :String instead of the .txt-file. Then set a breakpoint (in Flash Builder by double-clicking the line number next to the switch-statemen) and step through it line by line.

Related

Google Sheets Script: Get A1Notation For Each Cell In Named Range

The function I'm working on does an optimisation of the force required by a rudder foil (stabilator) on an America's Cup AC75 yacht, to balance the longitudinal moments of the sail forces. This is done by altering the angle of the stabilator, from initially providing an upward (positive) force, then as sail forces increase, the stabilator has to create a downward (negative) force.
The stabilator angles are in a column, and when it is changed, other calculations work out if it balances the sail forces. If it doesn't, there is a "Delta" column that indicates a value whether the rudder foil needs to provide more/less force, via it's angle.
I tried using Named Ranges for the column of Angles, and another for Delta. The code should iterate through adding a bit more (or less) angle to the stabilator, and each time, check the Delta. My code is wrong.
What I need to do is get the Angle value of one Angle cell, incrementally increase/decrease it, then setValue of that cell. Next is to getValue of the corresponding Delta cell, to see if I'm at Zero (plus/minus a small amount). If not, via a while loop, I increase/decrease the Angle again, setValue, recheck the Delta, and so on.
My problem is that I do not know how to get the A1Notation of each cell in the Named Ranges as I iterate through it, so that I can repeatedly getValue and setValue for just the single cell at a time?
function c_Optimise_Stabilator() {
// Author: Max Hugen
// Date: 20102-12-07
// Purpose: Attempt to optimise Stab Angle to balance with Stab Target Force
/* WARNING: This function may eventually cause a circular reference, so ensure there is an "escape".
* May occur if other optimisation functions are also run?
* OPTIMISATION: Try in this order:
* 1. Optimise Transverse Moments
* 2. Optimise Stabilator
* 3. Check, and if necessary, rerun Optimise Transverse Moments
* 4. Check, and if necessary, rerun Optimise Stabilator
* If Optimise Stabilator returns all Angles OK, we're good!
*/
const ui = SpreadsheetApp.getUi();
const ss = SpreadsheetApp.getActiveSpreadsheet();
// var target_sheet = "Analysis";
// var sheet = ss.getSheetByName("Analysis");
var msg = ""; // gather input for Logger
var s = ""; // short info for testing alerts, then added to msg
var log = true; // whether to output msg to the Logger
// angle range
const maxAngle = 2.0, minAngle = -0.2, incAngle = 0.1;
//limits
var maxLoopIterations=10; // to avoid excessive iterations
var minDelta=0.02; // to limit the minimum size of Delta tested
// counters
var i=0, loopIterations=0;
// Original and New Vals
var originalAngle=0.0, newAngle=0.0, originalDelta=0.0, newDelta=0.0;
// ranges used in getRange - variable here, for testing. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/*
var sAngle = "Optimise_Stab_Angle";
var sDelta = "Optimise_Stab_Delta";
var sAngle = "Analysis!AF14:AG14"; // 1 rows (but only 2 cols now) - failing
var sDelta = "Analysis!AM14:AM14";
*/
var sAngle = "Analysis!AF10:AG13"; // 4 rows
var sDelta = "Analysis!AM10:AM13";
var rAngle = ss.getRange(sAngle);
var dAngle = rAngle.getValues();
var rDelta = ss.getRange(sDelta);
var dDelta = rDelta.getValues();
originalAngle = Math.round(dAngle[i][1]*1000)/1000;
originalDelta = Math.round(dDelta[i][0]*1000)/1000;
var iLen = rAngle.getNumRows();
for(i=0; i<iLen; i++){
s = "";
newAngle = originalAngle;
s += " Vb: " + dAngle[i][0] + "; Original Angle: " + originalAngle + "; originalDelta: " + originalDelta + "\r\n";
// if stabilator force is below target (negative Delta), increase stab angle unless at maxAngle.
if ( Math.abs(Math.round(dDelta[i][0]*100)/100) > minDelta && originalAngle < maxAngle) {
loopIterations = 1;
while (newAngle <= maxAngle) {
try {
if ( newAngle == maxAngle ) {
s += " MAX.ANGLE: newDelta" + newDelta + "; originalDelta: " + originalDelta;
break;
}
// Have to update the Delta range, to check if Delta still too high/low
var rDelta = ss.getRange(sDelta);
var dDelta = rDelta.getValues();
newDelta = Math.round(dDelta[i][0]*1000)/1000;
if ( Math.abs(Math.round(newDelta*100)/100) < minDelta ) {
s += " COMPLETED: newDelta" + newDelta + "; originalDelta: " + originalDelta;
break;
}
if ( loopIterations > maxLoopIterations ) {
s += " EXCEEDED maxLoopIterations of " + maxLoopIterations;
break;
}
} catch(err) {
Logger.log (c_ErrorToString (err) + "\n" + "Vb: " + dAngle[i][0]);
}
newAngle += incAngle; // for some reason, this may STILL produce a number like 1.400000003 (example only)
newAngle = Math.round(newAngle*1000)/1000;
// set the new angle
dAngle[i][1] = newAngle;
// update the iteration count
loopIterations ++
}
}
// if stabilator force is above target (positive Delta), decrease stab angle unless at minAngle.
else if ( Math.abs(Math.round(dDelta[i][0]*100)/100) > minDelta && originalAngle > minAngle) {
loopIterations = 1;
while (newAngle >= minAngle) {
try {
if ( newAngle == minAngle ) {
s += " MIN.ANGLE: newDelta" + newDelta + "; originalDelta: " + originalDelta;
break;
}
// Have to update the Delta range, to check if Delta still too high/low
var rDelta = ss.getRange(sDelta);
var dDelta = rDelta.getValues();
newDelta = Math.round(dDelta[i][0]*1000)/1000;
if ( Math.abs(Math.round(newDelta*100)/100) < minDelta ) {
s += " COMPLETED: newDelta" + newDelta + "; originalDelta: " + originalDelta;
break;
}
if ( loopIterations > maxLoopIterations ) {
s += " EXCEEDED maxLoopIterations of " + maxLoopIterations;
break;
}
} catch(err) {
Logger.log (c_ErrorToString (err) + "\n" + "Vb: " + dAngle[i][0]);
}
newAngle -= incAngle; // for some reason, this may STILL produce a number like 1.400000003 (example only)
newAngle = Math.round(newAngle*1000)/1000;
// set the new angle
dAngle[i][1] = newAngle;
// update the iteration count
loopIterations ++
}
}
msg += s + "\r\n";
}
rAngle.setValues(dAngle);
msg = "c_Optimise_Stabilator \r\n" + msg
Logger.log(msg);
ui.alert(msg);
}
Found the way to get the cell A1Notation, use getCell() on the range, then getA1Notation.
cellA1 = range.getCell(1, 1).getA1Notation();

Copied Image from Google Document Paragraph inserted twice

I'm trying to combine several Google Document inside one, but images inside the originals documents are inserted twice. One is at the right location, the other one is at the end of the newly created doc.
From what I saw, these images are detected as Paragraph by the script.
As you might see in my code below, I've been inspired by similar topics found here.
One of them suggested searching for child Element inside the Paragraph Element, but debugging showed that there is none. The concerned part of the doc will always be inserted with appendParagraph method as the script is not able to properly detect the image.
This is why the other relevant topic I found cannot work here : it suggested inserting the image before the paragraph itself but it cannot detects it.
Logging with both default Logger and console.log from Stackdriver will display an object typed as Paragraph.
The execution step by step did not show displayed any loop calling the appendParagraph method twice.
/* chosenParts contains list of Google Documents name */
function concatChosenFiles(chosenParts) {
var folders = DriveApp.getFoldersByName(folderName);
var folder = folders.hasNext() ? folders.next() : false;
var parentFolders = folder.getParents();
var parentFolder = parentFolders.next();
var file = null;
var gdocFile = null;
var fileContent = null;
var offerTitle = "New offer";
var gdocOffer = DocumentApp.create(offerTitle);
var gfileOffer = DriveApp.getFileById(gdocOffer.getId()); // transform Doc into File in order to choose its path with DriveApp
var offerHeader = gdocOffer.addHeader();
var offerContent = gdocOffer.getBody();
var header = null;
var headerSubPart = null;
var partBody= null;
var style = {};
parentFolder.addFile(gfileOffer); // place current offer inside generator folder
DriveApp.getRootFolder().removeFile(gfileOffer); // remove from home folder to avoid copy
for (var i = 0; i < chosenParts.length; i++) {
// First retrieve Document to combine
file = folder.getFilesByName(chosenParts[i]);
file = file.hasNext() ? file.next() : null;
gdocFile = DocumentApp.openById(file.getId());
header = gdocFile.getHeader();
// set Header from first doc
if ((0 === i) && (null !== header)) {
for (var j = 0; j < header.getNumChildren(); j++) {
headerSubPart = header.getChild(j).copy();
offerHeader.appendParagraph(headerSubPart); // Assume header content is always a paragraph
}
}
fileContent = gdocFile.getBody();
// Analyse file content and insert each part inside the offer with the right method
for (var j = 0; j < fileContent.getNumChildren(); j++) {
// There is a limit somewhere between 50-100 unsaved changed where the script
// wont continue until a batch is commited.
if (j % 50 == 0) {
gdocOffer.saveAndClose();
gdocOffer = DocumentApp.openById(gdocOffer.getId());
offerContent = gdocOffer.getBody();
}
partBody = fileContent.getChild(j).copy();
switch (partBody.getType()) {
case DocumentApp.ElementType.HORIZONTAL_RULE:
offerContent.appendHorizontalRule();
break;
case DocumentApp.ElementType.INLINE_IMAGE:
offerContent.appendImage(partBody);
break;
case DocumentApp.ElementType.LIST_ITEM:
offerContent.appendListItem(partBody);
break;
case DocumentApp.ElementType.PAGE_BREAK:
offerContent.appendPageBreak(partBody);
break;
case DocumentApp.ElementType.PARAGRAPH:
// Search for image inside parapraph type
if (partBody.asParagraph().getNumChildren() != 0 && partBody.asParagraph().getChild(0).getType() == DocumentApp.ElementType.INLINE_IMAGE)
{
offerContent.appendImage(partBody.asParagraph().getChild(0).asInlineImage().getBlob());
} else {
offerContent.appendParagraph(partBody.asParagraph());
}
break;
case DocumentApp.ElementType.TABLE:
offerContent.appendTable(partBody);
break;
default:
style[DocumentApp.Attribute.BOLD] = true;
offerContent.appendParagraph("Element type '" + partBody.getType() + "' from '" + file.getName() + "' could not be merged.").setAttributes(style);
console.log("Element type '" + partBody.getType() + "' from '" + file.getName() + "' could not be merged.");
Logger.log("Element type '" + partBody.getType() + "' from '" + file.getName() + "' could not be merged.");
}
}
// page break at the end of each part.
offerContent.appendPageBreak();
}
}
The problem occurs no matter how much files are combined, using one is enough to reproduce.
If there's only one image in the file (no spaces nor line feed around) and if the "appendPageBreak" is not used afterward, it will not occur. When some text resides next to the image, then the image is duplicated.
One last thing : Someone suggested that it is "due to natural inheritance of formatting", but I did not find how to prevent that.
Many thanks to everyone who'll be able to take a look at this :)
Edit : I adapted the paragraph section after #ziganotschka suggestions
It is very similar to this subject except its solution does not work here.
Here is the new piece of code :
case DocumentApp.ElementType.PARAGRAPH:
// Search for image inside parapraph type
if(partBody.asParagraph().getPositionedImages().length) {
// Assume only one image per paragraph (#TODO : to improve)
tmpImage = partBody.asParagraph().getPositionedImages()[0].getBlob().copyBlob();
// remove image from paragraph in order to add only the paragraph
partBody.asParagraph().removePositionedImage(partBody.asParagraph().getPositionedImages()[0].getId());
tmpParagraph = offerContent.appendParagraph(partBody.asParagraph());
// Then add the image afterward, without text
tmpParagraph.addPositionedImage(tmpImage);
} else if (partBody.asParagraph().getNumChildren() != 0 && partBody.asParagraph().getChild(0).getType() == DocumentApp.ElementType.INLINE_IMAGE) {
offerContent.appendImage(partBody.asParagraph().getChild(0).asInlineImage().getBlob());
} else {
offerContent.appendParagraph(partBody.asParagraph());
}
break;
Unfortunately, it stills duplicate the image. And if I comment the line inserting the image (tmpParagraph.addPositionedImage(tmpImage);) then no image is inserted at all.
Edit 2 : it is a known bug in Google App Script
https://issuetracker.google.com/issues/36763970
See comments for some workaround.
Your image is embedded as a 'Wrap text', rather than an Inline image
This is why you cannot retrieve it with getBody().getImages();
Instead, you can retrieve it with getBody().getParagraphs();[index].getPositionedImages()
I am not sure why exactly your image is copied twice, but as a workaround you can make a copy of the image and insert it as an inline image with
getBody().insertImage(childIndex, getBody().getParagraphs()[index].getPositionedImages()[index].copy());
And subsequently
getBody().getParagraphs()[index].getPositionedImages()[index].removeFromParent();
Obviously, you will need to loop through all the paragraphs and check for each one either it has embedded positioned images in order to retrieve them with the right index and proceed.
Add your PositionedImages at the end of your script after you add all your other elements. From my experience if other elements get added to the document after the the image positioning paragraph, extra images will be added.
You can accomplish this my storing a reference to the paragraph element that will be used as the image holder, and any information (height, width, etc) along with the blob from the image. And then at the end of your script just iterate over the stored references and add the images.
var imageParagraphs = [];
...
case DocumentApp.ElementType.PARAGRAPH:
var positionedImages = element.getPositionedImages();
if (positionedImages.length > 0){
var imageData = [];
for each(var image in positionedImages){
imageData.push({
height: image.getHeight(),
width: image.getWidth(),
leftOffset: image.getLeftOffset(),
topOffset: image.getTopOffset(),
layout: image.getLayout(),
blob: image.getBlob()
});
element.removePositionedImage(image.getId());
}
var p = merged_doc_body.appendParagraph(element.asParagraph());
imageParagraphs.push({element: p, imageData: imageData});
}
else
merged_doc_body.appendParagraph(element);
break;
...
for each(var p in imageParagraphs){
var imageData = p.imageData
var imageParagraph = p.element
for each(var image in imageData){
imageParagraph.addPositionedImage(image.blob)
.setHeight(image.height)
.setWidth(image.width)
.setLeftOffset(image.leftOffset)
.setTopOffset(image.topOffset)
.setLayout(image.layout);
}
}

Can TeeChart draw value label at cursor point?

I'm looking for HTML5 chart that can show value at cursor point like this
http://www.tradeviewforex.com/forex-blog/tip-14-how-to-use-the-crosshair-on-metatrader-4
I found StockChartX can do this
http://developer.modulusfe.com/stockchartx_html5/
(click Draw -> Annotation)
but I can effort this price :P
Thanks for answer!
Ps. Sorry for my bad english.
Something similar can be done with the Annotation tool in TeeChart HTML5. See the example here
Also, you can format a tool tip, if that is the need.
tip = new Tee.ToolTip(Chart1);
Chart1.tools.add(tip);
tip.format.font.style = "11px Verdana";
tip.render = "canvas";
tip.onshow = function (tool, series, index) {
scaling = 2;
poindex = index;
}
tip.onhide = function () {
scaling = 0;
poindex = -1;
}
tip.ongettext = function (tool, text) {
var txt = tool.currentSeries.title + ":\n" + "Value: " + text + tool.currentSeries.units + "\n" + jsonDataArray[0].evDataTime[tool.currentIndex] + " (ms)";
model.MouseOverY(text + tool.currentSeries.units);
model.MouseOverX(jsonDataArray[0].evDataTime[tool.currentIndex] + " (ms)");
model.SelectedSeries(tool.currentSeries.title);
return txt;
}

typeof fails on trigger object property

I am trying to add an dumpObject function to a Spreadsheet Container bound Script.
Ideally, it is for visibility into variables passed through triggers.
I can run it all day long from within the Script Editor, but when setup as either an onEdit event or onEdit Installible trigger, it dies with no error.
I did some trial and error toast messages and confirmed the code in dumpObject is being executed from the Trigger.
If you take this code below, setup onEdit2 as an installable trigger, you might see it.
To see it work as a Trigger, uncommment the first line //e of onEdit2.
Best I can figure, is something in the e object coming from the trigger that is not quite what is expected of an object?
This test should be limiting the maxDepth to 5, so I don't think I'm hitting the 1000 depth limit.
UPDATE: The problem is calling typeof on the trigger object properties. For example, "typeof e.user" reports the following error: Invalid JavaScript value of type
Thanks,
Jim
function onEdit2(e) {
//e = {fish:{a:"1",b:"2"},range:SpreadsheetApp.getActiveSpreadsheet().getActiveRange(),B:"2"};
Browser.msgBox(typeof e);
Browser.msgBox("U:" + Utilities.jsonStringify(e));
e.range.setComment("Edited at: " + new Date().toTimeString());
Browser.msgBox("ShowOBJ:"+dumpObject(e, 5));
}
function dumpObject(obj, maxDepth) {
var dump = function(obj, name, depth, tab){
if (depth > maxDepth) {
return name + ' - Max depth\n';
}
if (typeof obj === 'object') {
var child = null;
var output = tab + name + '\n';
tab += '\t';
for(var item in obj){
child = obj[item];
if (typeof child === 'object') {
output += dump(child, item, depth + 1, tab);
} else {
output += tab + item + ': ' + child + '\n';
}
}
}
return output;
};
return dump(obj, '', 0, '');
}
You're not getting quite what you expect from the event object. If you throw in:
for(var q in e) {
Logger.log(q + " = " + e[q])
}
and then check the View->Logs menu item in the script editor you get
source = Spreadsheet
user = <your user>
So, checking the docs, you can come up with this as an alternative to your e.range.setComment("Edited at: " + new Date().toTimeString());:
e.source.getActiveSheet().getActiveCell().setComment("Edited at: " + new Date().toTimeString());
note: you can debug an error like you were (secretly) getting by wrapping your statement in a try catch like so:
try {
e.range.setComment("Edited at: " + new Date().toTimeString());
} catch (ex) {
Logger.log(ex);
}
and then checking the logs as mentioned above (or dumping to Browser.msgBox(), if you prefer).
This might not be a great "answer" but it works.
I found that replacing typeof with Object.prototype.toString.call(obj) I got something usable.
Of note, the e object returns [object Object] but the properties (e.user) return [object JavaObject]
if (Object.prototype.toString.call(obj).indexOf("object") != -1) {
var child = null;
var output = tab + name + '\n';
tab += '\t';
for(var item in obj){
child = obj[item];
if (Object.prototype.toString.call(child).indexOf("object") != -1) {
output += dump(child, item, depth + 1, tab);

Large fonts on canvas take long time in Chrome

has anyone noticed or found a solution to the problem I've been experiencing? It takes a long time to render large fonts (>100px) in Chrome on the canvas using fillText(). I need to have a much faster frame rate, but once the fonts get big it take like a second to load each frame. In firefox it runs well though...
UPDATE:
Here is the pertinent code that is running in my draw() function which runs every 10 milliseconds on interval. If anything pops out to you, that would be great. I'll try to profiler thing though, thanks.
g.font = Math.floor(zoom) + "px sans-serif";
g.fillStyle = "rgba(233,233,245," + (ZOOM_MAX-zoom*(zoom*0.01))/(ZOOM_MAX) + ")";
for (h=0; h<76; h++)
{
h_offset = 2.75*h*Math.floor(zoom);
// only render if will be visible, because it tends to lag; especially in Chrome
hpos = Math.floor(half_width + std_offset + h_offset);
if (hpos > (-half_width)-h_offset && hpos < WIDTH+h_offset)
{
g.fillText(1950+h, hpos, anchor_y - 0);
}
}
g.font = "600 " + Math.floor(zoom/40) + "px sans-serif";
g.fillStyle = "rgba(233,233,245," + (ZOOM_MAX-zoom*(zoom*0.0001))/(ZOOM_MAX) + ")";
for (h=0; h<76; h++)
{
h_offset = 2.75*h*Math.floor(zoom);
hpos = Math.floor(half_width + std_offset + h_offset);
if (hpos > (-half_width)-h_offset && hpos < WIDTH+h_offset)
{
// see if we should bother showing months (or will it be too small anyways)
if (zoom/40 > 2)
{
// show months
for (i=0; i<12; i++)
{
i_offset = 0.175*i*zoom;
ipos = Math.floor(WIDTH/2 + std_offset + i_offset + h_offset) + 10;
if (ipos > -half_width && ipos < WIDTH)
{
g.fillText(months[i], ipos, anchor_y - 20);
}
}
}
}
}
g.font = "600 " + Math.floor(zoom/350) + "px sans-serif";
g.fillStyle = "rgba(233,233,245," + (ZOOM_MAX-zoom/5)/(ZOOM_MAX*2.25) + ")";
for (h=0; h<76; h++)
{
h_offset = 2.75*h*Math.floor(zoom);
// only render if will be visible, because it tends to lag; especially in Chrome
hpos = Math.floor(half_width + std_offset + h_offset);
if (hpos > (-half_width)-h_offset && hpos < WIDTH+h_offset)
{
// see if we should bother showing months (or will it be too small anyways)
if (zoom/40 > 2)
{
// show months
for (i=0; i<12; i++)
{
i_offset = 0.175*i*zoom;
ipos = Math.floor(WIDTH/2 + std_offset + i_offset + h_offset) + 10;
// see if we should bother showing days (or will it be too small anyways)
if (zoom/350 > 2)
{
// show days
for (j=0; j<31; j++)
{
j_offset = 0.005*j*zoom + zoom*0.005;
jpos = Math.floor(half_width + std_offset + j_offset + i_offset + h_offset);
if (jpos > -half_width && jpos < WIDTH)
{
g.fillText(days[i][j], jpos, anchor_y - 20);
selected_days += 'm: '+i+', d: '+j+' | ';
}
}
}
}
}
}
}
We'd need a lot more information, I'm not convinced that drawing a large font is actually whats causing the performance issues. Drawing such a large font works extremely quickly on my machines for any browser that I've tried.
The first thing you should do is open up the Chrome profiler and then run the code, and see if it is actually the ctx.fillText call that is taking up the time. I imagine its actually something else.
It's possible you are calling something too much, like setting ctx.font over and over unnecessarily. Setting ctx.font on some browsers actually takes significantly longer to do than calls to fillRect! If your font changes in the app you can always cache.
Here's a test back from October: http://jsperf.com/set-font-perf
As you can see, in many versions of Chrome setting the font unnecessarily doubles the time it takes! So make sure you set it as little as possible (with caching, etc).