merging old data with new data - json

I want the old nodes in the force layout to keep their position/momentum/fixedness, when i update the graph with new nodes.
The update adds and removes nodes and links, but the server only sends {name: _}, and doesn't know about the rest, i.e. {x: _, y: _, px: _, py: _, fixed: _}.
Now, I'm manually merging each:
var names = {};
// stores old nodes, indexed by _.name
function merge(nodes) {
for (var i=0; i < nodes.length; i++) {
var next = nodes[i];
var prev = names[nodes[i].name]; // defaults to null
var node = $.extend(true, {}, next, prev); // merge old into new
nodes[i] = node;
names[node.name] = node;
}
return nodes;
}
d3.json(function(error, graph){
merge(graph.nodes)
force.nodes(graph.nodes);
...
}
Is there a better way to do this? Maybe some d3 function that takes the two data (i.e. the old and the new) and outputs one (to be used as the new), that's called by the data join? selection.data() only takes a key.
This example replaces the nodes, rather than merging them.
Related: Problems adding and removing nodes in a force-layout using d3.js

D3 doesn't provide any functionality to do what you're looking for, but you've already implemented merge, which does the same thing. Basically, you need to modify the data structures that you gave to force.links() and force.nodes(). There is no need to tell the force layout to use them explicitly after making the changes.

Related

D3 Line Generator Handling Multiple Arrays

I have 3 arrays within a JSON file of the following structure:
I am trying to parse a JSON file of coordinate data into something that can be read by D3 path/line generators. I first had to find a way to ensure the values were actual numbers and not strings. A full discussion can be found here:
D3/JS mapping a JSON data callback
That discussion prompted me to not only consider formatting the JSON data via .map() to numbers, but also consider a nested/zipped format that the line generator can make sense of. That is really the target I've been after all along. As depicted above, My JSON has 3 arrays, xs, ys and id. id only governs color, and takes 1 of 3 values (0,1,2). I was recommended this approach:
var obj = raw_json[0];
var data = obj.id.map((id, i) => [+id, +obj.xs[i], +obj.ys[i]]);
My line generator function is:
var valueLine = d3.svg.line()
.x(function(d) {return xScale(d.xs);})
.y(function(d) {return yScale(d.ys)});
However I am getting tens of thousands of errors, and unfortunately I do not have that much experience with parsing related issues and I am not sure how to proceed.
Full block & JSON here.
Glad to see you took my advice on restructuring your data as we are moving in the right direction. I suggested that you should convert your three separate arrays into one array of individual arrays per point to make the use of the line generator more easy and to eliminate the need for cross-array reads to collect data for the points.
This time, though, you are not accessing your values correctly. By using function(d) { return xScale(d.xs); } you are assuming that your points were represented by objects having properties xs and ys. My suggested approach however got rid of these properties by storing the information into arrays. There are basically two ways around this:
Adjust you path generator's .x() and .y() callbacks while keeping your data structure.
var obj = raw_json[0];
var data = obj.id.map((id, i) => [+id, +obj.xs[i], +obj.ys[i]]);
// Remember, that d is a point's array [id, x, y]
var valueLine = d3.svg.line()
.x(function(d) { return xScale(d[1]); })
.y(function(d) { return yScale(d[2]); });
If you prefer to store your points' data in objects instead, another solution would be to adjust how your data is built.
// Structure data into an array of objects {id, x, y}
var obj = raw_json[0];
var data = obj.id.map((id, i) => ({
id: +id,
x: +obj.xs[i],
y: +obj.ys[i]
}));
// Keep your code as d now has properties x and y.
var valueLine = d3.svg.line()
.x(function(d) { return xScale(d.x); })
.y(function(d) { return yScale(d.y); });
I think you aren't modeling correctly the data to use to use with data(data).enter() and/or d3.svg.line(). As you defined your valueLine function it expects an array of objects with xs and ys properties and you are feeding it with an array of arrays.
Try it out manually to see how it works
valueLine([{xs: 1, ys: 1}, {xs: 3, ys: 5}, {xs: 12, ys: 21}])
and see the generated svg path:
"M100,400L300,-400L1200,-3600"
So maybe you can change how you are preparing your data for something like :
var data = obj.id.map((id,i) => ({id: +id, xs:+obj.xs[i], ys: +obj.ys[i]}));

Using objects instead of arrays

I've spent nearly 1 week to learn working with objects instead of arrays. I had thought it was easy to call them and created some objects and set their properties. However I can't access them now, I tried this:
function onBoxClick(event:MouseEvent):void {
var str:String = event.currentTarget.name;
trace(str);
str = str.substring(str.indexOf("_") + 1);
trace(getChildByName("copy_" + str)); // trying to trace an object by name
}
My question is if there's a practical way of dealing with objects, otherwise what's the purpose of using them.
Edit: Here's my function that I use to create movieclips and other things:
function addBoxes(isUpdate:Boolean):void {
var copyOne:Object = getReadOnlyValues();
copyOne.name = "copy_" + num;
// Set default mc1 settings
var settings1:Object = copyOne.mc1Settings;
for(var num2:String in settings1) {
copyOne.mc1[num2] = settings1[num2];
}
// Set default mc1text settings
var settings2:Object = copyOne.mc1TextSettings;
for(var num3:String in settings2) {
copyOne.mc1Text[num3] = settings2[num3];
}
copyOne.mc1.x = nextXpos;
copyOne.mc1.name = "captionBox_" + num;
addChild(copyOne.mc1);
copyOne.mc1.addEventListener(MouseEvent.CLICK, onCaptionClick);
copyOne.mc1Text.name = "captionBoxText_" + num;
copyOne.mc1.addChild(copyOne.mc1Text);
// ---------------------------------------------------------------
// Set default mc2 settings
var settings4:Object = copyOne.mc2Settings;
for(var num4:String in settings4) {
copyOne.mc2[num4] = settings4[num4];
}
// Set default mc2text settings
var settings5:Object = copyOne.mc2TextSettings;
for(var num5:String in settings5) {
copyOne.mc2Text[num5] = settings5[num5];
}
copyOne.mc2.x = nextXpos;
copyOne.mc2.y = copyOne.mc1.height;
copyOne.mc2.name = "box2_" + num;
addChild(copyOne.mc2);
copyOne.mc2Text.name = "box2BoxText_" + num;
copyOne.mc2.addChild(copyOne.mc2Text);
copyOne.mc2.addEventListener(MouseEvent.CLICK, onBoxClick);
if (num / subunits is int) {
trace (num);
// createMc("normalBox", true);
}
nextXpos = nextXpos + copyOne.mc2.width;
// traceObj(copyOne);
// traceObj(getReadOnlyValues());
}
I called this function in a loop so I created many movieclips. Now I can't access objects' properties and their childen (e.g textfield).
Objects I have on stage: Movieclips and textfields
Where they come from: The function above
What I'm trying to do with them: Tracing movieclips and textfields (that are holded by objects) to change their children (textfield) text
What happens instead of what I expect: Trace code outputs undefined instead of giving me object type trace(getChildByName("copy_" + str)); // trying to trace an object by name
Is there a practical way of accessing an object whose name is "copy_1" and its property whose name is "box2_1" (movieclip)?
One problem I see is the "copyOne" object has been created within the scope of "addBoxes", so it will no longer exist outside of this function.
Another is you're trying to access an Object via getChildByName, which only addresses displayObjects of the displayObjectContainer you are calling from.
If you want to loosely keep track of variables with things like Objects or MovieClips (which are both dynamic-style objects that let you add properties to them as you wish), just use MovieClips to house your values. The movieClips, being on the stage, will be retained in memory until removed from the displayList (stage).
Also, check out the Dictionary, a sort of key/value based way of storing collections of objects.
Better yet, if you use strongly-typed custom objects (creating your own classes to extend MCs, and adding your own public or private methods and values), there are benefits such as using Vectors (fancy, fast arrays that are compatible with any Object type you choose).
I don't really know if I understood your question or not, but as #ozmachine said in his answer, you can not use getChildByName, instead I think that you can take a look on this, may be it can help :
var container:DisplayObjectContainer = this;
function getReadOnlyValues():Object {
return {
mc1: new box(),
mc1: {
name: 'mc1_',
alpha: 1,
x: 0,
y: 0,
width: 30,
height: 25
},
mc1Text: new TextField(),
mc1Text: {
text: 'test',
x: 0,
y: 0,
selectable: false,
multiline: false,
wordWrap: false
}
}
};
// create 5 objects
for(var i=0; i<5; i++){
container['copy_'+i] = getReadOnlyValues();
var obj:Object = getObjectByName('copy_'+i);
obj.mc1.alpha = 1;
obj.mc1.x = 0;
obj.mc1.y = 50 * i;
obj.mc1.width = 100;
obj.mc1.addChild(obj.mc1Text);
obj.mc1Text.text = 'test_' + i;
addChild(obj.mc1);
}
// get object by name
function getObjectByName(name:String):Object {
return container[name];
}
// change the text of the 4th button
stage.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void {
var obj:Object = getObjectByName('copy_3');
obj.mc1Text.text = 'new text';
})
Array and Object are both data structures.
Data means some form of information.
Data structure means some form of information being stored in a certain way.
Array and Object are two different ways to store information.
Arrays identify data with integer numbers.
An integer number to identify a single element of an array is called an index
Arrays are ideal to represent a list of similar things that belong to each other.
var names:Array = ["John", "Paul", "George", "Ringo"];
This often means that the elements of an array are of the same type, like in the example above.
But they don't have to:
var numbers:Array = [42, "twenty-five", "XIIV"];
For the above examples it's easy to answer the questions "What are the names of the four beatles?", "What different representations of numbers did you stumble upon during your trip through the historic town?". Other questions are harder or impossible to answer. "What Roman numerals did you stumble upon in the historic town?"
Objects identify data with names.
A name to identify a single element of an object is called a property
Objects are ideal to represent a list of dissimilar things that belong to each other.
var paula:Object = {age:37, name:"Paula", hairColor:0x123456};
This often means that the elements of an object are of different type, like in the example above.
But they don't have to:
var car:Object = {manufacturer:"Porsche", color:"red", sound:"wroooooom", soundOfDriver:"weeeeeeeeeeee"};
Considering this, let's take a look at your code and see how it applies.
The big picture is that you have a function addBoxes that you call multiple times. As one function should have one purpose, this function will do something similar every time it is executed. Uh-Oh: "similar". Whatever the result of this function is, it should go into an array. Each call to that function would be an element of the array. You can see this clearly on your use of "num" to identify whatever is happening in your current run of the function.
What data is present in your function?
copyOne
mc1
mc1Text
mc2
mc2Text
copyOne is a troublemaker here and what causes your confusion. It's trying to do everything at once and therefore you are not able to think clearly about when to use a Array and when Object. One would call it a god object. And that's not a good object to have around.
Your choice for variable names is very bad.
You choose super generic names like "mcX" only to later add a name property to it that describes what it truly is.
But even that doesn't hold true for whatever "Box2" is supposed to be.
Choose names so that it'S easy to understand what something in your code is.
It looks like you created all or parts of this structure jsut for this question and therefore lacked meaningful names.
I highly recommend that you do not learn by such made up projects. But from the real world.
I will therefore impose the following goal:
mc1 and mc1Text represent a caption
mc2 and mc2Text represent a content
With all this, I ask again:
What data is present in your function?
captionBox
captionText
contentBox
contentText
Both caption and content consist of a box and a text.
These are different things, so caption and content are each an object with properties "box" and "text"
One could think that due to this similarity, they both should go into an array.
But I beg to differ. A caption and a text are not the same thing. You deal with captions and texts differently. Walking on the streets you might catch a big caption in the news quickly, but not a lengthy text. That's why each of them should be a property of the object that's created in the function.
Here's somewhat of a conclusion:
var allBoxes:Array = []; // array to store the similar results of every function call
function createBoxes():void
{
var boxes:Object = {};
//the box consists of caption & content, both bying of the same type, but are containing different data
boxes.caption = {box:{}, text:{}}; //caption
boxes.content = {box:{}, text:{}}; //content
allBoxes.push(boxes);
}
This is it. That's how and why I would model your data with objects and arrays.
But it doesn't end here. My conclusion lacks a lot of the code you posted.
While the above is mostly language independent, the missing code is specific to Actionscript and not just on how to model data. It's as follows...
As3 is object oriented.
This is good, because the above conclusion has a lot of objects in it.
To define how some object is/does/moves/farts/etc, one creates classes.
The following changes take place (for reasons out of the scope of this answer):
createBoxes (formerly known as addBoxes) calls the constructor of
a class "CaptionAndContent" that extends Sprite.
There's no more need to explicitely create an object "boxes" as the constructor does exactly that.
The caption and content will not have a property "box", because
they can be the box themselves. This is exactly how it's done in the
code of the question. The default settings are set in the constructors of their classes.
Here's reduced snippet of code that hopefully illustrates how the classes could look like.
Each class should be in its own file, with the necessary imports, package block and the additional functionality that you did not specify in your question.
public class CaptionAndContent extends Sprite
{
private var caption:Caption;
private var content:Content;
public function CaptionAndContent(captionText:String = "", contentText:String = "")
{
caption = new Caption(captionText);
addChild(caption);
content = new Content(contentText);
content.y = caption.height;
addChild(content);
}
}
public class ClickableBoxWithText extends Sprite
{
protected var textField:TextField;
public function ClickableBoxWithText(text:String = "")
{
textField = new TextField();
textField.text = text;
addChild(textField);
addEventListener(MouseEvent.CLICK, onClick);
}
protected function onClick(mouseEvent:MouseEvent):void
{
//override this in a sublclass
}
}
public class Caption extends ClickableBoxWithText
{
public function Caption(text:String = "")
{
super(text);
// apply all the default settings of caption here.
}
}
public class Content extends ClickableBoxWithText
{
public function Content(text:String = "")
{
super(text);
// apply all the default settings of content here.
}
}
Using them would look something like this:
var allBoxes:Array = []; // array to store the similar results of every function call
function createBoxes():void
{
var captionAndContent:CaptionAndContent = new CaptionAndContent("This is the caption...", "...for this content");
captionAndContent.x = nextXpos;
addChild(captionAndContent);
allBoxes.push(captionAndContent);
}
Last but not least, the identification problem in the click handler.
Your question already contains the answer:
event.currentTarget
That's the reference to the object that was clicked on.
In my code it would be
mouseEvent.currentTarget
This identifies the object already. It's pointless to look up one of its properties (its name for example) in order to search all the objects for that name, just to identify the same object that you already had to identify (without a name) in order to get the name.
You aren't identifying the objects by name anyway. What differs between the names and what supposedly makes them unique is a number at their end. As pointed out in this answer, this is what's called an index and the thing you are trying to identify with it should go into an array. In my example codes, this is allBoxes.

