0
votes

I'm using Animate CC (the erstwhile Flash CC) to do some ads that I'm exporting in HTML5 format (<canvas> and CreateJS stuff). They're working quite nicely overall.

I have a formatted number, in a Static Text box, like so: 5,000,000 and I want to tween it to, say, 20,000, over the course of 30 frames. I want to tween the same text to 5,000 and 1,000,000 and so on throughout the course of my scene.

In my limited Animate CC experience, I've managed to avoid using any Javascript, but I imagine that I will need to now. So, my question: how do I do this?


My thoughts on ways of doing this:

Since I'm using CreateJS, which has the TweenJS library as part of it, maybe I can just use that for tweening? Make little Actions at different points of my timeline? Not sure how all that works, and a lot of the references online are for ActionScript 3 or even AS2. Sample code would be appreciated.

If I do get into Javascript, there's the question of how I would do the number formatting. I could tween the number as 5000000 -> 20000 and on each frame update insert commas, that's one way of doing it. But to make matters more complex, these ads are going to be translated, and different locales come into the mix. So in English you get 5,000,000 and in German would you have 5.000.000, of course.

Since we're talking Javascript in the browser, I'm aware of the method Number.prototype.toLocaleString() which does the following:

The toLocaleString() method returns a string with a language sensitive representation of this number.

That seems like it would do the trick, but then I have to worry about browser compatibility and what happens if I don't specify a locale. Ideally, since the German ads would only be displayed to people who had a German locale on their browser/OS, I could just call the method without any locale specified, and it would read it off the user's computer. I suppose it's possible to have the scenario where a German person is seeing an English ad, but I'm not that worried about it.

However, on the MDN page for toLocaleString() it has this big warning about earlier versions of FF defaulting to Western Arabic digits, so it makes me doubt the use of the method entirely.


Finally, I have the interesting fact that the translators will almost certainly take 5,000,000 and convert it into 5.000.000 for German. So it may be possible to avoid the use of toLocaleString() since I'll already have localized text. So if it were possible to write a simple Javascript function that could tween arbitrarily formatted numbers, I think that would do the trick. Perhaps:

  • Take the starting number and rip formatting out of it, save it
  • Tween the number
  • On each frame update, inject the formatting back into it

Probably not that hard from a JS perspective, but where I get stumped is how the heck I would do this in Animate/Flash and/or with CreateJS/TweenJS?

2

2 Answers

2
votes

As far as tweening a formatted number using TweenJS, you can just tween a non-formatted number, and on "change", create a formatted version to do what you need:

createjs.Tween.get(obj, {loop:true})
    .to({val:10000}, 4000)
  .to({val:0}, 4000)
  .on("change", formatNumber);

function formatNumber(event) {
    // Round and format
    var formattedNumber = (obj.val|0).toLocaleString();
}

Here is a simple fiddle: http://jsfiddle.net/m3req5g5/

1
votes

Although Lanny gave some good data, I wanted to lay out exactly what I ended up doing to get this working.

First, you need to get a reference to the object you're going to be tweening in some way. When you make an Action in Flash and write Javascript, this is bound to the Stage, or to the MovieClip or Graphic that you're editing: http://createjs.com/html5ads/#Scope

You can access objects using their instance names which are defined in Flash on the Properties of the object, once you've placed it on the Stage. Some sources online said that it was based on the symbol name or some such, but I haven't found that to be the case.

// Get a reference to the object you want to tween
var obj = this.anInstanceName;

Note that, if you want to access something that's inside a MovieClip, you will need to give your MovieClip on the stage an instance name, and then go inside the MovieClip and give an instance name to your target object. Then you can just walk down the hierarchy:

// Get a reference to the nested object you want to tween.
var obj = this.movieClipInstanceName.nestedInstanceName;

Now you can tween any numeric property of the object in question. For me, because I wanted to tween the text, I set an additional property on the object and tweened that, then formatted and copied it over into the text property as I went along.

It was useful to be able to specify how many frames the tween lasted, rather than the milliseconds, so I passed the useTicks flag.

obj.counter = 0;
createjs.Tween.get(obj, {useTicks: true})
    .to({counter: 100}, 30) // <- 30 frames, this number is ms without useTicks
    .on("change", formatNumber);

function formatNumber(event) {
    obj.text = obj.counter.toLocaleString();
}

The above is generally applicable. Otherwise, here's the working code that I ended up using. It should be able to be dropped into a Flash Action in an HTML5 Canvas project and just work.

// Figures for tweening
var textStart = "2,000";
var textEnd = "6,000,000";

// Locate our target text box
var target = this.myTextBox; // replace "myTextBox" with your instance name

// Get our formatting data and so on
var data = this.getFormatData(textStart);

// Set up the text box
target.number = data.number;
target.text = textStart;

// Get the raw number we're tweening to
var endNumber = this.getFormatData(textEnd).number;

// Create the tween
createjs.Tween.get(target, {useTicks: true})
  .to({number:endNumber}, 30)
  .on("change", format);

//Formatting function, gets called repeatedly for each frame
function format(event) {
    var rounded = Math.round(target.number);
    var formatted = formatNumber(rounded, data.format);
    target.text = formatted;
}

// UTILITY FUNCTIONS:

// Takes "###,###,###" or somesuch
// Returns a raw number and a formatting object
function getFormatData(formattedNumber) {

    var toString = "" + formattedNumber; // in case it's not a string
    var reversed = toString.split('').reverse(); // get a reversed array

    // now walk (backwards) through the array and remove formatting
    var formatChars = {};
    for (var i = reversed.length-1; i >= 0; i--) {
        var c = reversed[i];
        var isnum = /^\d$/.test(c);
        if (!isnum) {
            formatChars[i] = c;
            reversed.splice(i, 1);
        }
    }

    // get the actual number
    var number = parseInt(reversed.reverse().join(''));

    // return the data
    var result = {number: number, format: formatChars};
    return result;
}

// Takes a raw number and a formatting object and produces a formatted number
formatNumber(number, format) {
    var toString = '' + number;
    var reversed = toString.split('').reverse();
    var index = 0;
    while (index < reversed.length) {
        if (format[index]) {
            reversed.splice(index, 0, format[index]);
        }
        index++;
    }

    var finished = reversed.reverse().join('');
    return finished;
}

This fiddle demos the formatting and has a bit more of an explanation in the comments.

There are other ways of doing this, for sure, such as toLocaleString(), but this fit my exact requirements. Hopefully it'll help someone else.