Overall context: I have a db of cross-references among pages in a wiki space, and want an incrementally-growing visualization of links.
I have working code that shows clusters of labels as you mouseover. But when you move away, rather than hiding all the labels, I want to keep certain key labels (e.g. the centers of clusters).
I forked an existing example and got it roughly working.
info is at http://webseitz.fluxent.com/wiki/WikiGraphBrowser
near the bottom of that or any other page in that space, in the block that starts with "BackLinks:", at the end you'll find "Click here for WikiGraphBrowser" which will launch a window with the interface
equivalent static subset example visible at http://www.wikigraph.net/static/d3/cgmartin/WikiGraphBrowser/:
code for that example is at https://github.com/BillSeitz/WikiGraphBrowser/blob/master/js/wiki_graph.js
Code that works at removing all labels:
i = j = 0;
if (!bo) { //bo=False - from mouseout
//labels.select('text.label').remove();
labels.filter(function(o) {
return !(o.name in clicked_names);
})
.text(function(o) { return ""; });
j++;
}
Code attempting to leave behind some labels, which does not work:
labels.forEach(function(o) {
if (!(d.name in clicked_names)) {
d.text.label.remove();
}
I know I'm just not grokking the d3 model at all....
thx
The problem comes down to your use of in to search for a name in an array. The Javascript in keyword searches object keys not object values. For an array, the keys are the index values. So testing (d.name in clicked_names) will always return false.
Try
i = j = 0;
if (!bo) { //bo=False - from mouseout
//labels.select('text.label').remove();
labels.filter(function(o) {
return (clicked_names.indexOf(o.name) < 0);
})
.text(function(o) { return ""; });
j++;
}
The array .indexOf(object) method returns -1 if none of the elements in the array are equal (by triple-equals standards) to the parameter. Alternatively, if you are trying to support IE8 (I'm assuming not, since you're using SVG), you could use a .some(function) test.
By the way, there's a difference between removing a label and just setting it's text content to the empty string. Which one to use will depend on whether you want to show the text again later. Either way, just be sure you don't end up with a proliferation of empty labels clogging up your browser.
Related
Experienced programmer playing around with Gamemaker2 Studio.
Trying to draw some random squares on the screen using a 2D array to store the "map"
Step 1 : declare a 2D array MyMap[25,25] this works
Step 2 : Set 100 random locations in Map[]=1 this works
I get a crash when I try to look up the values I have stored in the array.
Its crashing with:
**Execution Error - Variable Index [3,14] out of range [26,14] **
So it looks like it is trying to read 26 element, when you can see from my code the for next loop only goes to 20 and the array bound is 25.
Oddly enough it does the first two loops just fine?
Looking like a bug, I've spent so much time trying to work it out, anyone got an idea what is going on?
var tx=0;
var ty=0;
var t=0;
MyMap[25,25]=99; **// Works**
for( t=1; t<100; t+=1 ) **// Works**
{
MyMap[random(20),random(15)]=1
}
for( tx=1; tx<20; tx+=1 )
{
for( ty=1; ty<15; ty+=1 )
{
show_debug_message(string(tx) + ":" + string(ty))
t = MyMap[tx,ty]; /// **<---- Crashes Here**
if t=1 then {draw_rectangle(tx*32,ty*32,tx*32+32,ty*32+32,false) }
}
}
The line MyMap[random(20),random(15)]=1 does not initialize values in the entire array, creating a sparse array(where some elements do not exist).
The line MyMap[25,25]=99;
Should read:
for( tx=1; tx<20; tx+=1 )
{
for( ty=1; ty<15; ty+=1 )
{
MyMap[tx,ty]=99;
}
}
This will pre-initialize the all of the array values to 99. Filling out the array.
Then you can randomly assign the ones. (You will probably get less than 100 ones the due to duplicates in the random function and the random returning zeros.)
You should have the above code in the Create Event, or in another single fire or controlled fire event, and move the loops for the draw into the Draw Event.
All draw calls should be in the Draw Event. If the entire block were in Draw, it would randomize the blocks each step.
I have a rather difficult problem. I am making a topdown 2D game. And I have decided to make an omnidirectional character control like realm of the mad god (Video shows at second 16 what that means). I have it all working fine and have managed to work out almost all the kinks of this sort of camera but one thing remains.
(if you dont know what effect im looking create you can see and example hee at 16 seconds mark: https://youtu.be/N2q6aXkvIiI?t=12s)
When the Camera of the the main client gets rotated more that 180 degrees Left becomes right and right becomes left and my messages to the server about flipping the given character when he is supposed to get inverted. I somewhat fixed this by making an if statement that sends an opposite flip request when your world is completely flipped.
However up and down also become a factor as they dont send requests to flip the character.
What im trying to get to is that I have overcomplicted this script I beleive when trying to get the correct messages accross all clients.
I am wondering if anyone has a logical solution to making sure all chracters on the network are always facing the correct direction at all times.
I am using socket.io and Node.js for speaking to the server.
Any input would be appeciated.
TL;DR
How would you go about making realm of the mad gods camera rotation style when all clients need to know what way everyone is facing. (see video 0:16)
thanks.
I have somewhat fixed this problem with a bit of a rewrite of my logic and managed to make all the magic happen on the client and keep the server out of it entirely. I do not know if what I have done is super effecient as I am rather new to coding.
The logic is that I have created a circle collider2D that represents the players field of view. so things slightly outside the camera view are included. Any collision with an object tagged "otherPlayer" will add them to a list.
I then iterate through the list, if its not empty, and I determine if the object is moving away or coming towards me. (thank you to HigherScriptingAuthority for part of the code for this :: https://forum.unity3d.com/threads/left-right-test-function.31420/).
once I know that, all I have to do is grab the transform of that object and flip it accordingly. Boom it now rotates the object or player correctly no matter what rotation the main client is in.
Hope this makes sense and it helps someone:
private float lastDist = 0;
public float dirNum;
void CheckArea()
{
if (listOfPlayers.Count != 0)
{
foreach(var otherPlayer in listOfPlayers)
{
float distance = (transform.position - otherPlayer.transform.position).magnitude;
if (distance < lastDist)
{
Vector3 heading = otherPlayer.transform.position - transform.position;
dirNum = AngleDir(transform.forward, heading, transform.up);
var objectDirection = AngleDir(transform.forward, heading, transform.up);
if (objectDirection > 0)
{
var nav = otherPlayer.GetComponent<Navigator>();
nav.Left();
}
if (objectDirection < 0)
{
var nav = otherPlayer.GetComponent<Navigator>();
nav.Right();
}
}
if (distance > lastDist)
{
Vector3 heading = otherPlayer.transform.position - transform.position;
dirNum = AngleDir(transform.forward, heading, transform.up);
var objectDirection = AngleDir(transform.forward, heading, transform.up);
if (objectDirection > 0)
{
var nav = otherPlayer.GetComponent<Navigator>();
nav.Right();
}
if (objectDirection < 0)
{
var nav = otherPlayer.GetComponent<Navigator>();
nav.Left();
}
}
lastDist = distance;
}
}
}
In IPython Notebook / Jupyter, arrow up/down keystrokes within a cell are handled by CodeMirror (as far as I can tell). I use these actions a lot (re-bound to control-p / control-n) to move between cells; but at the end of every cell, the cursor moves to end of line first before jumping to the next cell. This is counter-intuitive and, to me, rather distracting.
Is there any way to configure CodeMirror to make this move down to be just that - a move down?
Thanks!
The moving-to-next-cell behavior is defined by IPython wrapper code, which probably checks whether the cursor is at the end of the current cell, and overrides the default CodeMirror behavior in that case. You'll have to find that handler and somehow replace it with one that checks whether the cursor is on the last line. (I don't know much about IPython, only about CodeMirror, so I can't point you at the proper way to find and override the relevant code. They might have bound the Down key, or they might have overridden the goLineDown command.)
Knowing that I wasn't alone in wanting to skip the "going to end of line" behavior when going down from the last line of a code cell, I investigated that behavior and found out that:
it's CodeMirror that goes to the end of line when you type down in the last line of a code cell (file: codemirror.js ; "methods": findPosV and moveV)
and it's IPython that decides what to do with the "down" event after it has been handled by CodeMirror (file: cell.js ; class: Cell ; method: handle_codemirror_keyevent) ; looking at the code, I saw that IPython ignores the event when not at the last character of the last line.
This essentially confirms Marijin's answer.
The primary goal being to jump to the next cell, I think there's no need to prevent CodeMirror from going to the end of that line. The point is to force IPython to handle the event anyway.
My solution was to change the code from Cell.prototype.handle_codemirror_keyevent to this:
Cell.prototype.handle_codemirror_keyevent = function (editor, event) {
var shortcuts = this.keyboard_manager.edit_shortcuts;
var cur = editor.getCursor();
if((cur.line !== 0) && event.keyCode === 38){
// going up, but not from the first line
// don't do anything more with the event
event._ipkmIgnore = true;
}
var nLastLine = editor.lastLine();
if ((event.keyCode === 40) &&
((cur.line !== nLastLine))
) {
// going down, but not from the last line
// don't do anything more with the event
event._ipkmIgnore = true;
}
// if this is an edit_shortcuts shortcut, the global keyboard/shortcut
// manager will handle it
if (shortcuts.handles(event)) {
return true;
}
return false;
};
This code provides the desired behavior for the "down-arrow" key (almost: the cursor still goes to the end of the line, except that we don't see it, as we're already in another cell at that point), and also handles the "up-arrow" key similarly.
To modify the handle_codemirror_keyevent prototype, you have two possibilities:
You edit the cell.js file and change the code of the prototype to the code I gave above. The file is in <python>/Lib/site-packages/IPython/html/static/notebook/js or something similar depending on you distro
Much better, after the page is loaded, you change that prototype dynamically by doing this:
IPython.Cell.prototype.handle_codemirror_keyevent = function (editor, event) {
<same code as above>
};
You can do that in your custom.js for example, or create an extension to do it (that's what I did).
When I move page01 to page02, I pass the same data along with it using the following code:
navigator.pushView(Page02, data);
How do I move to page02 with passing the next row of data (instead of the same data)?
In other word, how to increment to the next row of data with pushView?
Thanks.
If you have access to the List component which displays the data you want to pass into views, you can do something like this:
myList.dataProvider[myList.selectedIndex+1]
You'll want to do some checking to make sure that you're trying to reference an index that actually exists:
var mySelectedObject :Object;
if(myList.selectedIndex+1 < myList.dataProvider.length){
mySelectedObject = myList.dataProvider[myList.selectedIndex+1]
} else {
// do some other behaviour; such as selecting the first one in the list
mySelectedObject = myList.dataProvider[0]
}
navigator.pushView(page02, mySelectedObject );
We'll soon be embarking on the development of a new mobile application. This particular app will be used for heavy searching of text based fields. Any suggestions from the group at large for what sort of database engine is best suited to allowing these types of searches on a mobile platform?
Specifics include Windows Mobile 6 and we'll be using the .Net CF. Also some of the text based fields will be anywhere between 35 and 500 characters. The device will operate in two different methods, batch and WiFi. Of course for WiFi we can just submit requests to a full blown DB engine and just fetch results back. This question centres around the "batch" version which will house a database loaded with information on the devices flash/removable storage card.
At any rate, I know SQLCE has some basic indexing but you don't get into the real fancy "full text" style indexes until you've got the full blown version which of course isn't available on a mobile platform.
An example of what the data would look like:
"apron carpenter adjustable leather container pocket waist hardware belt" etc. etc.
I haven't gotten into the evaluation of any other specific options yet as I figure I'd leverage the experience of this group in order to first point me down some specific avenues.
Any suggestions/tips?
Just recently I had the same issue. Here is what I did:
I created a class to hold just an id and the text for each object (in my case I called it a sku (item number) and a description). This creates a smaller object that uses less memory since it is only used for searching. I'll still grab the full-blown objects from the database after I find matches.
public class SmallItem
{
private int _sku;
public int Sku
{
get { return _sku; }
set { _sku = value; }
}
// Size of max description size + 1 for null terminator.
private char[] _description = new char[36];
public char[] Description
{
get { return _description; }
set { _description = value; }
}
public SmallItem()
{
}
}
After this class is created, you can then create an array (I actually used a List in my case) of these objects and use it for searching throughout your application. The initialization of this list takes a bit of time, but you only need to worry about this at start up. Basically just run a query on your database and grab the data you need to create this list.
Once you have a list, you can quickly go through it searching for any words you want. Since it's a contains, it must also find words within words (e.g. drill would return drill, drillbit, drills etc.). To do this, we wrote a home-grown, unmanaged c# contains function. It takes in a string array of words (so you can search for more than one word... we use it for "AND" searches... the description must contain all words passed in... "OR" is not currently supported in this example). As it searches through the list of words it builds a list of IDs, which are then passed back to the calling function. Once you have a list of IDs, you can easily run a fast query in your database to return the full-blown objects based on a fast indexed ID number. I should mention that we also limit the maximum number of results returned. This could be taken out. It's just handy if someone types in something like "e" as their search term. That's going to return a lot of results.
Here's the example of custom Contains function:
public static int[] Contains(string[] descriptionTerms, int maxResults, List<SmallItem> itemList)
{
// Don't allow more than the maximum allowable results constant.
int[] matchingSkus = new int[maxResults];
// Indexes and counters.
int matchNumber = 0;
int currentWord = 0;
int totalWords = descriptionTerms.Count() - 1; // - 1 because it will be used with 0 based array indexes
bool matchedWord;
try
{
/* Character array of character arrays. Each array is a word we want to match.
* We need the + 1 because totalWords had - 1 (We are setting a size/length here,
* so it is not 0 based... we used - 1 on totalWords because it is used for 0
* based index referencing.)
* */
char[][] allWordsToMatch = new char[totalWords + 1][];
// Character array to hold the current word to match.
char[] wordToMatch = new char[36]; // Max allowable word size + null terminator... I just picked 36 to be consistent with max description size.
// Loop through the original string array or words to match and create the character arrays.
for (currentWord = 0; currentWord <= totalWords; currentWord++)
{
char[] desc = new char[descriptionTerms[currentWord].Length + 1];
Array.Copy(descriptionTerms[currentWord].ToUpper().ToCharArray(), desc, descriptionTerms[currentWord].Length);
allWordsToMatch[currentWord] = desc;
}
// Offsets for description and filter(word to match) pointers.
int descriptionOffset = 0, filterOffset = 0;
// Loop through the list of items trying to find matching words.
foreach (SmallItem i in itemList)
{
// If we have reached our maximum allowable matches, we should stop searching and just return the results.
if (matchNumber == maxResults)
break;
// Loop through the "words to match" filter list.
for (currentWord = 0; currentWord <= totalWords; currentWord++)
{
// Reset our match flag and current word to match.
matchedWord = false;
wordToMatch = allWordsToMatch[currentWord];
// Delving into unmanaged code for SCREAMING performance ;)
unsafe
{
// Pointer to the description of the current item on the list (starting at first char).
fixed (char* pdesc = &i.Description[0])
{
// Pointer to the current word we are trying to match (starting at first char).
fixed (char* pfilter = &wordToMatch[0])
{
// Reset the description offset.
descriptionOffset = 0;
// Continue our search on the current word until we hit a null terminator for the char array.
while (*(pdesc + descriptionOffset) != '\0')
{
// We've matched the first character of the word we're trying to match.
if (*(pdesc + descriptionOffset) == *pfilter)
{
// Reset the filter offset.
filterOffset = 0;
/* Keep moving the offsets together while we have consecutive character matches. Once we hit a non-match
* or a null terminator, we need to jump out of this loop.
* */
while (*(pfilter + filterOffset) != '\0' && *(pfilter + filterOffset) == *(pdesc + descriptionOffset))
{
// Increase the offsets together to the next character.
++filterOffset;
++descriptionOffset;
}
// We hit matches all the way to the null terminator. The entire word was a match.
if (*(pfilter + filterOffset) == '\0')
{
// If our current word matched is the last word on the match list, we have matched all words.
if (currentWord == totalWords)
{
// Add the sku as a match.
matchingSkus[matchNumber] = i.Sku.ToString();
matchNumber++;
/* Break out of this item description. We have matched all needed words and can move to
* the next item.
* */
break;
}
/* We've matched a word, but still have more words left in our list of words to match.
* Set our match flag to true, which will mean we continue continue to search for the
* next word on the list.
* */
matchedWord = true;
}
}
// No match on the current character. Move to next one.
descriptionOffset++;
}
/* The current word had no match, so no sense in looking for the rest of the words. Break to the
* next item description.
* */
if (!matchedWord)
break;
}
}
}
}
};
// We have our list of matching skus. We'll resize the array and pass it back.
Array.Resize(ref matchingSkus, matchNumber);
return matchingSkus;
}
catch (Exception ex)
{
// Handle the exception
}
}
Once you have the list of matching skus, you can iterate through the array and build a query command that only returns the matching skus.
For an idea of performance, here's what we have found (doing the following steps):
Search ~171,000 items
Create list of all matching items
Query the database, returning only the matching items
Build full-blown items (similar to SmallItem class, but a lot more fields)
Populate a datagrid with the full-blow item objects.
On our mobile units, the entire process takes 2-4 seconds (takes 2 if we hit our match limit before we have searched all items... takes 4 seconds if we have to scan every item).
I've also tried doing this without unmanaged code and using String.IndexOf (and tried String.Contains... had same performance as IndexOf as it should). That way was much slower... about 25 seconds.
I've also tried using a StreamReader and a file containing lines of [Sku Number]|[Description]. The code was similar to the unmanaged code example. This way took about 15 seconds for an entire scan. Not too bad for speed, but not great. The file and StreamReader method has one advantage over the way I showed you though. The file can be created ahead of time. The way I showed you requires the memory and the initial time to load the List when the application starts up. For our 171,000 items, this takes about 2 minutes. If you can afford to wait for that initial load each time the app starts up (which can be done on a separate thread of course), then searching this way is the fastest way (that I've found at least).
Hope that helps.
PS - Thanks to Dolch for helping with some of the unmanaged code.
You could try Lucene.Net. I'm not sure how well it's suited to mobile devices, but it is billed as a "high-performance, full-featured text search engine library".
http://incubator.apache.org/lucene.net/
http://lucene.apache.org/java/docs/