Knockout - Creating Model from existing JSON data for Select All checkbox list

That's a pretty long winded statement.
I'm building a faceted search which implements WebAPI in .Net and utilizes Knockout on the front end. My search response includes two lists of objects, the Resources (object with data for presentation) and Resource Facets (array of strings).
\"ResourceFacets\": [\r\n \"Book\",\r\n \"Video\",\r\n \"DVD\",\r\n \"eBook\",\r\n \"Audio\"\r\n ]\r\n}"
My ViewModel contains both the facets and the resources along with a presentation object to handle a custom row count:
function ViewModel() {
this.facets = ko.observableArray(results.ResourceFacets);
this.resources = ko.observableArray(results.ResourceResults);
this.resourceRows = ko.computed(function() {
var rows = [],
rowIndex = 0,
itemsPerRow = 2;
var resourceList = this.resources();
for (var index = 0; index < resourceList.length; index++) {
if (!rows[rowIndex]) {
rows[rowIndex] = [];
}
rows[rowIndex].push(resourceList[index]);
if (rows[rowIndex].length == itemsPerRow) {
rowIndex++;
}
}
return rows;
});
};
This allowed me to create a dynamic list of checkboxes to handle the facets and also display the resource results. What I'm trying to do now is add a Select All checkbox which will, by default, select all the boxes. From other examples I've seen, my understanding is that I need an observable property, something like "Selected", on that ResourceFacet. I just feel like that is too much that the API needs to know about my presentation.
So my question is how can I avoid having to add a "selected" bool value to the ResourceFacets but still be able to select all checkboxes or deselect the "All" checkbox when a user deselects a facet?
You can keep the list of booleans necessary to track the selection on a separate member of your view model, in addition to facets and resources. Just create a new observableArray of booleans of the same size of facets and bind those values to the checkboxes.
Another solution is to create the objects necessary to bind the checkboxes on the fly, based on results.ResourceFacets, keeping your API clean. For example:
var realModel = [];
for (var i = 0; i < results.ResourceFacets; i++) {
realModel.push({ name: results.ResourceFacets[i], chkBoxVal: ko.observable(false) });
}
this.facets = ko.observableArray(realModel);

