In this thread, Mike Bostock explains that setting a brush's extent and redrawing the brush are two separate operations. I understand this, but I'm having trouble working out the details.
He says you need to do something like the following:
brush.extent([0.2, 0.8]);
svg.select(".brush").call(brush);
However, when I execute call(brush), it simply draws the brush rectangle on the new extent. The 'focus' chart never gets updated. However, if I call my brushed function (the function that I assigned to my brush), it works.
It seems like call(brush) doesn't execute brushed. How do I get it to execute this function?
UPDATE: Here's a fiddle with my code. When you run it, notice the brush is correctly drawn, but the focus is not updated. Uncomment line 180, and the focus gets redrawn too.
(Of course, eventually I will want to do this from outside the chart object, but for now I am doing it within just to try to figure out what's going wrong.)
Essentially, I'm asking: How can I trigger the brushed function from outside the object? How does the brush event handler do it?
Setting the extent of a brush explicitly doesn't trigger the event that causes the function associated with it to be called. In this case the simplest solution is to, as you already found out, call brushed() explicitly after setting the extent.
Related
Suppose you have a scrollable NSView. When you scroll it, the part coming into the clipping rectangle will need to be refreshed, and the view's drawRect (Swift draw) method will be called for a rectangle containing that new part. Suppose now that before that part can be drawn, some time-consuming processing will need to be done. Since you don't want to burden the main thread (from which drawRect is called) with that processing, you might want to unload it on a secondary thread. Now my question is, what's a good way to do this? For example, you can:
Initiate asynchronous processing from drawRect, exit it without drawing, and have the secondary thread, when it's finished, store the data somewhere and call setNeedsDisplay and thus have drawRect get called again.
As above, but when the processing is finished, draw into the view directly (in the main thread), without going through drawRect.
Set canDrawConcurrently for the view beforehand; but that, as far as I can tell, will not necessarily force drawRect into a secondary thread, unless the system decides to do so.
Or, maybe some other way? This seems like a common enough situation, but I can't find any tips on how to do this in a clean way.
In the example below,
OnTouchEffectAction contains canvas.InvalidateSurface().
OnCanvasViewPaintSurface contains convas.DrawPath().
Questions:
Why OnTouchEffectAction requires InvalidateSurface()?
Why doesnt call InvalidateSurface after
drawing?
Complete Code is given here
InvalidateSurface causes the PainSurface event to be raised, which calls OnCanvasViewPaintSurface. InvalidateSurface is how you tell Skia that you've made changes to a canvas and that it's UI needs to be refreshed. OnTouchEffectAction is adding new polylines to the canvas, so calling InvalidateSurface causes the canvas to be redrawn with those new lines.
I am displaying several identical charts (showing different datasets) side-by-side. Upon brushing on one chart, the brush should be replicated on all others.
Currently, I do this by calling brush.move on a selection of all charts excluding the currently brushed chart, as soon as someone brushes on a chart. This happens in a brush-type eventListener.
However, this brush.move triggers the brush-type event attached to the brush, leading to an error (or, more generally, an infinite loop).
How can I prevent this?
You can use the d3.event object to check what caused the update of the brush. From the API docs on brush events:
Brush Events
When a brush event listener is invoked, d3.event is set to the current brush event. The event object exposes several fields:
…
sourceEvent - the underlying input event, such as mousemove or touchmove.
If your brush is modified programtically, i.e. by calling brush.move(), the d3.event.sourceEvent property will be null, because no input event caused this update. In your event handler you can check this property to skip execution for programmatic changes:
if (!d3.event.sourceEvent) return;
The same technique is employed by Mike Bostock in his Brush Snapping Block. While handling the actual input event the brush is modified again to snap to the nearest value, which, obviously, should not trigger another run of the event handler.
How's the page scrolling created on flashvhtml.com? How is the scrolling triggered by the links at the top and how the other 'sub animation' events tied in to the scrolling background?
This is what I have been able to gather:
Listeners for interactions are added in the Trackpad.js file. Listeners for events such as mouse dragging, keyboard events, touch etc. All of which calculating a value variable.
This value variable of the Trackpad.js is then
used to adjust camera position in the update method of main.js
file.
There are 3 main views that are being rendered if I understand
it correctly: ScrollView, ScaleView, RocketView. All of those
initiated inside the init method of main.js. But they are all
defined in the fvh.js file.
Each of these three views have an
updatePosition method taking camera.y or mainScrollPosition as
parameter. These updatePosition methods are called inside of the
same update method of main.js file.
Then there is a ScrollMap.js which contains loads of position data for all 3 views e.g. it contains ScrollView data in the format of:
mcxxx:{view:'nameofelement',depth:xx,startFrame:xxx,endFrame:xxx,position:[xxx,...]} etc.
Also there is a sectionLandPositions variable defined in the main.js file which is also very interesting because this is what is then used inside the onMenuItemPressed method in the same file to tween and bring a certain section into view.
So magic basically happens in the updatePosition methods of each views and how the value is computed in the Trackpad.js. And this is where I leave you to debug further and take it home. :)
Files under scrutiny are: Trackpad.js, fvh.js, ScrollMap.js, main.js. Hope you find it all useful.
P.S. Kudos to Waste-Creative for creating this informative and engaging website.
T
An easy way to do this, is by adding tweens and then using the scroll/drag input and links to move around in the tween's timeline.
Tween one : Pans Camera down slowly continuously.
Tween two : Wait's until x, fades sprite in untily y, fades sprite out, ..
Make sure, you dont 'play' the tween's after creating them, but adjust the time manually (based on the scroll position).
There are a few tweeing frameworks you can use for pixi: Greensocks, Impact, tween.js
And there's a discusion on it over at the html5gamedevs forum.
KineticJS seems to have an issue with handling clicks on background layers after redrawing the stage.
I have a jsfiddle with a minimal example of this problem. http://jsfiddle.net/Z2SJS/
On line 34 I have:
stage.draw()
If this is commented out, events fire as they should. When this is present, after dragging the click events to the background will stop firing.
I know that in this example I am not doing anything that would require me to redraw the stage, but in my project I am using the dragstart and dragmove events to manipulate objects on multiple layers, and I then lose reference to my background clicks.
Is there something I need to do to ensure that redrawing the stage does not cause my events to stop firing?
Instead of using stage.draw() use foreground.draw()
here is the updated fiddle
Alternately: set dragOnTop: false inside the circle instantiation. Fiddle2