I have a stacked bar chart which has time on the x-axis and a count on the y-axis. I have most of the transitions working but there is a scenario where I'm unsure what to do.
If the new data is part of the update selection then I know to grow the bars (as they already exist).
If, if however, the data is part of the enter selection then, depending on where the data is entering, there are two possible transitions:
If the data is newer than the current "end time" then it should slide in from the right, as per this well known tutorial.
If the data is new but older than the current "end time" then a new category should be formed.
The analogous situation occurs in the exit selection.
I am already taking care of #2 above but am having trouble implementing #1. Especially at the same time as #2. It seem to me that I need to inspect the new datum and see where it falls on the chart, probably using the xScale.
How does one run different transitions on the same selection (enter or exit, in this case)?
Here's some pseudo code for what I could imagine for the exit selection:
rects.exit(function () {
if (d.timestamp < that.chartStartTime) {
transitionOffLeftEdge();
} else {
transitionOffBottom();
}
)};
Related
I'm using an iterator to iterate through a Linked List of 90,000 Book Objects. Each of them have titles, ISBNs, authors and prices.
In my GUI, I have a text field, and a button which would display these 90,000 Books.toString() in the text field. The user can search for a book, remove a book, or update fields in the book, so I feel like the user should be able to see all the books and all their fields.
The problem is, this takes way too long, I get the beach ball of death and it never loads. When I change the for loop to 10 or 1000, it works fine. Must be an O(n^2), right?
Or is there some other problem?
Thank you.
#FXML
void refreshListButtonPressed(ActionEvent event) {
listBooksTextArea.clear();
bookbag.myIter.reset();
for(int i = 0; i < 1000; i++) {
listBooksTextArea.appendText(bookbag.myIter.getCurrent().getData().toString() +
"\n");
bookbag.myIter.nextLink();
if(bookbag.myIter.atEnd()) {
listBooksTextArea.appendText(bookbag.myIter.getCurrent().getData().toString()+
"\n");
}
}
}
Ideally, I wouldn't even use a for loop, I'd use while (!bookbag.myIter.atEnd()), but the for loop proves to me the code works and the size or efficiency is the issue.
Your code is inefficient in a couple of different ways:
The TextArea stores the text as a String, which is an immutable object. Consequently, each time you call appendText(...) a new String is created, by copying the existing characters plus the new characters to a new string object. Since the size of the string grows essentially linearly on each iteration, this becomes an O(n^2) operation.
The TextArea creates a UI node for the entire text. UI nodes are generally quite expensive, and here you are creating a huge node to lay out, style, and display all 90,000 lines of text, the vast majority of which are not visible on the screen at any given time.
You can at least partially fix the first by concatenating the string in a StringBuilder, and then setting the text of the TextArea once, though this will not fix the second issue.
The preferred approach here is to use a virtualized control, such as a ListView or TableView. These controls create a limited number of cells (one per row in the case of a ListView, one per column per row in the case of a TableView), essentially creating cells only for the visible data. As the user scrolls around, cells are reused to display new data. This greatly enhances performance.
Additionally, these controls probably allow for a better interaction between your UI and your actual data. Using a TableView, each row would represent a Book object, and each cell in the row a property of that object. If you make your table editable, you can validate changes to each cell, i.e. on a property-by-property basis. Using a text area, you would need to carefully parse the changes to the text to make sure the result was a valid list of books.
I would generally recommend working through a tutorial on TableView, e.g. this one. In brief, create a Book class using JavaFX Properties. Create a TableView<Book> and configure the columns to point to appropriate properties using the setCellValueFactory(...) method. You can make the data editable by supplying, for example, a TextFieldTableCell in the cell factory for the column. Then simply add your Book instances to the table's items list.
I am trying to figure out how to have custom brush handles highlight data in a range equal to a single value, which seems to result in a null selection.
Here the Plunkr I recreated on one of Mike Bostock's examples. It's in Angular 2/ionic, so if that's an issue, please go here to view his example's plain javascript. The primary thing I edited was commenting out where he hides the custom handles with css when there is a null selection.
if (s == null) {
//handle.attr("display", "none");
//circle.classed("active", false);
}
http://plnkr.co/edit/tRyhlJ
https://bl.ocks.org/mbostock/4349545
If you look in the plunkr example, you can see that if you click and let go the brush is still a perfect sphere, with the line where you clicked. Instead if disappearing, I want the brush handles to stay... and not cause errors when you click to expand the handles.
The error I am currently getting, and can't seem to find a workaround, is this:
How do I gracefully ignore this internal d3 error and continue on letting my selection expand?
I've tried all sorts of things like turning pointer-events off when it's in this state, and manually unhiding/resizing the default handles, to no avail. Every time, when I click the handles I get this error.
As far as I can tell, there's no "clean" way to deal with it. The reason is that a single click defines a range whose size is 0, which the brush considers an empty range (see source) and so it purposely nullifies the selection (see source).
That all means that unless you create your own version of d3-brush to do what you want, there's no way to have an empty selection that's not null nor a way to render a brush for an empty selection.
There's one workaround I can think of: when you detect an empty selection (where s == null) use brush.move to set the selection to something. That something would have to be a range whose size is not 0 (because if you make it 0 then d3, again, would consider that an empty selection and nullify it). To make a non-zero selection that looks like a zero-sized selection (which it has to be, because it's being defined by a single click event) you'd have to make it a tiny selection, eg [123, 123.0001]. Instead of 123, you need to know the mouse position of the click, which you can get using d3.mouse. Putting it all together, it looks like this:
if (s == null) {
var mousex = d3.mouse(this)[0]
gBrush.call(brush.move, [mousex, mousex+.001]);
}
We have a script that export our Indesign documents to HTML and one of the routine is to export tables. In this script we go throught each Tables->Rows->Cells and evaluate some of the properties (i.e. bottomEdgeStrokeType, topEdgeStrokeType, etc...) and transport them to HTML.
Now yesterday we had problem converting one particular document because some cells were missing the "bottomEdgeStrokeType" property entirely. I've discovered this by outputting the properties of each cells and compare the faulty ones with the others.
This line bellow was trowing the error: "Invalid object for this request.".
var cellType = cell["bottomEdgeStrokeType"];
Now, to fix this I've wrapped this around a try catch block to handle the case when it's not there, but now what is puzzling me is how on earth can Extendscript instantiate an object with missing properties?
Indesign version: CS5.5
A property is not only 'undefined' if it cannot exist at all (such as asking for the parent text frame for a character in overset text), but InDesign's Javascript engine also fails to return a reasonably accurate result for multiple values.
If you ask for "the" point size of a paragraph, where this paragraph contains multiple sizes, poor ID does not consider to return something like CONSTANT.Mixed, or the first value only, or (what I might have preferred) an array of the values; it returns undefined instead.
So how can a single table cell have multiple bottom strokes? If the cell underneath it is split into multiple cells, and one has a "top" stroke but the other has not.
It's difficult to recommend an adequate solution. You could first test if the current cell is "merged" (as far as InDesign's internal table model is concerned) with columnSpan; and if so, iterate over the number of columns spanned and test the next row's cells for their top stroke, which in theory should match the bottom stroke of the cell above. (I find myself wondering if this is always true. ID's table model is ... weird. It's not entirely like a HTML table, despite the functional overlaps.)
If columnSpan is greater than 1 and equal to the number of cells immediately below the current one, you could test if all of their "top" values are the same and if so use that value. (I never tested this so ID's table model may simply fail because a cell is merged, regardless of same-values or not.)
One could attempt to flag this cell's next row to output "top" strokes as well -- but alternating top and bottom strokes may not align nicely in CSS, side to side. Perhaps it's best to translate only the first top stroke value to "the" bottom stroke property for your current cell, and fix up manually where needed (how?) or, a reasonable action, hope that no-one will ever notice it.
I'm new to D3 JS.
I spent some time to learn D3 js and build a sort of time table (I'm not sure this is the term) and to animate it.
Now I found a strange behavior on exit transition, when I try to remove the last element in a row the animation goes perfectly but when the element is not the last one, D3 removes it without animation.
It's hard to understand my problem, it's really easier to watch it! :)
I created a working fiddle here: http://jsfiddle.net/fLBq4/5/
Click 'Draw' to build the graph (data are loaded from an external js that create the var demodata)
Then click the second button and watch the last element of Sunday. The transition works correctly.
Then click the last button. You'll see that the first element of Friday is removed without the transition!
Now... I'm really surprised because the code for removing elements it's the same for both executions:
frames.exit()
.transition()
.duration(500)
.attr('width',0)
.remove();
Moreover, I implemented the listeners for 'start' and 'end' transition events (you will not find them in the fiddle). These events are fired correctly, i.e. the 'end' event is timed correctly 500 msec after start.
Why won't D3 animate all the elements in the same way, in my case?
What's happening is that you're getting caught out by D3's data matching. The bar that disappears suddenly isn't in the exit selection, it's in the update selection. The second bar is in the exit selection and disappears gradually, but the first bar is moved to its position instantaneously, so you can't actually see that. I've added a transition to the update selection so you can see what's happening here.
The reason that this is happening is that D3 matches data and DOM elements by index by default. That is, the first data element corresponds to the first DOM element in the selection and so on. In your particular case, you're removing an element from the array, so the last DOM element ends up being not matched and becomes part of the exit selection. The other elements however change their position (as new data is matched to them).
To fix, simply provide a function that tells D3 how to match data and DOM elements, e.g.
var frames = groups.selectAll('.frame')
.data(function(d){return d;}, function(d) { return d.start; });
Complete demo here.
My powerpoint is made is like a quiz, one slide has a question and 4 answers (buttons with text, not numbers) that can be clicked on. When an answer is clicked on, it is linked to another slide that explains if the answer being right/wrong and then adds/subtracts points from the score.
Currently what I have done is a simple macro that each button is linked to and upon clicking any of the 4 answer buttons, it will go to a certain slide and show a pop up box with their current score.
What I want to do is have either a text box or some object that holds the score throughout the entire presentation and ideally if possible, the score resets when the ppt is closed or opened but the running score is the most important aspect I'm trying to hammer down.
Is this possible for what I'm asking? Let me know if there are any details that would help
Instead of resetting the score when the presentation shuts down, do it at startup. For example, you could put a "Begin the quiz" button on the first slide, have it reset the score, then move to the next slide.
As to where to store the score, there are a number of ways of doing it. One would be to put a rectangle or text box on the last slide and store the score as its text. Make sure the rectangle's sent to back so it's the first shape on the slide, or change Shapes(1) below to indicate the actual z-order position of the shape.
Function SetScore(lScore as Long)
Dim lLastSlide as Long
lLastSlide = ActivePresentation.Slides.Count
With ActivePresentation.Slides(lLastSlide).Shapes(1).TextFrame.TextRange
.Text = Cstr(lScore)
End With
End Function
A companion GetScore function should be easy to come up with, similar to the above.