AdvancedDataGrid total sum of branch nodes

Introduction:
I have an AdvancedDataGrid displaying hierarchical data illustrated by the image below:
The branch nodes "Prosjekt" and "Tiltak" display the sum of the leaf nodes below.
Problem: I want the root node "Tavle" to display the total sum of the branch nodes below. When i attempted to do this by adding the same SummaryRow the sum of the root node was not calculcated correctly(Every node's sum was calculated twice).
dg_Teknikktavles = new AutoSizingAdvancedDataGrid();
dg_Teknikktavles.sortExpertMode="true";
dg_Teknikktavles.headerHeight = 50;
dg_Teknikktavles.variableRowHeight = true;
dg_Teknikktavles.addEventListener(ListEvent.ITEM_CLICK,dg_TeknikktavlesItemClicked);
dg_Teknikktavles.editable="false";
dg_Teknikktavles.percentWidth=100;
dg_Teknikktavles.minColumnWidth =0.8;
dg_Teknikktavles.height = 1000;
var sumFieldArray:Array = new Array(context.brukerList.length);
for(var i:int = 0; i < context.brukerList.length; i++)
{
var sumField:SummaryField2 = new SummaryField2();
sumField.dataField = Ressurstavle.ressursKey + i;
sumField.summaryOperation = "SUM";
sumFieldArray[i] = sumField;
}
var summaryRow:SummaryRow = new SummaryRow();
summaryRow.summaryPlacement = "group";
summaryRow.fields = sumFieldArray;
var summaryRow2:SummaryRow = new SummaryRow();
summaryRow2.summaryPlacement = "group";
summaryRow2.fields = sumFieldArray;
var groupField1:GroupingField = new GroupingField();
groupField1.name = "tavle";
//groupField1.summaries = [summaryRow2];
var groupField2:GroupingField = new GroupingField();
groupField2.name = "kategori";
groupField2.summaries = [summaryRow];
var group:Grouping = new Grouping();
group.fields = [groupField1, groupField2];
var groupCol:GroupingCollection2 = new GroupingCollection2();
groupCol.source = ressursTavle;
groupCol.grouping = group;
groupCol.refresh();
Main Question: How do i get my AdvancedDataGrid's (dg_Teknikktavles) root node "Tavle" to correctly display the sum of the two branch nodes below?
Side Question: How do i add a red color to the numbers of the root node's summary row that exceed 5? E.g the column displaying 8 will exceed 5 in the root node's summary row, and should therefore be marked red
Thanks in advance!
This is a general answer, without code examples, but I had to do the same just couple of days ago, so my memory is still fresh :) Here's what I did:
Created a class A to represent an item renderer data, extended it from Proxy (I had field names defined at run time), and let it contain a collection of values as it's data member. Once accessed through flash_proxy::getPropery(fieldName) it would find a corresponding value in the data member containing the values and return it. Special note: implement IUID, just do it, it'll save you couple of days of frustration.
Extended A in B, added a children property containing ArrayCollection of A (don't try to experiment with other collection types, unless you want to find yourself examining tons of framework code, trust me, it's ugly and is impossible to identify as interesting). Let B override flash_proxy::getPropery - depending of your compiler this may, or may not be possible, if not possible - call some function from A.flash_proxy::getPropery() that you can override in B. Let this function query every instance of A, which is a child of B, asking the same thing, as DataGrid itself would, when building item renderers - this way you would get the total.
When creating a data provider. Create an ArrayCollection of B (again, don't try to experiment with other collections--unless you are ready for lots of frustration). Create Hierarchical data that uses this array collection as a source.
Colors - that's what you use item renderers for, just look up any tutorial on using item renderers, that must be pretty basic.
In case someone else has the same problem:
The initial problem that everything was summed twice, was the result of using the same Array of SummaryField2 (sumFieldArray in the code) for both grouping fields(GropingField2 tavle and kategori)
The Solution to the main question: was to create a new array of summaryfields for the root node(in my intial for loop):
//Summary fields for root node
var sumFieldRoot:SummaryField2 = new SummaryField2();
sumFieldRoot.dataField = Ressurstavle.ressursKey + i;
sumFieldRoot.summaryOperation = "SUM";
sumFieldArrayRoot[i] = sumFieldRoot;
Answer to the side question:
This was pretty much as easy as pointed out by wvxyw. Code for this solution below:
private function summary_styleFunction(data:Object, col:AdvancedDataGridColumn):Object
{
var output:Object;
var field:String = col.dataField;
if ( data.children != null )
{
if(data[field] >5){
output = {color:0xFF0000, fontWeight:"bold"}
}
else {
output = {color:0x006633, fontWeight:"bold"}
}
//output = {color:0x081EA6, fontWeight:"bold", fontSize:14}
}
return output;
}

What's the fastest way to search a very long list of words for a match in actionscript 3?

So I have a list of words (the entire English dictionary).
For a word matching game, when a player moves a piece I need to check the entire dictionary to see if the the word that the player made exists in the dictionary. I need to do this as quickly as possible. simply iterating through the dictionary is way too slow.
What is the quickest algorithm in AS3 to search a long list like this for a match, and what datatype should I use? (ie array, object, Dictionary etc)
I would first go with an Object, which is a hash table (at least, storage-wise).
So, for every word in your list, make an entry in your dictionary Object and store true as its value.
Then, you just have to check if a given word is a key into your dictionary to know whether the word the user has choosen is valid or not.
This works really fast in this simple test (with 10,000,000 entries):
var dict:Object = {};
for(var i:int = 0; i < 10000000; i++) {
dict[i] = true;
}
var btn:Sprite = new Sprite();
btn.graphics.beginFill(0xff0000);
btn.graphics.drawRect(0,0,50,50);
btn.graphics.endFill();
addChild(btn);
btn.addEventListener(MouseEvent.CLICK,checkWord);
var findIt:Boolean = true;
function checkWord(e:MouseEvent):void {
var word:String;
if(findIt) {
word = "3752132";
} else {
word = "9123012456";
}
if(dict[word]) {
trace(word + " found");
} else {
trace(word + " not found");
}
findIt = !findIt;
}
It takes a little longer to build the dictionary, but lookup is almost instantaneous.
The only caveat is that you will have to consider certain keys that will pass the check and not necessarily be part of your words list. Words such as toString, prototype, etc. There are just a few of them, but keep that in mind.
I would try something like this with your real data set. If it works fine, then you have a really easy solution. Go have a beer (or whatever you prefer).
Now, if the above doesn't really work after testing it with real data (notice I've build the list with numbers cast as strings for simplicity), then a couple of options, off the top of my head:
1) Partition the first dict into a set of dictionaries. So, instead of having all the words in dict, have a dictionary for words that begin with 'a', another for 'b', etc. Then, before looking up a word, check the first char to know where to look it up.
Something like:
var word:String = "hello";
var dictKey:String = word.charAt(0);
// actual check
if(dict[dictKey][word]) {
trace("found");
} else {
trace("not found");
}
You can eventually repartition if necessary. I.e, make dict['a'] point to another set of dictionaries indexed by the first two characters. So, you'll have dict['a']['b'][wordToSearch]. There are a number of possible variations on this idea (you'd also have to come up with some strategy to cope with words of two letters, such as "be", for instance).
2) Try a binary search. The problem with it is that you'll first have to sort the list, upfront. You have to do it just once, as it doesn't make sense to remove words from your dict. But with millions of words, it might be rarther intensive.
3) Try some fancy data structures from open source libraries such as:
http://sibirjak.com/blog/index.php/collections/as3commons-collections/
http://lab.polygonal.de/ds/
But again, as I said above, I'd first try the easiest and simpler solution and check if it works against the real data set.
Added
A simple way to deal with keywords used for Object's built-in properties:
var dict:Object = {};
var keywordsInDict:Array = [];
function buildDictionary():void {
// let's assume this is your original list, retrieved
// from XML or other external means
// it contains "constructor", which should be dealt with
// separately, as it's a built-in prop of Object
var sourceList:Array = ["hello","world","foo","bar","constructor"];
var len:int = sourceList.length;
var word:String;
// just a dummy vanilla object, to test if a word in the list
// is already in use internally by Object
var dummy:Object = {};
for(var i:int = 0; i < len; i++) {
// also, lower-casing is a good idea
// do that when you check words as well
word = sourceList[i].toLowerCase();
if(!dummy[word]) {
dict[i] = true;
} else {
// it's a keyword, so store it separately
keywordsInDict.push(word);
}
}
}
Now, just add an extra check for built-in props in the checkWords function:
function checkWord(e:MouseEvent):void {
var word:String;
if(findIt) {
word = "Constructor";
} else {
word = "asdfds";
}
word = word.toLowerCase();
var dummy:Object = {};
// check first if the word is a built-in prop
if(dummy[word]) {
// if it is, check if that word was in the original list
// if it was present, we've stored it in keywordsInDict
if(keywordsInDict.indexOf(word) != -1) {
trace(word + " found");
} else {
trace(word + " not found");
}
// not a built-in prop, so just check if it's present in dict
} else {
if(dict[word]) {
trace(word + " found");
} else {
trace(word + " not found");
}
}
findIt = !findIt;
}
This isn't specific to ActionScript, but a Trie is a suitable data structure for storing words.